@tostudy-ai/cli 0.7.4 → 0.8.0
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 +562 -336
- package/dist/cli.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2280,6 +2280,7 @@ var init_mcp_setup = __esm({
|
|
|
2280
2280
|
// src/workspace/instruction-files.ts
|
|
2281
2281
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2282
2282
|
import { join as join2 } from "node:path";
|
|
2283
|
+
import os4 from "node:os";
|
|
2283
2284
|
function slugify(title) {
|
|
2284
2285
|
return title.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
2285
2286
|
}
|
|
@@ -2395,19 +2396,41 @@ ${rules.map((r, i) => `${i + 1}. ${r}`).join("\n")}`);
|
|
|
2395
2396
|
| Aluno perdido / sem saber o que fazer | Rodar \`tostudy progress\` e resumir estado atual |
|
|
2396
2397
|
| "Stop hook error" / "ECONNREFUSED" | Ignorar \u2014 problema de configura\xE7\xE3o do IDE, n\xE3o do ToStudy |`);
|
|
2397
2398
|
if (ctx.workspaceReady !== false) {
|
|
2399
|
+
const home = os4.homedir();
|
|
2400
|
+
const cwd = process.cwd();
|
|
2401
|
+
const isNamespaced = ctx.workspacePath === join2(cwd, ".tostudy");
|
|
2402
|
+
const isFlatCwd = ctx.workspacePath === cwd;
|
|
2403
|
+
const displayPath = ctx.workspacePath ? ctx.workspacePath.startsWith(home) ? ctx.workspacePath.replace(home, "~") : ctx.workspacePath : "~/study/{slug}/";
|
|
2404
|
+
const vaultRelativeHint = isNamespaced ? "../vault-<slug>/ \u2190 Vault Obsidian (fora de .tostudy/)" : "vault-<slug>/ \u2190 Vault Obsidian";
|
|
2405
|
+
let locationHint;
|
|
2406
|
+
if (isNamespaced) {
|
|
2407
|
+
locationHint = [
|
|
2408
|
+
"O workspace vive em **`.tostudy/`** nesta pasta \u2014 isolado do resto do projeto.",
|
|
2409
|
+
"Os arquivos do projeto (src/, README.md, AGENTS.md...) permanecem intactos.",
|
|
2410
|
+
"Os exerc\xEDcios s\xE3o extra\xEDdos dentro de `.tostudy/exercises/` e o assistente AI enxerga tudo normalmente.",
|
|
2411
|
+
"",
|
|
2412
|
+
"> \u26A0\uFE0F O **vault Obsidian** fica em `vault-<slug>/` **fora** de `.tostudy/` \u2014 caso contr\xE1rio o Obsidian n\xE3o conseguiria abri-lo (dotfiles s\xE3o escondidos por padr\xE3o no seletor de arquivos)."
|
|
2413
|
+
].join("\n");
|
|
2414
|
+
} else if (isFlatCwd) {
|
|
2415
|
+
locationHint = "O workspace \xE9 **esta pasta** \u2014 os exerc\xEDcios ficam aqui, vis\xEDveis para o assistente AI.";
|
|
2416
|
+
} else {
|
|
2417
|
+
locationHint = "O workspace local organiza os arquivos do curso:";
|
|
2418
|
+
}
|
|
2398
2419
|
sections.push(`## Workspace
|
|
2399
2420
|
|
|
2400
|
-
|
|
2421
|
+
${locationHint}
|
|
2401
2422
|
|
|
2402
2423
|
\`\`\`
|
|
2403
|
-
|
|
2424
|
+
${displayPath}/
|
|
2404
2425
|
\u251C\u2500\u2500 exercises/{m\xF3dulo}/{li\xE7\xE3o}/ \u2190 Exerc\xEDcios extra\xEDdos
|
|
2405
2426
|
\u251C\u2500\u2500 generated/ \u2190 Artefatos gerados
|
|
2406
|
-
\
|
|
2427
|
+
\u251C\u2500\u2500 diagrams/ \u2190 Diagramas
|
|
2428
|
+
\u2514\u2500\u2500 ${vaultRelativeHint}
|
|
2407
2429
|
\`\`\`
|
|
2408
2430
|
|
|
2409
2431
|
Comandos \xFAteis:
|
|
2410
2432
|
- \`tostudy export\` \u2014 Extrair exerc\xEDcio para o workspace
|
|
2433
|
+
- \`tostudy vault init\` \u2014 Gerar vault Obsidian (abra no Obsidian: "Open folder as vault")
|
|
2411
2434
|
- \`tostudy open\` \u2014 Abrir workspace no editor
|
|
2412
2435
|
- \`tostudy workspace status\` \u2014 Verificar estado do workspace`);
|
|
2413
2436
|
}
|
|
@@ -2582,10 +2605,10 @@ FIM DO M\xD3DULO:
|
|
|
2582
2605
|
|
|
2583
2606
|
## Workspace
|
|
2584
2607
|
|
|
2585
|
-
|
|
2608
|
+
Se esta pasta cont\xE9m \`.tostudy/\`, ela j\xE1 \xE9 o workspace \u2014 exerc\xEDcios ficam aqui.
|
|
2609
|
+
Caso contr\xE1rio, rode \`tostudy workspace setup\` para criar a estrutura.
|
|
2586
2610
|
|
|
2587
|
-
- \`tostudy
|
|
2588
|
-
- \`tostudy export\` \u2014 Extrai exerc\xEDcio para o workspace
|
|
2611
|
+
- \`tostudy export\` \u2014 Extrai exerc\xEDcio para o workspace (esta pasta ou ~/study/{slug}/)
|
|
2589
2612
|
- \`tostudy open\` \u2014 Abre workspace no editor
|
|
2590
2613
|
- \`tostudy workspace status\` \u2014 Verifica estado
|
|
2591
2614
|
|
|
@@ -2747,10 +2770,14 @@ async function runSetup(opts, deps = defaultDeps) {
|
|
|
2747
2770
|
const activeCourse = await deps.getActiveCourse();
|
|
2748
2771
|
const hasClaudeCmd = existsSync3(join3(cwd, ".claude", "commands", "tostudy.md"));
|
|
2749
2772
|
const hasCursorRule = existsSync3(join3(cwd, ".cursor", "rules", "tostudy.mdc"));
|
|
2773
|
+
const hasMcpConfig = existsSync3(join3(cwd, ".claude", "claude_desktop_config.json")) || existsSync3(join3(cwd, ".mcp.json"));
|
|
2774
|
+
const hasClaudeIDE = detected.some((ide) => ide.name.toLowerCase().includes("claude"));
|
|
2750
2775
|
deps.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2751
2776
|
deps.log(" Setup completo!\n");
|
|
2752
2777
|
if (activeCourse) {
|
|
2753
2778
|
deps.log(` Curso ativo: ${activeCourse.courseTitle}`);
|
|
2779
|
+
} else {
|
|
2780
|
+
deps.log(" Nenhum curso ativo \u2014 rode: tostudy courses");
|
|
2754
2781
|
}
|
|
2755
2782
|
if (hasClaudeCmd) {
|
|
2756
2783
|
deps.log(" \u2192 No Claude Code, digite: /tostudy");
|
|
@@ -2759,6 +2786,9 @@ async function runSetup(opts, deps = defaultDeps) {
|
|
|
2759
2786
|
} else {
|
|
2760
2787
|
deps.log(" \u2192 Abra seu IDE e o tutor estar\xE1 dispon\xEDvel");
|
|
2761
2788
|
}
|
|
2789
|
+
if (hasClaudeIDE && !hasMcpConfig && !opts.mcp) {
|
|
2790
|
+
deps.log("\n \u{1F4A1} Dica: rode tostudy setup --mcp para habilitar ferramentas avan\xE7adas");
|
|
2791
|
+
}
|
|
2762
2792
|
deps.log("");
|
|
2763
2793
|
}
|
|
2764
2794
|
async function runSetupMcpSubcommand() {
|
|
@@ -2813,12 +2843,12 @@ __export(update_checker_exports, {
|
|
|
2813
2843
|
});
|
|
2814
2844
|
import fs4 from "node:fs";
|
|
2815
2845
|
import path4 from "node:path";
|
|
2816
|
-
import
|
|
2846
|
+
import os5 from "node:os";
|
|
2817
2847
|
function getConfigDir2() {
|
|
2818
2848
|
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2819
2849
|
return path4.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2820
2850
|
}
|
|
2821
|
-
return path4.join(
|
|
2851
|
+
return path4.join(os5.homedir(), ".tostudy");
|
|
2822
2852
|
}
|
|
2823
2853
|
function readCache() {
|
|
2824
2854
|
try {
|
|
@@ -3044,8 +3074,112 @@ var init_courses2 = __esm({
|
|
|
3044
3074
|
}
|
|
3045
3075
|
});
|
|
3046
3076
|
|
|
3077
|
+
// src/workspace/resolve.ts
|
|
3078
|
+
import fs5 from "node:fs/promises";
|
|
3079
|
+
import path5 from "node:path";
|
|
3080
|
+
import os6 from "node:os";
|
|
3081
|
+
function courseSlug(title) {
|
|
3082
|
+
return title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
3083
|
+
}
|
|
3084
|
+
async function resolveWorkspace(courseTitle, basePath = DEFAULT_BASE) {
|
|
3085
|
+
const slug = courseSlug(courseTitle);
|
|
3086
|
+
const candidate = path5.join(basePath, slug);
|
|
3087
|
+
try {
|
|
3088
|
+
await fs5.access(path5.join(candidate, ".ana-config.json"));
|
|
3089
|
+
return { found: true, workspacePath: candidate, source: "default" };
|
|
3090
|
+
} catch {
|
|
3091
|
+
return { found: false, workspacePath: null };
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
async function isCwdWorkspace(cwd = process.cwd()) {
|
|
3095
|
+
return await resolveCwdWorkspacePath(cwd) !== null;
|
|
3096
|
+
}
|
|
3097
|
+
async function resolveCwdWorkspacePath(cwd = process.cwd()) {
|
|
3098
|
+
const tostudyDir = path5.join(cwd, ".tostudy");
|
|
3099
|
+
try {
|
|
3100
|
+
const stat = await fs5.stat(tostudyDir);
|
|
3101
|
+
if (stat.isDirectory()) return tostudyDir;
|
|
3102
|
+
} catch {
|
|
3103
|
+
}
|
|
3104
|
+
try {
|
|
3105
|
+
await fs5.access(path5.join(cwd, ".ana-config.json"));
|
|
3106
|
+
return cwd;
|
|
3107
|
+
} catch {
|
|
3108
|
+
return null;
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
function resolveVaultPath(workspacePath, slug) {
|
|
3112
|
+
const base = path5.basename(workspacePath) === ".tostudy" ? path5.dirname(workspacePath) : workspacePath;
|
|
3113
|
+
return path5.join(base, `vault-${slug}`);
|
|
3114
|
+
}
|
|
3115
|
+
async function findExistingVault(workspacePath, slug) {
|
|
3116
|
+
const slugged = resolveVaultPath(workspacePath, slug);
|
|
3117
|
+
try {
|
|
3118
|
+
await fs5.access(path5.join(slugged, ".ana-vault.json"));
|
|
3119
|
+
return slugged;
|
|
3120
|
+
} catch {
|
|
3121
|
+
}
|
|
3122
|
+
const legacy = path5.join(workspacePath, "vault");
|
|
3123
|
+
try {
|
|
3124
|
+
await fs5.access(path5.join(legacy, ".ana-vault.json"));
|
|
3125
|
+
return legacy;
|
|
3126
|
+
} catch {
|
|
3127
|
+
return null;
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
async function resolveEffectiveWorkspace(courseTitle, storedPath, cwd = process.cwd(), defaultBasePath = DEFAULT_BASE) {
|
|
3131
|
+
const cwdWorkspace = await resolveCwdWorkspacePath(cwd);
|
|
3132
|
+
if (cwdWorkspace) {
|
|
3133
|
+
return { found: true, workspacePath: cwdWorkspace, source: "cwd" };
|
|
3134
|
+
}
|
|
3135
|
+
if (storedPath) {
|
|
3136
|
+
try {
|
|
3137
|
+
await fs5.access(path5.join(storedPath, ".ana-config.json"));
|
|
3138
|
+
return { found: true, workspacePath: storedPath, source: "stored" };
|
|
3139
|
+
} catch {
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
const result = await resolveWorkspace(courseTitle, defaultBasePath);
|
|
3143
|
+
if (result.found) {
|
|
3144
|
+
return { ...result, source: "default" };
|
|
3145
|
+
}
|
|
3146
|
+
return { found: false, workspacePath: null };
|
|
3147
|
+
}
|
|
3148
|
+
var DEFAULT_BASE;
|
|
3149
|
+
var init_resolve = __esm({
|
|
3150
|
+
"src/workspace/resolve.ts"() {
|
|
3151
|
+
"use strict";
|
|
3152
|
+
DEFAULT_BASE = path5.join(os6.homedir(), "study");
|
|
3153
|
+
}
|
|
3154
|
+
});
|
|
3155
|
+
|
|
3156
|
+
// src/onboarding/status.ts
|
|
3157
|
+
async function getCourseOnboardingStatus(activeCourse, configDir, cwd = process.cwd()) {
|
|
3158
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId, configDir);
|
|
3159
|
+
const initReady = Boolean(onboardingState?.initCompletedAt);
|
|
3160
|
+
const ws = await resolveEffectiveWorkspace(
|
|
3161
|
+
activeCourse.courseTitle,
|
|
3162
|
+
onboardingState?.workspacePath,
|
|
3163
|
+
cwd
|
|
3164
|
+
);
|
|
3165
|
+
return {
|
|
3166
|
+
initReady,
|
|
3167
|
+
workspaceReady: ws.found,
|
|
3168
|
+
workspacePath: ws.workspacePath,
|
|
3169
|
+
workspaceSource: ws.source
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
var init_status = __esm({
|
|
3173
|
+
"src/onboarding/status.ts"() {
|
|
3174
|
+
"use strict";
|
|
3175
|
+
init_session();
|
|
3176
|
+
init_resolve();
|
|
3177
|
+
}
|
|
3178
|
+
});
|
|
3179
|
+
|
|
3047
3180
|
// src/commands/select.ts
|
|
3048
3181
|
import { Command as Command6 } from "commander";
|
|
3182
|
+
import os7 from "node:os";
|
|
3049
3183
|
var logger5, selectCommand;
|
|
3050
3184
|
var init_select = __esm({
|
|
3051
3185
|
"src/commands/select.ts"() {
|
|
@@ -3056,6 +3190,7 @@ var init_select = __esm({
|
|
|
3056
3190
|
init_session();
|
|
3057
3191
|
init_formatter();
|
|
3058
3192
|
init_instruction_files();
|
|
3193
|
+
init_status();
|
|
3059
3194
|
logger5 = createLogger("cli:select");
|
|
3060
3195
|
selectCommand = new Command6("select").description("Activate a course by ID or list index number").argument("<course>", "Course ID (UUID) or index number from `tostudy courses`").option("--json", "Output structured JSON").action(async (course, opts) => {
|
|
3061
3196
|
try {
|
|
@@ -3088,6 +3223,12 @@ var init_select = __esm({
|
|
|
3088
3223
|
courseTags: matched?.tags,
|
|
3089
3224
|
courseLevel: matched?.level
|
|
3090
3225
|
});
|
|
3226
|
+
const activeCourseForStatus = {
|
|
3227
|
+
courseId: detail.courseId,
|
|
3228
|
+
courseTitle: detail.courseTitle,
|
|
3229
|
+
enrollmentId
|
|
3230
|
+
};
|
|
3231
|
+
const onboarding = await getCourseOnboardingStatus(activeCourseForStatus);
|
|
3091
3232
|
let courseSlug2 = "";
|
|
3092
3233
|
try {
|
|
3093
3234
|
courseSlug2 = generateInstructionFiles({
|
|
@@ -3096,7 +3237,9 @@ var init_select = __esm({
|
|
|
3096
3237
|
progress: detail.progress,
|
|
3097
3238
|
moduleCount: detail.moduleCount,
|
|
3098
3239
|
lessonCount: detail.lessonCount,
|
|
3099
|
-
courseDescription: detail.courseDescription
|
|
3240
|
+
courseDescription: detail.courseDescription,
|
|
3241
|
+
workspaceReady: onboarding.workspaceReady,
|
|
3242
|
+
workspacePath: onboarding.workspacePath ?? void 0
|
|
3100
3243
|
});
|
|
3101
3244
|
} catch (err) {
|
|
3102
3245
|
logger5.warn("Failed to generate instruction files", {
|
|
@@ -3104,13 +3247,36 @@ var init_select = __esm({
|
|
|
3104
3247
|
});
|
|
3105
3248
|
}
|
|
3106
3249
|
if (opts.json) {
|
|
3107
|
-
output(
|
|
3250
|
+
output(
|
|
3251
|
+
{
|
|
3252
|
+
...detail,
|
|
3253
|
+
enrollmentId,
|
|
3254
|
+
courseSlug: courseSlug2,
|
|
3255
|
+
workspacePath: onboarding.workspacePath,
|
|
3256
|
+
workspaceSource: onboarding.workspaceSource
|
|
3257
|
+
},
|
|
3258
|
+
{ json: true }
|
|
3259
|
+
);
|
|
3108
3260
|
} else {
|
|
3109
3261
|
const slashCmd = courseSlug2 ? `/tostudy-${courseSlug2}` : "/tostudy";
|
|
3262
|
+
const home = os7.homedir();
|
|
3263
|
+
const cwd = process.cwd();
|
|
3264
|
+
const namespacedPath = `${cwd}/.tostudy`;
|
|
3265
|
+
let wsLine;
|
|
3266
|
+
if (onboarding.workspacePath === namespacedPath) {
|
|
3267
|
+
wsLine = ` Workspace: ${cwd.replace(home, "~")}/.tostudy/ (isolado do projeto)`;
|
|
3268
|
+
} else if (onboarding.workspacePath === cwd) {
|
|
3269
|
+
wsLine = ` Workspace: esta pasta (${cwd.replace(home, "~")})`;
|
|
3270
|
+
} else if (onboarding.workspacePath) {
|
|
3271
|
+
wsLine = ` Workspace: ${onboarding.workspacePath.replace(home, "~")}`;
|
|
3272
|
+
} else {
|
|
3273
|
+
wsLine = " Workspace: rode `tostudy workspace setup` para configurar";
|
|
3274
|
+
}
|
|
3110
3275
|
output(
|
|
3111
3276
|
[
|
|
3112
3277
|
`\u2713 Curso ativado: ${detail.courseTitle}`,
|
|
3113
3278
|
` Progresso: ${detail.progress}% | ${detail.moduleCount} m\xF3dulos | ${detail.lessonCount} li\xE7\xF5es`,
|
|
3279
|
+
wsLine,
|
|
3114
3280
|
"",
|
|
3115
3281
|
" Arquivos de contexto criados para seu assistente AI.",
|
|
3116
3282
|
"",
|
|
@@ -4709,7 +4875,7 @@ var init_query_promise = __esm({
|
|
|
4709
4875
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
4710
4876
|
const nullifyMap = {};
|
|
4711
4877
|
const result = columns.reduce(
|
|
4712
|
-
(result2, { path:
|
|
4878
|
+
(result2, { path: path14, field }, columnIndex) => {
|
|
4713
4879
|
let decoder;
|
|
4714
4880
|
if (is(field, Column)) {
|
|
4715
4881
|
decoder = field;
|
|
@@ -4721,8 +4887,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
4721
4887
|
decoder = field.sql.decoder;
|
|
4722
4888
|
}
|
|
4723
4889
|
let node = result2;
|
|
4724
|
-
for (const [pathChunkIndex, pathChunk] of
|
|
4725
|
-
if (pathChunkIndex <
|
|
4890
|
+
for (const [pathChunkIndex, pathChunk] of path14.entries()) {
|
|
4891
|
+
if (pathChunkIndex < path14.length - 1) {
|
|
4726
4892
|
if (!(pathChunk in node)) {
|
|
4727
4893
|
node[pathChunk] = {};
|
|
4728
4894
|
}
|
|
@@ -4730,8 +4896,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
4730
4896
|
} else {
|
|
4731
4897
|
const rawValue = row[columnIndex];
|
|
4732
4898
|
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
4733
|
-
if (joinsNotNullableMap && is(field, Column) &&
|
|
4734
|
-
const objectName =
|
|
4899
|
+
if (joinsNotNullableMap && is(field, Column) && path14.length === 2) {
|
|
4900
|
+
const objectName = path14[0];
|
|
4735
4901
|
if (!(objectName in nullifyMap)) {
|
|
4736
4902
|
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
4737
4903
|
} else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
@@ -8678,13 +8844,13 @@ function Subscribe(postgres2, options) {
|
|
|
8678
8844
|
}
|
|
8679
8845
|
}
|
|
8680
8846
|
function handle(a, b2) {
|
|
8681
|
-
const
|
|
8847
|
+
const path14 = b2.relation.schema + "." + b2.relation.table;
|
|
8682
8848
|
call("*", a, b2);
|
|
8683
|
-
call("*:" +
|
|
8684
|
-
b2.relation.keys.length && call("*:" +
|
|
8849
|
+
call("*:" + path14, a, b2);
|
|
8850
|
+
b2.relation.keys.length && call("*:" + path14 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
|
|
8685
8851
|
call(b2.command, a, b2);
|
|
8686
|
-
call(b2.command + ":" +
|
|
8687
|
-
b2.relation.keys.length && call(b2.command + ":" +
|
|
8852
|
+
call(b2.command + ":" + path14, a, b2);
|
|
8853
|
+
b2.relation.keys.length && call(b2.command + ":" + path14 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
|
|
8688
8854
|
}
|
|
8689
8855
|
function pong() {
|
|
8690
8856
|
const x2 = Buffer.alloc(34);
|
|
@@ -8797,8 +8963,8 @@ function parseEvent(x) {
|
|
|
8797
8963
|
const xs = x.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i) || [];
|
|
8798
8964
|
if (!xs)
|
|
8799
8965
|
throw new Error("Malformed subscribe pattern: " + x);
|
|
8800
|
-
const [, command,
|
|
8801
|
-
return (command || "*") + (
|
|
8966
|
+
const [, command, path14, key] = xs;
|
|
8967
|
+
return (command || "*") + (path14 ? ":" + (path14.indexOf(".") === -1 ? "public." + path14 : path14) : "") + (key ? "=" + key : "");
|
|
8802
8968
|
}
|
|
8803
8969
|
var noop2;
|
|
8804
8970
|
var init_subscribe = __esm({
|
|
@@ -8879,8 +9045,8 @@ var init_large = __esm({
|
|
|
8879
9045
|
});
|
|
8880
9046
|
|
|
8881
9047
|
// ../../node_modules/postgres/src/index.js
|
|
8882
|
-
import
|
|
8883
|
-
import
|
|
9048
|
+
import os8 from "os";
|
|
9049
|
+
import fs6 from "fs";
|
|
8884
9050
|
function Postgres(a, b2) {
|
|
8885
9051
|
const options = parseOptions(a, b2), subscribe = options.no_subscribe || Subscribe(Postgres, { ...options });
|
|
8886
9052
|
let ending = false;
|
|
@@ -8936,10 +9102,10 @@ function Postgres(a, b2) {
|
|
|
8936
9102
|
});
|
|
8937
9103
|
return query;
|
|
8938
9104
|
}
|
|
8939
|
-
function file2(
|
|
9105
|
+
function file2(path14, args = [], options2 = {}) {
|
|
8940
9106
|
arguments.length === 2 && !Array.isArray(args) && (options2 = args, args = []);
|
|
8941
9107
|
const query = new Query([], args, (query2) => {
|
|
8942
|
-
|
|
9108
|
+
fs6.readFile(path14, "utf8", (err, string4) => {
|
|
8943
9109
|
if (err)
|
|
8944
9110
|
return query2.reject(err);
|
|
8945
9111
|
query2.strings = [string4];
|
|
@@ -9257,7 +9423,7 @@ function parseUrl(url2) {
|
|
|
9257
9423
|
}
|
|
9258
9424
|
function osUsername() {
|
|
9259
9425
|
try {
|
|
9260
|
-
return
|
|
9426
|
+
return os8.userInfo().username;
|
|
9261
9427
|
} catch (_) {
|
|
9262
9428
|
return process.env.USERNAME || process.env.USER || process.env.LOGNAME;
|
|
9263
9429
|
}
|
|
@@ -13518,12 +13684,12 @@ var init_session3 = __esm({
|
|
|
13518
13684
|
init_tracing();
|
|
13519
13685
|
init_utils();
|
|
13520
13686
|
PostgresJsPreparedQuery = class extends PgPreparedQuery {
|
|
13521
|
-
constructor(client, queryString, params,
|
|
13687
|
+
constructor(client, queryString, params, logger19, cache, queryMetadata, cacheConfig, fields, _isResponseInArrayMode, customResultMapper) {
|
|
13522
13688
|
super({ sql: queryString, params }, cache, queryMetadata, cacheConfig);
|
|
13523
13689
|
this.client = client;
|
|
13524
13690
|
this.queryString = queryString;
|
|
13525
13691
|
this.params = params;
|
|
13526
|
-
this.logger =
|
|
13692
|
+
this.logger = logger19;
|
|
13527
13693
|
this.fields = fields;
|
|
13528
13694
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
13529
13695
|
this.customResultMapper = customResultMapper;
|
|
@@ -13664,11 +13830,11 @@ function construct(client, config2 = {}) {
|
|
|
13664
13830
|
client.options.serializers["114"] = transparentParser;
|
|
13665
13831
|
client.options.serializers["3802"] = transparentParser;
|
|
13666
13832
|
const dialect = new PgDialect({ casing: config2.casing });
|
|
13667
|
-
let
|
|
13833
|
+
let logger19;
|
|
13668
13834
|
if (config2.logger === true) {
|
|
13669
|
-
|
|
13835
|
+
logger19 = new DefaultLogger();
|
|
13670
13836
|
} else if (config2.logger !== false) {
|
|
13671
|
-
|
|
13837
|
+
logger19 = config2.logger;
|
|
13672
13838
|
}
|
|
13673
13839
|
let schema;
|
|
13674
13840
|
if (config2.schema) {
|
|
@@ -13682,7 +13848,7 @@ function construct(client, config2 = {}) {
|
|
|
13682
13848
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
13683
13849
|
};
|
|
13684
13850
|
}
|
|
13685
|
-
const session = new PostgresJsSession(client, dialect, schema, { logger:
|
|
13851
|
+
const session = new PostgresJsSession(client, dialect, schema, { logger: logger19, cache: config2.cache });
|
|
13686
13852
|
const db2 = new PostgresJsDatabase(dialect, session, schema);
|
|
13687
13853
|
db2.$client = client;
|
|
13688
13854
|
db2.$cache = config2.cache;
|
|
@@ -13884,7 +14050,7 @@ __export(util_exports, {
|
|
|
13884
14050
|
required: () => required,
|
|
13885
14051
|
safeExtend: () => safeExtend,
|
|
13886
14052
|
shallowClone: () => shallowClone,
|
|
13887
|
-
slugify: () =>
|
|
14053
|
+
slugify: () => slugify2,
|
|
13888
14054
|
stringifyPrimitive: () => stringifyPrimitive,
|
|
13889
14055
|
uint8ArrayToBase64: () => uint8ArrayToBase64,
|
|
13890
14056
|
uint8ArrayToBase64url: () => uint8ArrayToBase64url,
|
|
@@ -13997,10 +14163,10 @@ function mergeDefs(...defs) {
|
|
|
13997
14163
|
function cloneDef(schema) {
|
|
13998
14164
|
return mergeDefs(schema._zod.def);
|
|
13999
14165
|
}
|
|
14000
|
-
function getElementAtPath(obj,
|
|
14001
|
-
if (!
|
|
14166
|
+
function getElementAtPath(obj, path14) {
|
|
14167
|
+
if (!path14)
|
|
14002
14168
|
return obj;
|
|
14003
|
-
return
|
|
14169
|
+
return path14.reduce((acc, key) => acc?.[key], obj);
|
|
14004
14170
|
}
|
|
14005
14171
|
function promiseAllObject(promisesObj) {
|
|
14006
14172
|
const keys = Object.keys(promisesObj);
|
|
@@ -14024,7 +14190,7 @@ function randomString(length = 10) {
|
|
|
14024
14190
|
function esc(str) {
|
|
14025
14191
|
return JSON.stringify(str);
|
|
14026
14192
|
}
|
|
14027
|
-
function
|
|
14193
|
+
function slugify2(input2) {
|
|
14028
14194
|
return input2.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
14029
14195
|
}
|
|
14030
14196
|
function isObject(data) {
|
|
@@ -14312,11 +14478,11 @@ function aborted(x, startIndex = 0) {
|
|
|
14312
14478
|
}
|
|
14313
14479
|
return false;
|
|
14314
14480
|
}
|
|
14315
|
-
function prefixIssues(
|
|
14481
|
+
function prefixIssues(path14, issues) {
|
|
14316
14482
|
return issues.map((iss) => {
|
|
14317
14483
|
var _a2;
|
|
14318
14484
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
14319
|
-
iss.path.unshift(
|
|
14485
|
+
iss.path.unshift(path14);
|
|
14320
14486
|
return iss;
|
|
14321
14487
|
});
|
|
14322
14488
|
}
|
|
@@ -14558,7 +14724,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
|
|
|
14558
14724
|
}
|
|
14559
14725
|
function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
14560
14726
|
const result = { errors: [] };
|
|
14561
|
-
const processError = (error50,
|
|
14727
|
+
const processError = (error50, path14 = []) => {
|
|
14562
14728
|
var _a2, _b;
|
|
14563
14729
|
for (const issue2 of error50.issues) {
|
|
14564
14730
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -14568,7 +14734,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
14568
14734
|
} else if (issue2.code === "invalid_element") {
|
|
14569
14735
|
processError({ issues: issue2.issues }, issue2.path);
|
|
14570
14736
|
} else {
|
|
14571
|
-
const fullpath = [...
|
|
14737
|
+
const fullpath = [...path14, ...issue2.path];
|
|
14572
14738
|
if (fullpath.length === 0) {
|
|
14573
14739
|
result.errors.push(mapper(issue2));
|
|
14574
14740
|
continue;
|
|
@@ -14600,8 +14766,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
14600
14766
|
}
|
|
14601
14767
|
function toDotPath(_path) {
|
|
14602
14768
|
const segs = [];
|
|
14603
|
-
const
|
|
14604
|
-
for (const seg of
|
|
14769
|
+
const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
14770
|
+
for (const seg of path14) {
|
|
14605
14771
|
if (typeof seg === "number")
|
|
14606
14772
|
segs.push(`[${seg}]`);
|
|
14607
14773
|
else if (typeof seg === "symbol")
|
|
@@ -24158,7 +24324,7 @@ function _toUpperCase() {
|
|
|
24158
24324
|
}
|
|
24159
24325
|
// @__NO_SIDE_EFFECTS__
|
|
24160
24326
|
function _slugify() {
|
|
24161
|
-
return /* @__PURE__ */ _overwrite((input2) =>
|
|
24327
|
+
return /* @__PURE__ */ _overwrite((input2) => slugify2(input2));
|
|
24162
24328
|
}
|
|
24163
24329
|
// @__NO_SIDE_EFFECTS__
|
|
24164
24330
|
function _array(Class2, element, params) {
|
|
@@ -27295,13 +27461,13 @@ function resolveRef(ref, ctx) {
|
|
|
27295
27461
|
if (!ref.startsWith("#")) {
|
|
27296
27462
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
27297
27463
|
}
|
|
27298
|
-
const
|
|
27299
|
-
if (
|
|
27464
|
+
const path14 = ref.slice(1).split("/").filter(Boolean);
|
|
27465
|
+
if (path14.length === 0) {
|
|
27300
27466
|
return ctx.rootSchema;
|
|
27301
27467
|
}
|
|
27302
27468
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
27303
|
-
if (
|
|
27304
|
-
const key =
|
|
27469
|
+
if (path14[0] === defsKey) {
|
|
27470
|
+
const key = path14[1];
|
|
27305
27471
|
if (!key || !ctx.defs[key]) {
|
|
27306
27472
|
throw new Error(`Reference not found: ${ref}`);
|
|
27307
27473
|
}
|
|
@@ -28490,7 +28656,11 @@ var init_courses3 = __esm({
|
|
|
28490
28656
|
// Learning Path Graph: Reference to migrated graph (null if not migrated)
|
|
28491
28657
|
migratedToGraphId: uuid("migrated_to_graph_id"),
|
|
28492
28658
|
// Study Channel Configuration: which channels are available for this course
|
|
28493
|
-
channelConfig: jsonb("channel_config").$type()
|
|
28659
|
+
channelConfig: jsonb("channel_config").$type(),
|
|
28660
|
+
// Course Quality Dashboard: Cached health score (0-100 with tier + dimensions)
|
|
28661
|
+
healthScore: jsonb("health_score").$type(),
|
|
28662
|
+
// Certificate: AI-generated course summary for PDF certificates (max 200 chars)
|
|
28663
|
+
certificateSummary: varchar("certificate_summary", { length: 200 })
|
|
28494
28664
|
},
|
|
28495
28665
|
(table) => ({
|
|
28496
28666
|
creatorIdIdx: index("courses_creator_id_idx").on(table.creatorId),
|
|
@@ -32926,29 +33096,32 @@ var init_validation_attempts = __esm({
|
|
|
32926
33096
|
init_users();
|
|
32927
33097
|
init_enrollments();
|
|
32928
33098
|
init_courses3();
|
|
32929
|
-
validationAttempts2 = pgTable(
|
|
32930
|
-
|
|
32931
|
-
|
|
32932
|
-
|
|
32933
|
-
|
|
32934
|
-
|
|
32935
|
-
|
|
32936
|
-
|
|
32937
|
-
|
|
32938
|
-
|
|
32939
|
-
|
|
32940
|
-
|
|
32941
|
-
|
|
32942
|
-
|
|
32943
|
-
|
|
32944
|
-
|
|
32945
|
-
|
|
32946
|
-
|
|
32947
|
-
|
|
32948
|
-
|
|
32949
|
-
|
|
32950
|
-
|
|
32951
|
-
|
|
33099
|
+
validationAttempts2 = pgTable(
|
|
33100
|
+
"validation_attempts",
|
|
33101
|
+
{
|
|
33102
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
33103
|
+
lessonId: uuid("lesson_id").references(() => lessons.id, { onDelete: "cascade" }).notNull(),
|
|
33104
|
+
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
33105
|
+
passed: boolean("passed").notNull(),
|
|
33106
|
+
score: real("score"),
|
|
33107
|
+
feedback: text("feedback"),
|
|
33108
|
+
missingCriteria: jsonb("missing_criteria").$type(),
|
|
33109
|
+
attemptedAt: timestamp("attempted_at").defaultNow().notNull(),
|
|
33110
|
+
// v2 — validation persistence & learning analytics
|
|
33111
|
+
enrollmentId: uuid("enrollment_id").references(() => enrollments.id, { onDelete: "cascade" }),
|
|
33112
|
+
courseId: uuid("course_id").references(() => courses.id, { onDelete: "cascade" }),
|
|
33113
|
+
exerciseIndex: integer("exercise_index"),
|
|
33114
|
+
solution: text("solution"),
|
|
33115
|
+
criteriaResults: jsonb("criteria_results").$type(),
|
|
33116
|
+
source: text("source").$type(),
|
|
33117
|
+
duration: integer("duration")
|
|
33118
|
+
},
|
|
33119
|
+
(table) => [
|
|
33120
|
+
index("va_user_lesson_exercise_idx").on(table.userId, table.lessonId, table.exerciseIndex),
|
|
33121
|
+
index("va_course_lesson_passed_idx").on(table.courseId, table.lessonId, table.passed),
|
|
33122
|
+
index("va_user_course_attempted_idx").on(table.userId, table.courseId, table.attemptedAt)
|
|
33123
|
+
]
|
|
33124
|
+
);
|
|
32952
33125
|
}
|
|
32953
33126
|
});
|
|
32954
33127
|
|
|
@@ -35131,77 +35304,6 @@ var init_course_variants = __esm({
|
|
|
35131
35304
|
}
|
|
35132
35305
|
});
|
|
35133
35306
|
|
|
35134
|
-
// ../../packages/database/src/schema/_archived/user-credits.ts
|
|
35135
|
-
var transactionTypeEnum, userCredits2, creditTransactions2;
|
|
35136
|
-
var init_user_credits = __esm({
|
|
35137
|
-
"../../packages/database/src/schema/_archived/user-credits.ts"() {
|
|
35138
|
-
"use strict";
|
|
35139
|
-
init_pg_core();
|
|
35140
|
-
init_users();
|
|
35141
|
-
transactionTypeEnum = pgEnum("transaction_type", [
|
|
35142
|
-
"initial_grant",
|
|
35143
|
-
// Credito inicial de $5
|
|
35144
|
-
"purchase",
|
|
35145
|
-
// Compra de creditos
|
|
35146
|
-
"consumption",
|
|
35147
|
-
// Consumo por uso de IA
|
|
35148
|
-
"refund",
|
|
35149
|
-
// Reembolso
|
|
35150
|
-
"adjustment"
|
|
35151
|
-
// Ajuste manual admin
|
|
35152
|
-
]);
|
|
35153
|
-
userCredits2 = pgTable(
|
|
35154
|
-
"user_credits",
|
|
35155
|
-
{
|
|
35156
|
-
id: uuid("id").primaryKey().defaultRandom(),
|
|
35157
|
-
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull().unique(),
|
|
35158
|
-
/** Current balance in USD */
|
|
35159
|
-
balance: decimal("balance", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
35160
|
-
/** Total consumed in USD (absolute value, always positive) */
|
|
35161
|
-
totalConsumed: decimal("total_consumed", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
35162
|
-
/** Total purchased in USD */
|
|
35163
|
-
totalPurchased: decimal("total_purchased", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
35164
|
-
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
35165
|
-
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
35166
|
-
},
|
|
35167
|
-
(table) => ({
|
|
35168
|
-
userIdIdx: index("user_credits_user_id_idx").on(table.userId)
|
|
35169
|
-
})
|
|
35170
|
-
);
|
|
35171
|
-
creditTransactions2 = pgTable(
|
|
35172
|
-
"credit_transactions",
|
|
35173
|
-
{
|
|
35174
|
-
id: uuid("id").primaryKey().defaultRandom(),
|
|
35175
|
-
userId: uuid("user_id").references(() => users.id, { onDelete: "restrict" }).notNull(),
|
|
35176
|
-
type: transactionTypeEnum("type").notNull(),
|
|
35177
|
-
/** Amount in USD (negative for consumption, positive for purchase/grant) */
|
|
35178
|
-
amount: decimal("amount", { precision: 10, scale: 4 }).notNull(),
|
|
35179
|
-
/** Balance after this transaction in USD */
|
|
35180
|
-
balanceAfter: decimal("balance_after", { precision: 10, scale: 4 }).notNull(),
|
|
35181
|
-
description: text("description"),
|
|
35182
|
-
metadata: text("metadata"),
|
|
35183
|
-
// JSON com detalhes (tokens, modelo, etc)
|
|
35184
|
-
// Granular usage tracking columns
|
|
35185
|
-
operation: varchar("operation", { length: 50 }),
|
|
35186
|
-
// 'brainstorm_message', 'generation_outline', etc.
|
|
35187
|
-
model: varchar("model", { length: 100 }),
|
|
35188
|
-
// 'claude-sonnet-4-5-20250929'
|
|
35189
|
-
inputTokens: integer("input_tokens"),
|
|
35190
|
-
outputTokens: integer("output_tokens"),
|
|
35191
|
-
latencyMs: integer("latency_ms"),
|
|
35192
|
-
// DB FK to course_proposals preserved in migration; Drizzle ref removed for schema archival
|
|
35193
|
-
proposalId: uuid("proposal_id"),
|
|
35194
|
-
sessionId: uuid("session_id"),
|
|
35195
|
-
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
35196
|
-
},
|
|
35197
|
-
(table) => ({
|
|
35198
|
-
userIdIdx: index("credit_transactions_user_id_idx").on(table.userId),
|
|
35199
|
-
createdAtIdx: index("credit_transactions_created_at_idx").on(table.createdAt)
|
|
35200
|
-
})
|
|
35201
|
-
);
|
|
35202
|
-
}
|
|
35203
|
-
});
|
|
35204
|
-
|
|
35205
35307
|
// ../../packages/database/src/schema/_archived/index.ts
|
|
35206
35308
|
var init_archived = __esm({
|
|
35207
35309
|
"../../packages/database/src/schema/_archived/index.ts"() {
|
|
@@ -35210,7 +35312,6 @@ var init_archived = __esm({
|
|
|
35210
35312
|
init_course_matrices();
|
|
35211
35313
|
init_matrix_modules();
|
|
35212
35314
|
init_course_variants();
|
|
35213
|
-
init_user_credits();
|
|
35214
35315
|
}
|
|
35215
35316
|
});
|
|
35216
35317
|
|
|
@@ -36417,7 +36518,6 @@ var init_system_config = __esm({
|
|
|
36417
36518
|
"business.limits.free_brainstorm_sessions": "business.limits.free_brainstorm_sessions",
|
|
36418
36519
|
// Feature Flags
|
|
36419
36520
|
"feature.spark_chat_enabled": "feature.spark_chat_enabled",
|
|
36420
|
-
"feature.ai_course_generation_enabled": "feature.ai_course_generation_enabled",
|
|
36421
36521
|
"feature.analytics_enabled": "feature.analytics_enabled",
|
|
36422
36522
|
"feature.mentorship_enabled": "feature.mentorship_enabled",
|
|
36423
36523
|
"feature.community_enabled": "feature.community_enabled",
|
|
@@ -38896,7 +38996,6 @@ __export(schema_exports, {
|
|
|
38896
38996
|
creditSubscriptionPlans: () => creditSubscriptionPlans,
|
|
38897
38997
|
creditSubscriptionStatusEnum: () => creditSubscriptionStatusEnum,
|
|
38898
38998
|
creditSubscriptions: () => creditSubscriptions,
|
|
38899
|
-
creditTransactions: () => creditTransactions2,
|
|
38900
38999
|
creditWalletTransactionTypeEnum: () => creditWalletTransactionTypeEnum,
|
|
38901
39000
|
creditWalletTransactions: () => creditWalletTransactions,
|
|
38902
39001
|
creditWallets: () => creditWallets,
|
|
@@ -39182,7 +39281,6 @@ __export(schema_exports, {
|
|
|
39182
39281
|
testimonialStatusEnum: () => testimonialStatusEnum,
|
|
39183
39282
|
threadStatusEnum: () => threadStatusEnum,
|
|
39184
39283
|
toneEnum: () => toneEnum,
|
|
39185
|
-
transactionTypeEnum: () => transactionTypeEnum,
|
|
39186
39284
|
transactions: () => transactions2,
|
|
39187
39285
|
transactionsRelations: () => transactionsRelations2,
|
|
39188
39286
|
transferStatusEnum: () => transferStatusEnum,
|
|
@@ -39199,7 +39297,6 @@ __export(schema_exports, {
|
|
|
39199
39297
|
userBadgesRelations: () => userBadgesRelations2,
|
|
39200
39298
|
userChallengeScores: () => userChallengeScores,
|
|
39201
39299
|
userChallengeScoresRelations: () => userChallengeScoresRelations,
|
|
39202
|
-
userCredits: () => userCredits2,
|
|
39203
39300
|
userFollows: () => userFollows2,
|
|
39204
39301
|
userFollowsRelations: () => userFollowsRelations2,
|
|
39205
39302
|
userPathEnrollments: () => userPathEnrollments,
|
|
@@ -40896,65 +40993,6 @@ var init_lessons2 = __esm({
|
|
|
40896
40993
|
}
|
|
40897
40994
|
});
|
|
40898
40995
|
|
|
40899
|
-
// src/workspace/resolve.ts
|
|
40900
|
-
import fs6 from "node:fs/promises";
|
|
40901
|
-
import path5 from "node:path";
|
|
40902
|
-
import os6 from "node:os";
|
|
40903
|
-
function courseSlug(title) {
|
|
40904
|
-
return title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
40905
|
-
}
|
|
40906
|
-
async function resolveWorkspace(courseTitle, basePath = DEFAULT_BASE) {
|
|
40907
|
-
const slug = courseSlug(courseTitle);
|
|
40908
|
-
const candidate = path5.join(basePath, slug);
|
|
40909
|
-
try {
|
|
40910
|
-
await fs6.access(path5.join(candidate, ".ana-config.json"));
|
|
40911
|
-
return { found: true, workspacePath: candidate };
|
|
40912
|
-
} catch {
|
|
40913
|
-
return { found: false, workspacePath: null };
|
|
40914
|
-
}
|
|
40915
|
-
}
|
|
40916
|
-
var DEFAULT_BASE;
|
|
40917
|
-
var init_resolve = __esm({
|
|
40918
|
-
"src/workspace/resolve.ts"() {
|
|
40919
|
-
"use strict";
|
|
40920
|
-
DEFAULT_BASE = path5.join(os6.homedir(), "study");
|
|
40921
|
-
}
|
|
40922
|
-
});
|
|
40923
|
-
|
|
40924
|
-
// src/onboarding/status.ts
|
|
40925
|
-
import fs7 from "node:fs/promises";
|
|
40926
|
-
import path6 from "node:path";
|
|
40927
|
-
async function resolveStoredWorkspace(workspacePath) {
|
|
40928
|
-
if (!workspacePath) return null;
|
|
40929
|
-
try {
|
|
40930
|
-
await fs7.access(path6.join(workspacePath, ".ana-config.json"));
|
|
40931
|
-
return workspacePath;
|
|
40932
|
-
} catch {
|
|
40933
|
-
return null;
|
|
40934
|
-
}
|
|
40935
|
-
}
|
|
40936
|
-
async function getCourseOnboardingStatus(activeCourse, configDir) {
|
|
40937
|
-
const onboardingState = await getCourseOnboardingState(activeCourse.courseId, configDir);
|
|
40938
|
-
const initReady = Boolean(onboardingState?.initCompletedAt);
|
|
40939
|
-
let workspacePath = await resolveStoredWorkspace(onboardingState?.workspacePath);
|
|
40940
|
-
if (!workspacePath) {
|
|
40941
|
-
const resolvedWorkspace = await resolveWorkspace(activeCourse.courseTitle);
|
|
40942
|
-
workspacePath = resolvedWorkspace.workspacePath;
|
|
40943
|
-
}
|
|
40944
|
-
return {
|
|
40945
|
-
initReady,
|
|
40946
|
-
workspaceReady: Boolean(workspacePath),
|
|
40947
|
-
workspacePath
|
|
40948
|
-
};
|
|
40949
|
-
}
|
|
40950
|
-
var init_status = __esm({
|
|
40951
|
-
"src/onboarding/status.ts"() {
|
|
40952
|
-
"use strict";
|
|
40953
|
-
init_session();
|
|
40954
|
-
init_resolve();
|
|
40955
|
-
}
|
|
40956
|
-
});
|
|
40957
|
-
|
|
40958
40996
|
// src/commands/start.ts
|
|
40959
40997
|
import { Command as Command8 } from "commander";
|
|
40960
40998
|
async function runStart(opts, deps = defaultDeps2) {
|
|
@@ -41190,10 +41228,14 @@ var init_lesson = __esm({
|
|
|
41190
41228
|
output(formatLessonContent(content), { json: false });
|
|
41191
41229
|
}
|
|
41192
41230
|
if (content.type === "exercise") {
|
|
41193
|
-
const
|
|
41231
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
41232
|
+
const ws = await resolveEffectiveWorkspace(
|
|
41233
|
+
activeCourse.courseTitle,
|
|
41234
|
+
onboardingState?.workspacePath
|
|
41235
|
+
);
|
|
41194
41236
|
if (!ws.found) {
|
|
41195
41237
|
process.stderr.write(
|
|
41196
|
-
"\n\u{1F4A1} Dica: rode `tostudy
|
|
41238
|
+
"\n\u{1F4A1} Dica: rode `tostudy select` desta pasta para us\xE1-la como workspace, ou `tostudy workspace setup` para criar em ~/study/.\n"
|
|
41197
41239
|
);
|
|
41198
41240
|
}
|
|
41199
41241
|
}
|
|
@@ -41270,8 +41312,8 @@ var init_exercises = __esm({
|
|
|
41270
41312
|
});
|
|
41271
41313
|
|
|
41272
41314
|
// src/commands/validate.ts
|
|
41273
|
-
import
|
|
41274
|
-
import
|
|
41315
|
+
import fs7 from "node:fs";
|
|
41316
|
+
import path6 from "node:path";
|
|
41275
41317
|
import { Command as Command13 } from "commander";
|
|
41276
41318
|
var logger12, validateCommand;
|
|
41277
41319
|
var init_validate = __esm({
|
|
@@ -41296,17 +41338,17 @@ var init_validate = __esm({
|
|
|
41296
41338
|
}
|
|
41297
41339
|
let solution;
|
|
41298
41340
|
if (opts.stdin) {
|
|
41299
|
-
solution =
|
|
41341
|
+
solution = fs7.readFileSync("/dev/stdin", "utf-8");
|
|
41300
41342
|
} else if (file2) {
|
|
41301
|
-
if (!
|
|
41343
|
+
if (!fs7.existsSync(file2)) {
|
|
41302
41344
|
error(`Arquivo n\xE3o encontrado: ${file2}`);
|
|
41303
41345
|
}
|
|
41304
|
-
solution =
|
|
41346
|
+
solution = fs7.readFileSync(file2, "utf-8");
|
|
41305
41347
|
} else {
|
|
41306
41348
|
error("Forne\xE7a um arquivo ou use --stdin.\n\nExemplo: tostudy validate resposta.md");
|
|
41307
41349
|
}
|
|
41308
41350
|
if (file2 && activeCourse.courseTags?.length) {
|
|
41309
|
-
const ext =
|
|
41351
|
+
const ext = path6.extname(file2).toLowerCase();
|
|
41310
41352
|
const LANG_EXTENSIONS = {
|
|
41311
41353
|
".html": ["html", "html5"],
|
|
41312
41354
|
".css": ["css"],
|
|
@@ -41739,14 +41781,14 @@ var init_init = __esm({
|
|
|
41739
41781
|
});
|
|
41740
41782
|
|
|
41741
41783
|
// ../../packages/tostudy-core/src/workspace/setup-workspace.ts
|
|
41742
|
-
import
|
|
41743
|
-
import
|
|
41784
|
+
import fs8 from "node:fs/promises";
|
|
41785
|
+
import path7 from "node:path";
|
|
41744
41786
|
async function setupWorkspace(input2) {
|
|
41745
|
-
const workspacePath =
|
|
41787
|
+
const workspacePath = path7.join(input2.basePath, input2.courseSlug);
|
|
41746
41788
|
for (const dir of WORKSPACE_DIRS) {
|
|
41747
|
-
await
|
|
41789
|
+
await fs8.mkdir(path7.join(workspacePath, dir), { recursive: true });
|
|
41748
41790
|
}
|
|
41749
|
-
const configPath =
|
|
41791
|
+
const configPath = path7.join(workspacePath, ".ana-config.json");
|
|
41750
41792
|
const config2 = {
|
|
41751
41793
|
courseId: input2.courseId,
|
|
41752
41794
|
courseSlug: input2.courseSlug,
|
|
@@ -41756,7 +41798,7 @@ async function setupWorkspace(input2) {
|
|
|
41756
41798
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41757
41799
|
lastAccessedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
41758
41800
|
};
|
|
41759
|
-
await
|
|
41801
|
+
await fs8.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
41760
41802
|
const readme = [
|
|
41761
41803
|
`# ${input2.courseName}`,
|
|
41762
41804
|
"",
|
|
@@ -41781,7 +41823,7 @@ async function setupWorkspace(input2) {
|
|
|
41781
41823
|
"tostudy vault sync # Sincronizar progresso",
|
|
41782
41824
|
"```"
|
|
41783
41825
|
].join("\n");
|
|
41784
|
-
await
|
|
41826
|
+
await fs8.writeFile(path7.join(workspacePath, "README.md"), readme, "utf-8");
|
|
41785
41827
|
return { workspacePath, directories: WORKSPACE_DIRS, configPath };
|
|
41786
41828
|
}
|
|
41787
41829
|
var WORKSPACE_DIRS;
|
|
@@ -41882,8 +41924,8 @@ var init_templates = __esm({
|
|
|
41882
41924
|
});
|
|
41883
41925
|
|
|
41884
41926
|
// ../../packages/tostudy-core/src/workspace/extract-exercise.ts
|
|
41885
|
-
import
|
|
41886
|
-
import
|
|
41927
|
+
import fs9 from "node:fs/promises";
|
|
41928
|
+
import path8 from "node:path";
|
|
41887
41929
|
function padOrder(n) {
|
|
41888
41930
|
return String(n).padStart(2, "0");
|
|
41889
41931
|
}
|
|
@@ -41907,16 +41949,16 @@ async function extractExercise(input2) {
|
|
|
41907
41949
|
const { lessonData, exerciseTier, workspacePath } = input2;
|
|
41908
41950
|
const moduleDir = `${padOrder(lessonData.moduleOrder)}-${lessonData.moduleSlug}`;
|
|
41909
41951
|
const lessonDir = `${padOrder(lessonData.lessonOrder)}-${lessonData.lessonSlug}`;
|
|
41910
|
-
const exercisePath =
|
|
41911
|
-
await
|
|
41952
|
+
const exercisePath = path8.join(workspacePath, "exercises", moduleDir, lessonDir);
|
|
41953
|
+
await fs9.mkdir(exercisePath, { recursive: true });
|
|
41912
41954
|
const extractedFiles = [];
|
|
41913
41955
|
let hasStarterCode = false;
|
|
41914
41956
|
if (lessonData.sandpackConfig?.files) {
|
|
41915
41957
|
for (const [filePath, fileData] of Object.entries(lessonData.sandpackConfig.files)) {
|
|
41916
41958
|
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
41917
|
-
const fullPath =
|
|
41918
|
-
await
|
|
41919
|
-
await
|
|
41959
|
+
const fullPath = path8.join(exercisePath, cleanPath);
|
|
41960
|
+
await fs9.mkdir(path8.dirname(fullPath), { recursive: true });
|
|
41961
|
+
await fs9.writeFile(fullPath, fileData.code, "utf-8");
|
|
41920
41962
|
extractedFiles.push(cleanPath);
|
|
41921
41963
|
hasStarterCode = true;
|
|
41922
41964
|
}
|
|
@@ -41924,13 +41966,13 @@ async function extractExercise(input2) {
|
|
|
41924
41966
|
const tierData = getTierData(lessonData.structuredData, exerciseTier);
|
|
41925
41967
|
const tierCode = tierData?.code;
|
|
41926
41968
|
if (tierCode) {
|
|
41927
|
-
await
|
|
41969
|
+
await fs9.writeFile(path8.join(exercisePath, "exercise.js"), tierCode, "utf-8");
|
|
41928
41970
|
extractedFiles.push("exercise.js");
|
|
41929
41971
|
hasStarterCode = true;
|
|
41930
41972
|
} else {
|
|
41931
41973
|
const starter = getStarterCode(lessonData.structuredData);
|
|
41932
41974
|
if (starter) {
|
|
41933
|
-
await
|
|
41975
|
+
await fs9.writeFile(path8.join(exercisePath, "exercise.js"), starter, "utf-8");
|
|
41934
41976
|
extractedFiles.push("exercise.js");
|
|
41935
41977
|
hasStarterCode = true;
|
|
41936
41978
|
}
|
|
@@ -41948,8 +41990,8 @@ async function extractExercise(input2) {
|
|
|
41948
41990
|
...exerciseDeps
|
|
41949
41991
|
}
|
|
41950
41992
|
};
|
|
41951
|
-
await
|
|
41952
|
-
|
|
41993
|
+
await fs9.writeFile(
|
|
41994
|
+
path8.join(exercisePath, "package.json"),
|
|
41953
41995
|
JSON.stringify(pkgJson, null, 2),
|
|
41954
41996
|
"utf-8"
|
|
41955
41997
|
);
|
|
@@ -41961,20 +42003,20 @@ async function extractExercise(input2) {
|
|
|
41961
42003
|
);
|
|
41962
42004
|
for (const [configFile, configContent] of Object.entries(scaffold.configs)) {
|
|
41963
42005
|
if (!sandpackFileNames.has(configFile)) {
|
|
41964
|
-
await
|
|
42006
|
+
await fs9.writeFile(path8.join(exercisePath, configFile), configContent, "utf-8");
|
|
41965
42007
|
extractedFiles.push(configFile);
|
|
41966
42008
|
}
|
|
41967
42009
|
}
|
|
41968
42010
|
const setupSh = `#!/bin/sh
|
|
41969
42011
|
${scaffold.setupScript}
|
|
41970
42012
|
`;
|
|
41971
|
-
await
|
|
42013
|
+
await fs9.writeFile(path8.join(exercisePath, "setup.sh"), setupSh, "utf-8");
|
|
41972
42014
|
extractedFiles.push("setup.sh");
|
|
41973
42015
|
}
|
|
41974
42016
|
}
|
|
41975
42017
|
const readme = generateReadme(lessonData, exerciseTier);
|
|
41976
|
-
const readmePath =
|
|
41977
|
-
await
|
|
42018
|
+
const readmePath = path8.join(exercisePath, "README.md");
|
|
42019
|
+
await fs9.writeFile(readmePath, readme, "utf-8");
|
|
41978
42020
|
extractedFiles.push("README.md");
|
|
41979
42021
|
return {
|
|
41980
42022
|
exercisePath,
|
|
@@ -42046,9 +42088,9 @@ var init_workspace = __esm({
|
|
|
42046
42088
|
|
|
42047
42089
|
// src/commands/workspace.ts
|
|
42048
42090
|
import { Command as Command16 } from "commander";
|
|
42049
|
-
import
|
|
42050
|
-
import
|
|
42051
|
-
import
|
|
42091
|
+
import path9 from "node:path";
|
|
42092
|
+
import os9 from "node:os";
|
|
42093
|
+
import fs10 from "node:fs/promises";
|
|
42052
42094
|
var logger14, workspaceCommand;
|
|
42053
42095
|
var init_workspace2 = __esm({
|
|
42054
42096
|
"src/commands/workspace.ts"() {
|
|
@@ -42056,31 +42098,67 @@ var init_workspace2 = __esm({
|
|
|
42056
42098
|
init_src();
|
|
42057
42099
|
init_workspace();
|
|
42058
42100
|
init_session();
|
|
42101
|
+
init_resolve();
|
|
42059
42102
|
logger14 = createLogger("cli:workspace");
|
|
42060
42103
|
workspaceCommand = new Command16("workspace").description(
|
|
42061
42104
|
"Gerenciar workspace de estudo local"
|
|
42062
42105
|
);
|
|
42063
|
-
workspaceCommand.command("setup").description("Criar estrutura do workspace para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace
|
|
42106
|
+
workspaceCommand.command("setup").description("Criar estrutura do workspace para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace (omita para usar a pasta atual)").option("--json", "Output structured JSON").action(async (opts) => {
|
|
42064
42107
|
try {
|
|
42065
42108
|
await requireSession();
|
|
42066
42109
|
const activeCourse = await requireActiveCourse();
|
|
42067
|
-
const
|
|
42068
|
-
|
|
42069
|
-
|
|
42070
|
-
|
|
42071
|
-
|
|
42072
|
-
|
|
42073
|
-
|
|
42074
|
-
|
|
42110
|
+
const cwdIsWorkspace = await isCwdWorkspace(process.cwd());
|
|
42111
|
+
let workspacePath;
|
|
42112
|
+
let directories;
|
|
42113
|
+
if (!opts.path && cwdIsWorkspace) {
|
|
42114
|
+
const resolvedCwd = await resolveCwdWorkspacePath(process.cwd());
|
|
42115
|
+
workspacePath = resolvedCwd ?? path9.join(process.cwd(), ".tostudy");
|
|
42116
|
+
await fs10.mkdir(workspacePath, { recursive: true });
|
|
42117
|
+
directories = ["exercises", "generated", "notes", "diagrams"];
|
|
42118
|
+
for (const dir of directories) {
|
|
42119
|
+
await fs10.mkdir(path9.join(workspacePath, dir), { recursive: true });
|
|
42120
|
+
}
|
|
42121
|
+
const configPath = path9.join(workspacePath, ".ana-config.json");
|
|
42122
|
+
await fs10.writeFile(
|
|
42123
|
+
configPath,
|
|
42124
|
+
JSON.stringify(
|
|
42125
|
+
{
|
|
42126
|
+
courseId: activeCourse.courseId,
|
|
42127
|
+
courseSlug: courseSlug(activeCourse.courseTitle),
|
|
42128
|
+
courseName: activeCourse.courseTitle,
|
|
42129
|
+
workspacePath,
|
|
42130
|
+
locale: "pt-BR",
|
|
42131
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42132
|
+
lastAccessedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
42133
|
+
},
|
|
42134
|
+
null,
|
|
42135
|
+
2
|
|
42136
|
+
),
|
|
42137
|
+
"utf-8"
|
|
42138
|
+
);
|
|
42139
|
+
} else {
|
|
42140
|
+
const basePath = opts.path ?? path9.join(os9.homedir(), "study");
|
|
42141
|
+
const result2 = await setupWorkspace({
|
|
42142
|
+
courseId: activeCourse.courseId,
|
|
42143
|
+
courseSlug: courseSlug(activeCourse.courseTitle),
|
|
42144
|
+
courseName: activeCourse.courseTitle,
|
|
42145
|
+
basePath,
|
|
42146
|
+
locale: "pt-BR"
|
|
42147
|
+
});
|
|
42148
|
+
workspacePath = result2.workspacePath;
|
|
42149
|
+
directories = result2.directories;
|
|
42150
|
+
}
|
|
42151
|
+
await setCourseWorkspacePath(activeCourse.courseId, workspacePath);
|
|
42152
|
+
const result = { workspacePath, directories };
|
|
42075
42153
|
if (opts.json) {
|
|
42076
42154
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
42077
42155
|
} else {
|
|
42078
42156
|
process.stdout.write(
|
|
42079
42157
|
`
|
|
42080
|
-
\u2705 Workspace criado em: ${
|
|
42158
|
+
\u2705 Workspace criado em: ${workspacePath}
|
|
42081
42159
|
|
|
42082
42160
|
Diret\xF3rios:
|
|
42083
|
-
${
|
|
42161
|
+
${directories.map((d) => ` \u{1F4C1} ${d}/`).join("\n")}
|
|
42084
42162
|
|
|
42085
42163
|
Pr\xF3ximo passo: tostudy export
|
|
42086
42164
|
`
|
|
@@ -42093,62 +42171,68 @@ Pr\xF3ximo passo: tostudy export
|
|
|
42093
42171
|
process.exit(1);
|
|
42094
42172
|
}
|
|
42095
42173
|
});
|
|
42096
|
-
workspaceCommand.command("status").description("Mostrar status do workspace do curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
42174
|
+
workspaceCommand.command("status").description("Mostrar status do workspace do curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace", path9.join(os9.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
42097
42175
|
try {
|
|
42098
42176
|
const activeCourse = await requireActiveCourse();
|
|
42099
|
-
const
|
|
42100
|
-
const
|
|
42101
|
-
|
|
42102
|
-
|
|
42103
|
-
|
|
42104
|
-
|
|
42105
|
-
|
|
42177
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42178
|
+
const ws = await resolveEffectiveWorkspace(
|
|
42179
|
+
activeCourse.courseTitle,
|
|
42180
|
+
onboardingState?.workspacePath,
|
|
42181
|
+
process.cwd(),
|
|
42182
|
+
opts.path
|
|
42183
|
+
);
|
|
42184
|
+
if (!ws.found || !ws.workspacePath) {
|
|
42106
42185
|
process.stderr.write(
|
|
42107
42186
|
"\u274C Workspace n\xE3o encontrado. Execute 'tostudy workspace setup' primeiro.\n"
|
|
42108
42187
|
);
|
|
42109
42188
|
process.exit(1);
|
|
42110
42189
|
}
|
|
42111
|
-
const
|
|
42190
|
+
const workspacePath = ws.workspacePath;
|
|
42191
|
+
let configData = null;
|
|
42192
|
+
try {
|
|
42193
|
+
const raw = await fs10.readFile(path9.join(workspacePath, ".ana-config.json"), "utf-8");
|
|
42194
|
+
configData = JSON.parse(raw);
|
|
42195
|
+
} catch {
|
|
42196
|
+
configData = null;
|
|
42197
|
+
}
|
|
42198
|
+
const exercisesDir = path9.join(workspacePath, "exercises");
|
|
42112
42199
|
let exerciseCount = 0;
|
|
42113
42200
|
try {
|
|
42114
|
-
const moduleDirs = await
|
|
42201
|
+
const moduleDirs = await fs10.readdir(exercisesDir);
|
|
42115
42202
|
for (const modDir of moduleDirs) {
|
|
42116
|
-
const modPath =
|
|
42117
|
-
const stat = await
|
|
42203
|
+
const modPath = path9.join(exercisesDir, modDir);
|
|
42204
|
+
const stat = await fs10.stat(modPath);
|
|
42118
42205
|
if (stat.isDirectory()) {
|
|
42119
|
-
const lessonDirs = await
|
|
42206
|
+
const lessonDirs = await fs10.readdir(modPath);
|
|
42120
42207
|
for (const lessonDir of lessonDirs) {
|
|
42121
|
-
const lessonPath =
|
|
42122
|
-
const lstat = await
|
|
42208
|
+
const lessonPath = path9.join(modPath, lessonDir);
|
|
42209
|
+
const lstat = await fs10.stat(lessonPath);
|
|
42123
42210
|
if (lstat.isDirectory()) exerciseCount++;
|
|
42124
42211
|
}
|
|
42125
42212
|
}
|
|
42126
42213
|
}
|
|
42127
42214
|
} catch {
|
|
42128
42215
|
}
|
|
42129
|
-
const generatedDir =
|
|
42216
|
+
const generatedDir = path9.join(workspacePath, "generated");
|
|
42130
42217
|
let artifactCount = 0;
|
|
42131
42218
|
try {
|
|
42132
|
-
const files = await
|
|
42219
|
+
const files = await fs10.readdir(generatedDir);
|
|
42133
42220
|
artifactCount = files.length;
|
|
42134
42221
|
} catch {
|
|
42135
42222
|
}
|
|
42136
|
-
const diagramsDir =
|
|
42223
|
+
const diagramsDir = path9.join(workspacePath, "diagrams");
|
|
42137
42224
|
let diagramCount = 0;
|
|
42138
42225
|
try {
|
|
42139
|
-
const files = await
|
|
42226
|
+
const files = await fs10.readdir(diagramsDir);
|
|
42140
42227
|
diagramCount = files.length;
|
|
42141
42228
|
} catch {
|
|
42142
42229
|
}
|
|
42143
|
-
const
|
|
42144
|
-
|
|
42145
|
-
|
|
42146
|
-
await fs11.access(path10.join(vaultDir, ".ana-vault.json"));
|
|
42147
|
-
hasVault = true;
|
|
42148
|
-
} catch {
|
|
42149
|
-
}
|
|
42230
|
+
const slug = courseSlug(activeCourse.courseTitle);
|
|
42231
|
+
const foundVaultPath = await findExistingVault(workspacePath, slug);
|
|
42232
|
+
const hasVault = foundVaultPath !== null;
|
|
42150
42233
|
const status = {
|
|
42151
42234
|
workspacePath,
|
|
42235
|
+
workspaceSource: ws.source,
|
|
42152
42236
|
course: activeCourse.courseTitle,
|
|
42153
42237
|
courseId: activeCourse.courseId,
|
|
42154
42238
|
exercisesExtracted: exerciseCount,
|
|
@@ -42160,11 +42244,12 @@ Pr\xF3ximo passo: tostudy export
|
|
|
42160
42244
|
if (opts.json) {
|
|
42161
42245
|
process.stdout.write(JSON.stringify(status, null, 2) + "\n");
|
|
42162
42246
|
} else {
|
|
42247
|
+
const sourceLabel = ws.source === "cwd" ? " (pasta atual)" : ws.source === "stored" ? " (configurado)" : ws.source === "default" ? " (~/study/)" : "";
|
|
42163
42248
|
process.stdout.write(
|
|
42164
42249
|
[
|
|
42165
42250
|
"",
|
|
42166
42251
|
`\u{1F4DA} **${activeCourse.courseTitle}**`,
|
|
42167
|
-
`\u{1F4C1} ${workspacePath}`,
|
|
42252
|
+
`\u{1F4C1} ${workspacePath}${sourceLabel}`,
|
|
42168
42253
|
"",
|
|
42169
42254
|
` Exerc\xEDcios extra\xEDdos: ${exerciseCount}`,
|
|
42170
42255
|
` Artefatos exportados: ${artifactCount}`,
|
|
@@ -42187,8 +42272,9 @@ Pr\xF3ximo passo: tostudy export
|
|
|
42187
42272
|
|
|
42188
42273
|
// src/commands/export.ts
|
|
42189
42274
|
import { Command as Command17 } from "commander";
|
|
42190
|
-
import
|
|
42191
|
-
import
|
|
42275
|
+
import path10 from "node:path";
|
|
42276
|
+
import os10 from "node:os";
|
|
42277
|
+
import fs11 from "node:fs/promises";
|
|
42192
42278
|
var logger15, exportCommand;
|
|
42193
42279
|
var init_export = __esm({
|
|
42194
42280
|
"src/commands/export.ts"() {
|
|
@@ -42199,7 +42285,7 @@ var init_export = __esm({
|
|
|
42199
42285
|
init_session();
|
|
42200
42286
|
init_resolve();
|
|
42201
42287
|
logger15 = createLogger("cli:export");
|
|
42202
|
-
exportCommand = new Command17("export").description("Extrair exerc\xEDcio atual para o workspace local").option("--tier <tier>", "Tier do exerc\xEDcio: guided, semiGuided, challenging", "guided").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
42288
|
+
exportCommand = new Command17("export").description("Extrair exerc\xEDcio atual para o workspace local").option("--tier <tier>", "Tier do exerc\xEDcio: guided, semiGuided, challenging", "guided").option("--path <dir>", "Diret\xF3rio base do workspace", path10.join(os10.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
42203
42289
|
try {
|
|
42204
42290
|
const session = await requireSession();
|
|
42205
42291
|
const activeCourse = await requireActiveCourse();
|
|
@@ -42209,10 +42295,57 @@ var init_export = __esm({
|
|
|
42209
42295
|
process.stderr.write("\u274C Nenhuma li\xE7\xE3o ativa. Execute 'tostudy start' primeiro.\n");
|
|
42210
42296
|
process.exit(1);
|
|
42211
42297
|
}
|
|
42212
|
-
const
|
|
42213
|
-
|
|
42298
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42299
|
+
const ws = await resolveEffectiveWorkspace(
|
|
42300
|
+
activeCourse.courseTitle,
|
|
42301
|
+
onboardingState?.workspacePath,
|
|
42302
|
+
process.cwd(),
|
|
42303
|
+
opts.path
|
|
42304
|
+
);
|
|
42305
|
+
if (ws.found && ws.source === "cwd" && ws.workspacePath) {
|
|
42306
|
+
const configPath = path10.join(ws.workspacePath, ".ana-config.json");
|
|
42307
|
+
let hasConfig = false;
|
|
42308
|
+
try {
|
|
42309
|
+
await fs11.access(configPath);
|
|
42310
|
+
hasConfig = true;
|
|
42311
|
+
} catch {
|
|
42312
|
+
}
|
|
42313
|
+
if (!hasConfig) {
|
|
42314
|
+
const slug = courseSlug(activeCourse.courseTitle);
|
|
42315
|
+
logger15.info("Auto-initializing workspace", { workspacePath: ws.workspacePath });
|
|
42316
|
+
await fs11.mkdir(ws.workspacePath, { recursive: true });
|
|
42317
|
+
for (const dir of ["exercises", "generated", "notes", "diagrams"]) {
|
|
42318
|
+
await fs11.mkdir(path10.join(ws.workspacePath, dir), { recursive: true });
|
|
42319
|
+
}
|
|
42320
|
+
await fs11.writeFile(
|
|
42321
|
+
configPath,
|
|
42322
|
+
JSON.stringify(
|
|
42323
|
+
{
|
|
42324
|
+
courseId: activeCourse.courseId,
|
|
42325
|
+
courseSlug: slug,
|
|
42326
|
+
courseName: activeCourse.courseTitle,
|
|
42327
|
+
workspacePath: ws.workspacePath,
|
|
42328
|
+
locale: "pt-BR",
|
|
42329
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42330
|
+
lastAccessedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
42331
|
+
},
|
|
42332
|
+
null,
|
|
42333
|
+
2
|
|
42334
|
+
),
|
|
42335
|
+
"utf-8"
|
|
42336
|
+
);
|
|
42337
|
+
await setCourseWorkspacePath(activeCourse.courseId, ws.workspacePath);
|
|
42338
|
+
const isNamespaced = ws.workspacePath === path10.join(process.cwd(), ".tostudy");
|
|
42339
|
+
process.stderr.write(
|
|
42340
|
+
isNamespaced ? `\u2728 Workspace inicializado em .tostudy/ (isolado do projeto).
|
|
42341
|
+
` : `\u2728 Workspace inicializado nesta pasta.
|
|
42342
|
+
`
|
|
42343
|
+
);
|
|
42344
|
+
}
|
|
42345
|
+
}
|
|
42346
|
+
if (!ws.found || !ws.workspacePath) {
|
|
42214
42347
|
process.stderr.write(
|
|
42215
|
-
"\u274C Workspace n\xE3o encontrado. Execute 'tostudy workspace setup'
|
|
42348
|
+
"\u274C Workspace n\xE3o encontrado. Execute 'tostudy workspace setup' ou rode 'tostudy select' desta pasta.\n"
|
|
42216
42349
|
);
|
|
42217
42350
|
process.exit(1);
|
|
42218
42351
|
}
|
|
@@ -42255,45 +42388,41 @@ ${result.files.map((f) => ` \u{1F4C4} ${f}`).join("\n")}
|
|
|
42255
42388
|
// src/commands/open.ts
|
|
42256
42389
|
import { Command as Command18 } from "commander";
|
|
42257
42390
|
import { execFile as execFile3 } from "node:child_process";
|
|
42258
|
-
import
|
|
42259
|
-
import
|
|
42260
|
-
import os9 from "node:os";
|
|
42261
|
-
async function findWorkspacePath(courseTitle, basePath) {
|
|
42262
|
-
const slug = courseTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
42263
|
-
const candidate = path12.join(basePath, slug);
|
|
42264
|
-
try {
|
|
42265
|
-
await fs12.access(path12.join(candidate, ".ana-config.json"));
|
|
42266
|
-
return candidate;
|
|
42267
|
-
} catch {
|
|
42268
|
-
return null;
|
|
42269
|
-
}
|
|
42270
|
-
}
|
|
42391
|
+
import path11 from "node:path";
|
|
42392
|
+
import os11 from "node:os";
|
|
42271
42393
|
var logger16, openCommand;
|
|
42272
42394
|
var init_open = __esm({
|
|
42273
42395
|
"src/commands/open.ts"() {
|
|
42274
42396
|
"use strict";
|
|
42275
42397
|
init_src();
|
|
42276
42398
|
init_session();
|
|
42399
|
+
init_resolve();
|
|
42277
42400
|
logger16 = createLogger("cli:open");
|
|
42278
|
-
openCommand = new Command18("open").description("Abrir workspace do curso na IDE").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
42401
|
+
openCommand = new Command18("open").description("Abrir workspace do curso na IDE").option("--path <dir>", "Diret\xF3rio base do workspace", path11.join(os11.homedir(), "study")).action(async (opts) => {
|
|
42279
42402
|
try {
|
|
42280
42403
|
const activeCourse = await requireActiveCourse();
|
|
42281
|
-
const
|
|
42282
|
-
|
|
42404
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42405
|
+
const ws = await resolveEffectiveWorkspace(
|
|
42406
|
+
activeCourse.courseTitle,
|
|
42407
|
+
onboardingState?.workspacePath,
|
|
42408
|
+
process.cwd(),
|
|
42409
|
+
opts.path
|
|
42410
|
+
);
|
|
42411
|
+
if (!ws.found || !ws.workspacePath) {
|
|
42283
42412
|
process.stderr.write(
|
|
42284
42413
|
"\u274C Workspace n\xE3o encontrado. Execute 'tostudy workspace setup' primeiro.\n"
|
|
42285
42414
|
);
|
|
42286
42415
|
process.exit(1);
|
|
42287
42416
|
}
|
|
42288
42417
|
const editor = process.env["EDITOR"] ?? "code";
|
|
42289
|
-
execFile3(editor, [workspacePath], (err) => {
|
|
42418
|
+
execFile3(editor, [ws.workspacePath], (err) => {
|
|
42290
42419
|
if (err) {
|
|
42291
|
-
logger16.error("open failed", { editor, workspacePath });
|
|
42420
|
+
logger16.error("open failed", { editor, workspacePath: ws.workspacePath });
|
|
42292
42421
|
process.stderr.write(`\u274C Falha ao abrir: ${err.message}
|
|
42293
42422
|
`);
|
|
42294
42423
|
process.exit(1);
|
|
42295
42424
|
}
|
|
42296
|
-
process.stdout.write(`\u2705 Aberto em ${editor}: ${workspacePath}
|
|
42425
|
+
process.stdout.write(`\u2705 Aberto em ${editor}: ${ws.workspacePath}
|
|
42297
42426
|
`);
|
|
42298
42427
|
});
|
|
42299
42428
|
} catch (err) {
|
|
@@ -42324,24 +42453,24 @@ var init_types3 = __esm({
|
|
|
42324
42453
|
});
|
|
42325
42454
|
|
|
42326
42455
|
// ../../packages/tostudy-core/src/vault/write-vault.ts
|
|
42327
|
-
import
|
|
42328
|
-
import
|
|
42456
|
+
import fs12 from "node:fs/promises";
|
|
42457
|
+
import path12 from "node:path";
|
|
42329
42458
|
async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
|
|
42330
42459
|
for (const file2 of files) {
|
|
42331
|
-
const fullPath =
|
|
42332
|
-
await
|
|
42333
|
-
await
|
|
42460
|
+
const fullPath = path12.join(outputPath, file2.relativePath);
|
|
42461
|
+
await fs12.mkdir(path12.dirname(fullPath), { recursive: true });
|
|
42462
|
+
await fs12.writeFile(fullPath, file2.content, "utf-8");
|
|
42334
42463
|
}
|
|
42335
|
-
const vaultPath =
|
|
42464
|
+
const vaultPath = path12.join(outputPath, courseSlug2);
|
|
42336
42465
|
const marker = {
|
|
42337
42466
|
courseId,
|
|
42338
42467
|
courseSlug: courseSlug2,
|
|
42339
42468
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42340
42469
|
version: VAULT_MARKER_VERSION
|
|
42341
42470
|
};
|
|
42342
|
-
await
|
|
42343
|
-
await
|
|
42344
|
-
|
|
42471
|
+
await fs12.mkdir(vaultPath, { recursive: true });
|
|
42472
|
+
await fs12.writeFile(
|
|
42473
|
+
path12.join(vaultPath, VAULT_MARKER_FILENAME),
|
|
42345
42474
|
JSON.stringify(marker, null, 2),
|
|
42346
42475
|
"utf-8"
|
|
42347
42476
|
);
|
|
@@ -42366,9 +42495,9 @@ var init_vault = __esm({
|
|
|
42366
42495
|
|
|
42367
42496
|
// src/commands/vault.ts
|
|
42368
42497
|
import { Command as Command19 } from "commander";
|
|
42369
|
-
import
|
|
42370
|
-
import
|
|
42371
|
-
import
|
|
42498
|
+
import path13 from "node:path";
|
|
42499
|
+
import os12 from "node:os";
|
|
42500
|
+
import fs13 from "node:fs/promises";
|
|
42372
42501
|
var logger17, vaultCommand;
|
|
42373
42502
|
var init_vault2 = __esm({
|
|
42374
42503
|
"src/commands/vault.ts"() {
|
|
@@ -42378,17 +42507,31 @@ var init_vault2 = __esm({
|
|
|
42378
42507
|
init_courses();
|
|
42379
42508
|
init_http2();
|
|
42380
42509
|
init_session();
|
|
42510
|
+
init_resolve();
|
|
42381
42511
|
logger17 = createLogger("cli:vault");
|
|
42382
42512
|
vaultCommand = new Command19("vault").description("Gerenciar vault Obsidian do curso");
|
|
42383
|
-
vaultCommand.command("init").description("Gerar vault Obsidian para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
42513
|
+
vaultCommand.command("init").description("Gerar vault Obsidian para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace", path13.join(os12.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
42384
42514
|
try {
|
|
42385
42515
|
const session = await requireSession();
|
|
42386
42516
|
const activeCourse = await requireActiveCourse();
|
|
42387
42517
|
const driftWarning = await checkCourseDrift();
|
|
42388
42518
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
42389
|
-
const
|
|
42390
|
-
const
|
|
42391
|
-
|
|
42519
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42520
|
+
const ws = await resolveEffectiveWorkspace(
|
|
42521
|
+
activeCourse.courseTitle,
|
|
42522
|
+
onboardingState?.workspacePath,
|
|
42523
|
+
process.cwd(),
|
|
42524
|
+
opts.path
|
|
42525
|
+
);
|
|
42526
|
+
if (!ws.found || !ws.workspacePath) {
|
|
42527
|
+
process.stderr.write(
|
|
42528
|
+
"\u274C Workspace n\xE3o encontrado. Execute 'tostudy workspace setup' primeiro.\n"
|
|
42529
|
+
);
|
|
42530
|
+
process.exit(1);
|
|
42531
|
+
}
|
|
42532
|
+
const slug = courseSlug(activeCourse.courseTitle);
|
|
42533
|
+
const workspacePath = ws.workspacePath;
|
|
42534
|
+
const vaultOutputPath = resolveVaultPath(workspacePath, slug);
|
|
42392
42535
|
const res = await fetch(`${session.apiUrl}/api/cli/vault/init`, {
|
|
42393
42536
|
method: "POST",
|
|
42394
42537
|
headers: {
|
|
@@ -42410,7 +42553,7 @@ var init_vault2 = __esm({
|
|
|
42410
42553
|
data.files,
|
|
42411
42554
|
vaultOutputPath,
|
|
42412
42555
|
activeCourse.courseId,
|
|
42413
|
-
|
|
42556
|
+
slug
|
|
42414
42557
|
);
|
|
42415
42558
|
logger17.info("Vault generated", {
|
|
42416
42559
|
courseId: activeCourse.courseId,
|
|
@@ -42451,25 +42594,36 @@ Para visualizar:
|
|
|
42451
42594
|
process.exit(1);
|
|
42452
42595
|
}
|
|
42453
42596
|
});
|
|
42454
|
-
vaultCommand.command("sync").description("Sincronizar progresso do curso com o vault local").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
42597
|
+
vaultCommand.command("sync").description("Sincronizar progresso do curso com o vault local").option("--path <dir>", "Diret\xF3rio base do workspace", path13.join(os12.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
42455
42598
|
try {
|
|
42456
42599
|
const session = await requireSession();
|
|
42457
42600
|
const activeCourse = await requireActiveCourse();
|
|
42458
42601
|
const driftWarning = await checkCourseDrift();
|
|
42459
42602
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
42460
|
-
const
|
|
42461
|
-
const
|
|
42462
|
-
|
|
42463
|
-
|
|
42464
|
-
|
|
42603
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42604
|
+
const ws = await resolveEffectiveWorkspace(
|
|
42605
|
+
activeCourse.courseTitle,
|
|
42606
|
+
onboardingState?.workspacePath,
|
|
42607
|
+
process.cwd(),
|
|
42608
|
+
opts.path
|
|
42609
|
+
);
|
|
42610
|
+
if (!ws.found || !ws.workspacePath) {
|
|
42611
|
+
process.stderr.write(
|
|
42612
|
+
"\u274C Workspace n\xE3o encontrado. Execute 'tostudy workspace setup' primeiro.\n"
|
|
42613
|
+
);
|
|
42614
|
+
process.exit(1);
|
|
42615
|
+
}
|
|
42616
|
+
const slug = courseSlug(activeCourse.courseTitle);
|
|
42617
|
+
const vaultPath = await findExistingVault(ws.workspacePath, slug);
|
|
42618
|
+
if (!vaultPath) {
|
|
42465
42619
|
process.stderr.write("\u274C Vault n\xE3o encontrado. Execute 'tostudy vault init' primeiro.\n");
|
|
42466
42620
|
process.exit(1);
|
|
42467
42621
|
}
|
|
42468
42622
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
42469
42623
|
const deps = { data, logger: logger17 };
|
|
42470
42624
|
const progress3 = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
42471
|
-
const markerPath =
|
|
42472
|
-
const markerRaw = await
|
|
42625
|
+
const markerPath = path13.join(vaultPath, ".ana-vault.json");
|
|
42626
|
+
const markerRaw = await fs13.readFile(markerPath, "utf-8");
|
|
42473
42627
|
const marker = JSON.parse(markerRaw);
|
|
42474
42628
|
marker.lastSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
42475
42629
|
marker.progress = {
|
|
@@ -42477,10 +42631,10 @@ Para visualizar:
|
|
|
42477
42631
|
currentModule: progress3.currentModule.title,
|
|
42478
42632
|
currentLesson: progress3.currentLesson.title
|
|
42479
42633
|
};
|
|
42480
|
-
await
|
|
42481
|
-
const courseIndexPath =
|
|
42634
|
+
await fs13.writeFile(markerPath, JSON.stringify(marker, null, 2), "utf-8");
|
|
42635
|
+
const courseIndexPath = path13.join(vaultPath, slug, "index.md");
|
|
42482
42636
|
try {
|
|
42483
|
-
let indexContent = await
|
|
42637
|
+
let indexContent = await fs13.readFile(courseIndexPath, "utf-8");
|
|
42484
42638
|
indexContent = indexContent.replace(/\n---\n\n> 📊 Progresso:.*\n/g, "");
|
|
42485
42639
|
const titleEnd = indexContent.indexOf("\n");
|
|
42486
42640
|
if (titleEnd !== -1) {
|
|
@@ -42491,7 +42645,7 @@ Para visualizar:
|
|
|
42491
42645
|
`;
|
|
42492
42646
|
indexContent = indexContent.slice(0, titleEnd) + banner + indexContent.slice(titleEnd);
|
|
42493
42647
|
}
|
|
42494
|
-
await
|
|
42648
|
+
await fs13.writeFile(courseIndexPath, indexContent, "utf-8");
|
|
42495
42649
|
} catch {
|
|
42496
42650
|
}
|
|
42497
42651
|
const syncedAt = marker.lastSyncedAt;
|
|
@@ -42596,15 +42750,85 @@ var init_profile = __esm({
|
|
|
42596
42750
|
}
|
|
42597
42751
|
});
|
|
42598
42752
|
|
|
42753
|
+
// src/commands/sync.ts
|
|
42754
|
+
import { Command as Command21 } from "commander";
|
|
42755
|
+
var logger18, syncCommand;
|
|
42756
|
+
var init_sync = __esm({
|
|
42757
|
+
"src/commands/sync.ts"() {
|
|
42758
|
+
"use strict";
|
|
42759
|
+
init_src();
|
|
42760
|
+
init_courses();
|
|
42761
|
+
init_http2();
|
|
42762
|
+
init_session();
|
|
42763
|
+
init_formatter();
|
|
42764
|
+
init_instruction_files();
|
|
42765
|
+
init_status();
|
|
42766
|
+
logger18 = createLogger("cli:sync");
|
|
42767
|
+
syncCommand = new Command21("sync").description("Regenerate instruction files with updated progress").option("--json", "Output structured JSON").action(async (opts) => {
|
|
42768
|
+
try {
|
|
42769
|
+
const session = await requireSession();
|
|
42770
|
+
const activeCourse = await requireActiveCourse();
|
|
42771
|
+
const data = createHttpProvider(session.apiUrl, session.token);
|
|
42772
|
+
const deps = { data, logger: logger18 };
|
|
42773
|
+
const [courses3, progressData] = await Promise.all([
|
|
42774
|
+
listCourses({ userId: session.userId }, deps),
|
|
42775
|
+
getProgress({ enrollmentId: activeCourse.enrollmentId }, deps).catch(() => null)
|
|
42776
|
+
]);
|
|
42777
|
+
const matchedCourse = courses3.find((c) => c.courseId === activeCourse.courseId);
|
|
42778
|
+
if (!matchedCourse) {
|
|
42779
|
+
error("Curso ativo n\xE3o encontrado. Rode `tostudy courses` para verificar.");
|
|
42780
|
+
}
|
|
42781
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42782
|
+
const onboarding = await getCourseOnboardingStatus(activeCourse);
|
|
42783
|
+
const slug = generateInstructionFiles(
|
|
42784
|
+
{
|
|
42785
|
+
courseTitle: matchedCourse.title,
|
|
42786
|
+
courseId: activeCourse.courseId,
|
|
42787
|
+
progress: progressData?.coursePercent ?? matchedCourse.progress ?? 0,
|
|
42788
|
+
moduleCount: progressData?.currentModule?.totalModules ?? 0,
|
|
42789
|
+
lessonCount: progressData?.currentLesson?.totalLessons ?? 0,
|
|
42790
|
+
currentModuleTitle: progressData?.currentModule?.title,
|
|
42791
|
+
currentLessonTitle: progressData?.currentLesson?.title,
|
|
42792
|
+
courseDescription: matchedCourse.description ?? void 0,
|
|
42793
|
+
workspaceReady: onboarding.workspaceReady,
|
|
42794
|
+
workspacePath: onboarding.workspacePath ?? void 0
|
|
42795
|
+
},
|
|
42796
|
+
onboardingState?.learnerProfile
|
|
42797
|
+
);
|
|
42798
|
+
if (opts.json) {
|
|
42799
|
+
output(
|
|
42800
|
+
{
|
|
42801
|
+
status: "ok",
|
|
42802
|
+
courseId: activeCourse.courseId,
|
|
42803
|
+
slug,
|
|
42804
|
+
progress: progressData?.coursePercent ?? matchedCourse.progress ?? 0
|
|
42805
|
+
},
|
|
42806
|
+
{ json: true }
|
|
42807
|
+
);
|
|
42808
|
+
} else {
|
|
42809
|
+
const progress3 = progressData?.coursePercent ?? matchedCourse.progress ?? 0;
|
|
42810
|
+
output(`\u2713 Instru\xE7\xF5es sincronizadas para "${matchedCourse.title}" (${progress3}%)`, {
|
|
42811
|
+
json: false
|
|
42812
|
+
});
|
|
42813
|
+
}
|
|
42814
|
+
} catch (err) {
|
|
42815
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
42816
|
+
if (msg.includes("process.exit")) return;
|
|
42817
|
+
error(msg);
|
|
42818
|
+
}
|
|
42819
|
+
});
|
|
42820
|
+
}
|
|
42821
|
+
});
|
|
42822
|
+
|
|
42599
42823
|
// src/cli.ts
|
|
42600
42824
|
var cli_exports = {};
|
|
42601
42825
|
__export(cli_exports, {
|
|
42602
42826
|
CLI_VERSION: () => CLI_VERSION,
|
|
42603
42827
|
createProgram: () => createProgram
|
|
42604
42828
|
});
|
|
42605
|
-
import { Command as
|
|
42829
|
+
import { Command as Command22 } from "commander";
|
|
42606
42830
|
function createProgram() {
|
|
42607
|
-
const program2 = new
|
|
42831
|
+
const program2 = new Command22();
|
|
42608
42832
|
program2.name("tostudy").description("ToStudy CLI \u2014 study courses from the terminal").version(CLI_VERSION).option("--verbose", "Enable debug output").option("--course <id>", "Override active course ID");
|
|
42609
42833
|
program2.addCommand(setupCommand);
|
|
42610
42834
|
program2.addCommand(doctorCommand);
|
|
@@ -42623,6 +42847,7 @@ function createProgram() {
|
|
|
42623
42847
|
program2.addCommand(menuCommand);
|
|
42624
42848
|
program2.addCommand(profileCommand);
|
|
42625
42849
|
program2.addCommand(workspaceCommand);
|
|
42850
|
+
program2.addCommand(syncCommand);
|
|
42626
42851
|
program2.addCommand(exportCommand);
|
|
42627
42852
|
program2.addCommand(openCommand);
|
|
42628
42853
|
program2.addCommand(vaultCommand);
|
|
@@ -42652,7 +42877,8 @@ var init_cli = __esm({
|
|
|
42652
42877
|
init_open();
|
|
42653
42878
|
init_vault2();
|
|
42654
42879
|
init_profile();
|
|
42655
|
-
|
|
42880
|
+
init_sync();
|
|
42881
|
+
CLI_VERSION = true ? "0.8.0" : "0.7.1";
|
|
42656
42882
|
}
|
|
42657
42883
|
});
|
|
42658
42884
|
|