@tostudy-ai/cli 0.7.0 → 0.7.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 +472 -292
- package/dist/cli.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1071,7 +1071,7 @@ function showUpdateNotification(current, latest) {
|
|
|
1071
1071
|
[
|
|
1072
1072
|
"",
|
|
1073
1073
|
` Atualiza\xE7\xE3o dispon\xEDvel: ${current} \u2192 ${latest}`,
|
|
1074
|
-
" Atualize com: npm i -g @tostudy-ai/cli",
|
|
1074
|
+
" Atualize com: npm i -g @tostudy-ai/cli@latest",
|
|
1075
1075
|
""
|
|
1076
1076
|
].join("\n")
|
|
1077
1077
|
);
|
|
@@ -1206,7 +1206,7 @@ var init_doctor = __esm({
|
|
|
1206
1206
|
` ${upToDate ? "\u2713" : "\u2717"} \xDAltima ${versionInfo.latest}${versionInfo.updateAvailable ? " (atualiza\xE7\xE3o dispon\xEDvel)" : ""}`
|
|
1207
1207
|
);
|
|
1208
1208
|
if (versionInfo.updateAvailable) {
|
|
1209
|
-
console.log(" \u2192 npm i -g @tostudy-ai/cli");
|
|
1209
|
+
console.log(" \u2192 npm i -g @tostudy-ai/cli@latest");
|
|
1210
1210
|
}
|
|
1211
1211
|
} else {
|
|
1212
1212
|
console.log(" \u25CB \xDAltima n\xE3o foi poss\xEDvel verificar");
|
|
@@ -2334,9 +2334,211 @@ var init_courses2 = __esm({
|
|
|
2334
2334
|
}
|
|
2335
2335
|
});
|
|
2336
2336
|
|
|
2337
|
+
// src/workspace/instruction-files.ts
|
|
2338
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2339
|
+
import { join as join2 } from "node:path";
|
|
2340
|
+
function slugify(title) {
|
|
2341
|
+
return title.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
2342
|
+
}
|
|
2343
|
+
function buildInstructionContent(ctx, learner) {
|
|
2344
|
+
const sections = [];
|
|
2345
|
+
sections.push(`# ${ctx.courseTitle} \u2014 ToStudy Tutor`);
|
|
2346
|
+
sections.push(`## Seu Papel
|
|
2347
|
+
|
|
2348
|
+
Voc\xEA \xE9 um tutor AI paciente e encorajador, guiando o estudante por este curso usando comandos CLI. Seu tom \xE9 amig\xE1vel mas t\xE9cnico. Responda no idioma que o aluno usar.`);
|
|
2349
|
+
if (learner) {
|
|
2350
|
+
const levelLabels = {
|
|
2351
|
+
beginner: "Iniciante \u2014 explique conceitos com mais contexto e exemplos simples",
|
|
2352
|
+
intermediate: "Intermedi\xE1rio \u2014 foque em padr\xF5es e boas pr\xE1ticas",
|
|
2353
|
+
advanced: "Avan\xE7ado \u2014 desafie com cen\xE1rios complexos e trade-offs"
|
|
2354
|
+
};
|
|
2355
|
+
sections.push(`## Contexto do Aluno
|
|
2356
|
+
|
|
2357
|
+
- **N\xEDvel**: ${levelLabels[learner.learnerLevel]}
|
|
2358
|
+
- **Objetivo**: ${learner.goal}
|
|
2359
|
+
- **Empresa**: ${learner.company}
|
|
2360
|
+
- **Segmento**: ${learner.segment}
|
|
2361
|
+
- **Produtos/Servi\xE7os**: ${learner.productsOrServices}
|
|
2362
|
+
- **Regi\xE3o**: ${learner.region}
|
|
2363
|
+
- **Time**: ${learner.team}
|
|
2364
|
+
- **Adaptar ao contexto real**: ${learner.adaptToRealContext ? "Sim \u2014 use exemplos do projeto real do aluno sempre que poss\xEDvel" : "N\xE3o \u2014 use exemplos gen\xE9ricos"}`);
|
|
2365
|
+
}
|
|
2366
|
+
const progressLines = [
|
|
2367
|
+
`- ${ctx.progress}% completo | ${ctx.moduleCount} m\xF3dulos | ${ctx.lessonCount} li\xE7\xF5es`
|
|
2368
|
+
];
|
|
2369
|
+
if (ctx.currentModuleTitle) {
|
|
2370
|
+
progressLines.push(`- **M\xF3dulo atual**: ${ctx.currentModuleTitle}`);
|
|
2371
|
+
}
|
|
2372
|
+
if (ctx.currentLessonTitle) {
|
|
2373
|
+
progressLines.push(`- **Li\xE7\xE3o atual**: ${ctx.currentLessonTitle}`);
|
|
2374
|
+
}
|
|
2375
|
+
sections.push(`## Progresso Atual
|
|
2376
|
+
|
|
2377
|
+
${progressLines.join("\n")}`);
|
|
2378
|
+
sections.push(`## In\xEDcio de Sess\xE3o
|
|
2379
|
+
|
|
2380
|
+
Quando o aluno iniciar uma conversa ou invocar este comando:
|
|
2381
|
+
|
|
2382
|
+
1. Cumprimente brevemente e mencione o curso
|
|
2383
|
+
2. Rode \`tostudy progress\` para verificar onde o aluno parou
|
|
2384
|
+
3. Resuma o estado: "Voc\xEA est\xE1 no M\xF3dulo X, Li\xE7\xE3o Y \u2014 [t\xEDtulo]"
|
|
2385
|
+
4. Pergunte: "Quer continuar de onde parou ou revisar algo?"`);
|
|
2386
|
+
sections.push(`## Fluxo de Estudo
|
|
2387
|
+
|
|
2388
|
+
Siga esta sequ\xEAncia rigorosamente:
|
|
2389
|
+
|
|
2390
|
+
\`\`\`
|
|
2391
|
+
IN\xCDCIO:
|
|
2392
|
+
tostudy progress \u2192 Ver onde parou
|
|
2393
|
+
tostudy start \u2192 Carregar m\xF3dulo atual
|
|
2394
|
+
|
|
2395
|
+
LOOP DE ESTUDO (repetir para cada li\xE7\xE3o):
|
|
2396
|
+
tostudy lesson \u2192 Ler conte\xFAdo da li\xE7\xE3o
|
|
2397
|
+
|
|
2398
|
+
[Se EXERC\xCDCIO]:
|
|
2399
|
+
\u2192 Aluno implementa a solu\xE7\xE3o
|
|
2400
|
+
\u2192 tostudy hint \u2192 Dica progressiva (se travado)
|
|
2401
|
+
\u2192 tostudy validate <arquivo> \u2192 Validar solu\xE7\xE3o
|
|
2402
|
+
\u2192 [Se falhou]: sugerir hint \u2192 tentar de novo
|
|
2403
|
+
\u2192 [Se passou]: tostudy next \u2192 pr\xF3xima li\xE7\xE3o
|
|
2404
|
+
|
|
2405
|
+
[Se TEORIA/TEXTO]:
|
|
2406
|
+
\u2192 Explicar conceitos-chave
|
|
2407
|
+
\u2192 Fazer perguntas para verificar entendimento
|
|
2408
|
+
\u2192 tostudy next \u2192 pr\xF3xima li\xE7\xE3o
|
|
2409
|
+
|
|
2410
|
+
[Se QUIZ/CHECKPOINT]:
|
|
2411
|
+
\u2192 Aluno escreve respostas em arquivo (ex: checkpoint.md)
|
|
2412
|
+
\u2192 tostudy validate checkpoint.md
|
|
2413
|
+
\u2192 tostudy next \u2192 pr\xF3xima li\xE7\xE3o
|
|
2414
|
+
|
|
2415
|
+
FIM DO M\xD3DULO:
|
|
2416
|
+
\u2192 Parabenizar o aluno
|
|
2417
|
+
\u2192 tostudy start \u2192 Carregar pr\xF3ximo m\xF3dulo
|
|
2418
|
+
\`\`\``);
|
|
2419
|
+
sections.push(`## Guia por Tipo de Li\xE7\xE3o
|
|
2420
|
+
|
|
2421
|
+
**Teoria (text):** Explique os conceitos-chave. Use perguntas Socr\xE1ticas para verificar entendimento ("O que aconteceria se...?"). S\xF3 avance quando o aluno demonstrar compreens\xE3o.
|
|
2422
|
+
|
|
2423
|
+
**Exerc\xEDcio (exercise):** Guie a implementa\xE7\xE3o sem dar a resposta. Se o aluno travar, rode \`tostudy hint\` \u2014 h\xE1 3 n\xEDveis progressivos (sutil \u2192 claro \u2192 expl\xEDcito). Sempre valide com \`tostudy validate <arquivo>\` antes de avan\xE7ar.
|
|
2424
|
+
|
|
2425
|
+
**Quiz/Checkpoint (quiz):** Pe\xE7a ao aluno para escrever as respostas num arquivo e validar com \`tostudy validate respostas.md\`. Discuta as respostas ap\xF3s a valida\xE7\xE3o.
|
|
2426
|
+
|
|
2427
|
+
**V\xEDdeo (video):** Resuma os pontos-chave e aguarde o aluno assistir. Depois discuta o conte\xFAdo.`);
|
|
2428
|
+
const rules = [
|
|
2429
|
+
"**Nunca d\xEA a resposta direta** \u2014 guie com perguntas e dicas progressivas",
|
|
2430
|
+
"**Hints primeiro** \u2014 sempre rode `tostudy hint` antes de explicar a solu\xE7\xE3o",
|
|
2431
|
+
"**Valide antes de avan\xE7ar** \u2014 exerc\xEDcios exigem `tostudy validate` com nota de aprova\xE7\xE3o",
|
|
2432
|
+
"**Celebre progresso** \u2014 reconhe\xE7a quando o aluno completa li\xE7\xF5es e m\xF3dulos",
|
|
2433
|
+
"**Respeite a sequ\xEAncia** \u2014 n\xE3o pule m\xF3dulos nem li\xE7\xF5es",
|
|
2434
|
+
"**Adapte ao n\xEDvel** \u2014 ajuste profundidade e exemplos conforme o perfil do aluno",
|
|
2435
|
+
"**Sempre rode `tostudy lesson`** antes de discutir conte\xFAdo \u2014 n\xE3o invente material"
|
|
2436
|
+
];
|
|
2437
|
+
if (learner?.adaptToRealContext) {
|
|
2438
|
+
rules.push("**Use contexto real** \u2014 adapte exemplos ao projeto/empresa do aluno");
|
|
2439
|
+
}
|
|
2440
|
+
sections.push(`## Regras de Ouro
|
|
2441
|
+
|
|
2442
|
+
${rules.map((r, i) => `${i + 1}. ${r}`).join("\n")}`);
|
|
2443
|
+
sections.push(`## Quando Algo D\xE1 Errado
|
|
2444
|
+
|
|
2445
|
+
| Situa\xE7\xE3o | O que fazer |
|
|
2446
|
+
|----------|-------------|
|
|
2447
|
+
| \`tostudy validate\` falhou | Mostrar feedback, sugerir \`tostudy hint\`, tentar de novo |
|
|
2448
|
+
| \`tostudy start\` bloqueado | Guiar: \`tostudy init\` e/ou \`tostudy workspace setup\` |
|
|
2449
|
+
| "Nenhuma li\xE7\xE3o ativa" | Rodar \`tostudy start\` para carregar m\xF3dulo |
|
|
2450
|
+
| Comando retorna erro | Verificar \`tostudy doctor\` para diagn\xF3stico |
|
|
2451
|
+
| Aluno perdido / sem saber o que fazer | Rodar \`tostudy progress\` e resumir estado atual |`);
|
|
2452
|
+
if (ctx.workspaceReady !== false) {
|
|
2453
|
+
sections.push(`## Workspace
|
|
2454
|
+
|
|
2455
|
+
O workspace local organiza os arquivos do curso:
|
|
2456
|
+
|
|
2457
|
+
\`\`\`
|
|
2458
|
+
~/study/{slug}/
|
|
2459
|
+
\u251C\u2500\u2500 exercises/{m\xF3dulo}/{li\xE7\xE3o}/ \u2190 Exerc\xEDcios extra\xEDdos
|
|
2460
|
+
\u251C\u2500\u2500 generated/ \u2190 Artefatos gerados
|
|
2461
|
+
\u2514\u2500\u2500 diagrams/ \u2190 Diagramas
|
|
2462
|
+
\`\`\`
|
|
2463
|
+
|
|
2464
|
+
Comandos \xFAteis:
|
|
2465
|
+
- \`tostudy export\` \u2014 Extrair exerc\xEDcio para o workspace
|
|
2466
|
+
- \`tostudy open\` \u2014 Abrir workspace no editor
|
|
2467
|
+
- \`tostudy workspace status\` \u2014 Verificar estado do workspace`);
|
|
2468
|
+
}
|
|
2469
|
+
sections.push(`## Comandos CLI
|
|
2470
|
+
|
|
2471
|
+
| Comando | Quando usar |
|
|
2472
|
+
|---------|-------------|
|
|
2473
|
+
| \`tostudy progress\` | No in\xEDcio da sess\xE3o e quando o aluno perguntar "onde estou?" |
|
|
2474
|
+
| \`tostudy start\` | Para carregar o m\xF3dulo atual ou o pr\xF3ximo |
|
|
2475
|
+
| \`tostudy lesson\` | Antes de discutir qualquer conte\xFAdo \u2014 sempre ler primeiro |
|
|
2476
|
+
| \`tostudy next\` | Ap\xF3s completar uma li\xE7\xE3o (teoria discutida ou exerc\xEDcio validado) |
|
|
2477
|
+
| \`tostudy hint\` | Quando o aluno travar \u2014 antes de explicar voc\xEA mesmo |
|
|
2478
|
+
| \`tostudy validate <arquivo>\` | Para validar exerc\xEDcios e checkpoints |
|
|
2479
|
+
| \`tostudy export\` | Para extrair exerc\xEDcio ao workspace local |`);
|
|
2480
|
+
sections.push(`## Refer\xEAncia T\xE9cnica (Modo Agente)
|
|
2481
|
+
|
|
2482
|
+
- Use \`--json\` em qualquer comando para sa\xEDda estruturada (ex: \`tostudy progress --json\`)
|
|
2483
|
+
- \`tostudy validate\` retorna exit code 0 (aprovado) ou 1 (reprovado)
|
|
2484
|
+
- \`tostudy validate --stdin\` aceita solu\xE7\xE3o via pipe
|
|
2485
|
+
- \`tostudy lesson --json\` retorna \`{ type, title, content, hints, acceptanceCriteria }\``);
|
|
2486
|
+
sections.push(`<!-- tostudy-course-id: ${ctx.courseId} -->`);
|
|
2487
|
+
return sections.join("\n\n") + "\n";
|
|
2488
|
+
}
|
|
2489
|
+
function generateInstructionFiles(ctx, learner) {
|
|
2490
|
+
const cwd = process.cwd();
|
|
2491
|
+
const slug = slugify(ctx.courseTitle);
|
|
2492
|
+
const content = buildInstructionContent(ctx, learner);
|
|
2493
|
+
const written = [];
|
|
2494
|
+
const claudeDir = join2(cwd, ".claude", "commands");
|
|
2495
|
+
if (!existsSync2(claudeDir)) {
|
|
2496
|
+
mkdirSync2(claudeDir, { recursive: true });
|
|
2497
|
+
}
|
|
2498
|
+
const claudeFile = `tostudy-${slug}.md`;
|
|
2499
|
+
writeFileSync2(join2(claudeDir, claudeFile), content);
|
|
2500
|
+
written.push(`.claude/commands/${claudeFile}`);
|
|
2501
|
+
const cursorDir = join2(cwd, ".cursor", "rules");
|
|
2502
|
+
if (existsSync2(join2(cwd, ".cursor")) || existsSync2(cursorDir)) {
|
|
2503
|
+
if (!existsSync2(cursorDir)) {
|
|
2504
|
+
mkdirSync2(cursorDir, { recursive: true });
|
|
2505
|
+
}
|
|
2506
|
+
const mdcContent = `---
|
|
2507
|
+
description: ${ctx.courseTitle} \u2014 ToStudy Course Guide
|
|
2508
|
+
globs: ["**/*"]
|
|
2509
|
+
alwaysApply: true
|
|
2510
|
+
---
|
|
2511
|
+
|
|
2512
|
+
${content}`;
|
|
2513
|
+
const cursorFile = `tostudy-${slug}.mdc`;
|
|
2514
|
+
writeFileSync2(join2(cursorDir, cursorFile), mdcContent);
|
|
2515
|
+
written.push(`.cursor/rules/${cursorFile}`);
|
|
2516
|
+
}
|
|
2517
|
+
const courseDir = join2(cwd, ".tostudy", "courses", slug);
|
|
2518
|
+
if (!existsSync2(courseDir)) {
|
|
2519
|
+
mkdirSync2(courseDir, { recursive: true });
|
|
2520
|
+
}
|
|
2521
|
+
writeFileSync2(join2(courseDir, "AGENTS.md"), content);
|
|
2522
|
+
written.push(`.tostudy/courses/${slug}/AGENTS.md`);
|
|
2523
|
+
logger3.info("Generated instruction files", {
|
|
2524
|
+
slug,
|
|
2525
|
+
files: written,
|
|
2526
|
+
hasLearnerProfile: !!learner
|
|
2527
|
+
});
|
|
2528
|
+
return slug;
|
|
2529
|
+
}
|
|
2530
|
+
var logger3;
|
|
2531
|
+
var init_instruction_files = __esm({
|
|
2532
|
+
"src/workspace/instruction-files.ts"() {
|
|
2533
|
+
"use strict";
|
|
2534
|
+
init_src();
|
|
2535
|
+
logger3 = createLogger("cli:instruction-files");
|
|
2536
|
+
}
|
|
2537
|
+
});
|
|
2538
|
+
|
|
2337
2539
|
// src/commands/select.ts
|
|
2338
2540
|
import { Command as Command6 } from "commander";
|
|
2339
|
-
var
|
|
2541
|
+
var logger4, selectCommand;
|
|
2340
2542
|
var init_select = __esm({
|
|
2341
2543
|
"src/commands/select.ts"() {
|
|
2342
2544
|
"use strict";
|
|
@@ -2345,12 +2547,13 @@ var init_select = __esm({
|
|
|
2345
2547
|
init_http2();
|
|
2346
2548
|
init_session();
|
|
2347
2549
|
init_formatter();
|
|
2348
|
-
|
|
2550
|
+
init_instruction_files();
|
|
2551
|
+
logger4 = createLogger("cli:select");
|
|
2349
2552
|
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) => {
|
|
2350
2553
|
try {
|
|
2351
2554
|
const session = await requireSession();
|
|
2352
2555
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
2353
|
-
const deps = { data, logger:
|
|
2556
|
+
const deps = { data, logger: logger4 };
|
|
2354
2557
|
const courses3 = await listCourses({ userId: session.userId }, deps);
|
|
2355
2558
|
let courseId = course;
|
|
2356
2559
|
let enrollmentId = "";
|
|
@@ -2377,17 +2580,35 @@ var init_select = __esm({
|
|
|
2377
2580
|
courseTags: matched?.tags,
|
|
2378
2581
|
courseLevel: matched?.level
|
|
2379
2582
|
});
|
|
2583
|
+
let courseSlug2 = "";
|
|
2584
|
+
try {
|
|
2585
|
+
courseSlug2 = generateInstructionFiles({
|
|
2586
|
+
courseTitle: detail.courseTitle,
|
|
2587
|
+
courseId: detail.courseId,
|
|
2588
|
+
progress: detail.progress,
|
|
2589
|
+
moduleCount: detail.moduleCount,
|
|
2590
|
+
lessonCount: detail.lessonCount,
|
|
2591
|
+
courseDescription: detail.courseDescription
|
|
2592
|
+
});
|
|
2593
|
+
} catch (err) {
|
|
2594
|
+
logger4.warn("Failed to generate instruction files", {
|
|
2595
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2380
2598
|
if (opts.json) {
|
|
2381
|
-
output({ ...detail, enrollmentId }, { json: true });
|
|
2599
|
+
output({ ...detail, enrollmentId, courseSlug: courseSlug2 }, { json: true });
|
|
2382
2600
|
} else {
|
|
2601
|
+
const slashCmd = courseSlug2 ? `/tostudy-${courseSlug2}` : "/tostudy";
|
|
2383
2602
|
output(
|
|
2384
2603
|
[
|
|
2385
2604
|
`\u2713 Curso ativado: ${detail.courseTitle}`,
|
|
2386
2605
|
` Progresso: ${detail.progress}% | ${detail.moduleCount} m\xF3dulos | ${detail.lessonCount} li\xE7\xF5es`,
|
|
2387
2606
|
"",
|
|
2388
|
-
"
|
|
2389
|
-
"
|
|
2390
|
-
"\u2192
|
|
2607
|
+
" Arquivos de contexto criados para seu assistente AI.",
|
|
2608
|
+
"",
|
|
2609
|
+
"\u2192 Abra sua plataforma (claude, codex, cursor...)",
|
|
2610
|
+
`\u2192 No Claude Code, digite: ${slashCmd}`,
|
|
2611
|
+
"\u2192 Em outras plataformas: tostudy init"
|
|
2391
2612
|
].join("\n"),
|
|
2392
2613
|
{ json: false }
|
|
2393
2614
|
);
|
|
@@ -2402,7 +2623,7 @@ var init_select = __esm({
|
|
|
2402
2623
|
|
|
2403
2624
|
// src/commands/progress.ts
|
|
2404
2625
|
import { Command as Command7 } from "commander";
|
|
2405
|
-
var
|
|
2626
|
+
var logger5, progressCommand;
|
|
2406
2627
|
var init_progress = __esm({
|
|
2407
2628
|
"src/commands/progress.ts"() {
|
|
2408
2629
|
"use strict";
|
|
@@ -2411,7 +2632,7 @@ var init_progress = __esm({
|
|
|
2411
2632
|
init_http2();
|
|
2412
2633
|
init_session();
|
|
2413
2634
|
init_formatter();
|
|
2414
|
-
|
|
2635
|
+
logger5 = createLogger("cli:progress");
|
|
2415
2636
|
progressCommand = new Command7("progress").description("Show your progress in the active course").option("--json", "Output structured JSON").action(async (opts) => {
|
|
2416
2637
|
try {
|
|
2417
2638
|
const session = await requireSession();
|
|
@@ -2419,7 +2640,7 @@ var init_progress = __esm({
|
|
|
2419
2640
|
const driftWarning = await checkCourseDrift();
|
|
2420
2641
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
2421
2642
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
2422
|
-
const deps = { data, logger:
|
|
2643
|
+
const deps = { data, logger: logger5 };
|
|
2423
2644
|
const progress3 = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
2424
2645
|
if (opts.json) {
|
|
2425
2646
|
output(progress3, { json: true });
|
|
@@ -3678,7 +3899,7 @@ var init_sql = __esm({
|
|
|
3678
3899
|
return new SQL([new StringChunk(str)]);
|
|
3679
3900
|
}
|
|
3680
3901
|
sql2.raw = raw;
|
|
3681
|
-
function
|
|
3902
|
+
function join3(chunks, separator) {
|
|
3682
3903
|
const result = [];
|
|
3683
3904
|
for (const [i, chunk] of chunks.entries()) {
|
|
3684
3905
|
if (i > 0 && separator !== void 0) {
|
|
@@ -3688,7 +3909,7 @@ var init_sql = __esm({
|
|
|
3688
3909
|
}
|
|
3689
3910
|
return new SQL(result);
|
|
3690
3911
|
}
|
|
3691
|
-
sql2.join =
|
|
3912
|
+
sql2.join = join3;
|
|
3692
3913
|
function identifier(value) {
|
|
3693
3914
|
return new Name(value);
|
|
3694
3915
|
}
|
|
@@ -10220,7 +10441,7 @@ var init_select3 = __esm({
|
|
|
10220
10441
|
const baseTableName = this.tableName;
|
|
10221
10442
|
const tableName = getTableLikeName(table);
|
|
10222
10443
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
10223
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
10444
|
+
if (typeof tableName === "string" && this.config.joins?.some((join3) => join3.alias === tableName)) {
|
|
10224
10445
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
10225
10446
|
}
|
|
10226
10447
|
if (!this.isPartialSelect) {
|
|
@@ -11747,7 +11968,7 @@ var init_update = __esm({
|
|
|
11747
11968
|
createJoin(joinType) {
|
|
11748
11969
|
return (table, on) => {
|
|
11749
11970
|
const tableName = getTableLikeName(table);
|
|
11750
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
11971
|
+
if (typeof tableName === "string" && this.config.joins.some((join3) => join3.alias === tableName)) {
|
|
11751
11972
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
11752
11973
|
}
|
|
11753
11974
|
if (typeof on === "function") {
|
|
@@ -11843,10 +12064,10 @@ var init_update = __esm({
|
|
|
11843
12064
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
11844
12065
|
fields[tableName] = fromFields;
|
|
11845
12066
|
}
|
|
11846
|
-
for (const
|
|
11847
|
-
const tableName2 = getTableLikeName(
|
|
11848
|
-
if (typeof tableName2 === "string" && !is(
|
|
11849
|
-
const fromFields = this.getTableLikeFields(
|
|
12067
|
+
for (const join3 of this.config.joins) {
|
|
12068
|
+
const tableName2 = getTableLikeName(join3.table);
|
|
12069
|
+
if (typeof tableName2 === "string" && !is(join3.table, SQL)) {
|
|
12070
|
+
const fromFields = this.getTableLikeFields(join3.table);
|
|
11850
12071
|
fields[tableName2] = fromFields;
|
|
11851
12072
|
}
|
|
11852
12073
|
}
|
|
@@ -12789,12 +13010,12 @@ var init_session3 = __esm({
|
|
|
12789
13010
|
init_tracing();
|
|
12790
13011
|
init_utils();
|
|
12791
13012
|
PostgresJsPreparedQuery = class extends PgPreparedQuery {
|
|
12792
|
-
constructor(client, queryString, params,
|
|
13013
|
+
constructor(client, queryString, params, logger17, cache, queryMetadata, cacheConfig, fields, _isResponseInArrayMode, customResultMapper) {
|
|
12793
13014
|
super({ sql: queryString, params }, cache, queryMetadata, cacheConfig);
|
|
12794
13015
|
this.client = client;
|
|
12795
13016
|
this.queryString = queryString;
|
|
12796
13017
|
this.params = params;
|
|
12797
|
-
this.logger =
|
|
13018
|
+
this.logger = logger17;
|
|
12798
13019
|
this.fields = fields;
|
|
12799
13020
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
12800
13021
|
this.customResultMapper = customResultMapper;
|
|
@@ -12935,11 +13156,11 @@ function construct(client, config2 = {}) {
|
|
|
12935
13156
|
client.options.serializers["114"] = transparentParser;
|
|
12936
13157
|
client.options.serializers["3802"] = transparentParser;
|
|
12937
13158
|
const dialect = new PgDialect({ casing: config2.casing });
|
|
12938
|
-
let
|
|
13159
|
+
let logger17;
|
|
12939
13160
|
if (config2.logger === true) {
|
|
12940
|
-
|
|
13161
|
+
logger17 = new DefaultLogger();
|
|
12941
13162
|
} else if (config2.logger !== false) {
|
|
12942
|
-
|
|
13163
|
+
logger17 = config2.logger;
|
|
12943
13164
|
}
|
|
12944
13165
|
let schema;
|
|
12945
13166
|
if (config2.schema) {
|
|
@@ -12953,7 +13174,7 @@ function construct(client, config2 = {}) {
|
|
|
12953
13174
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
12954
13175
|
};
|
|
12955
13176
|
}
|
|
12956
|
-
const session = new PostgresJsSession(client, dialect, schema, { logger:
|
|
13177
|
+
const session = new PostgresJsSession(client, dialect, schema, { logger: logger17, cache: config2.cache });
|
|
12957
13178
|
const db2 = new PostgresJsDatabase(dialect, session, schema);
|
|
12958
13179
|
db2.$client = client;
|
|
12959
13180
|
db2.$cache = config2.cache;
|
|
@@ -13155,7 +13376,7 @@ __export(util_exports, {
|
|
|
13155
13376
|
required: () => required,
|
|
13156
13377
|
safeExtend: () => safeExtend,
|
|
13157
13378
|
shallowClone: () => shallowClone,
|
|
13158
|
-
slugify: () =>
|
|
13379
|
+
slugify: () => slugify3,
|
|
13159
13380
|
stringifyPrimitive: () => stringifyPrimitive,
|
|
13160
13381
|
uint8ArrayToBase64: () => uint8ArrayToBase64,
|
|
13161
13382
|
uint8ArrayToBase64url: () => uint8ArrayToBase64url,
|
|
@@ -13295,7 +13516,7 @@ function randomString(length = 10) {
|
|
|
13295
13516
|
function esc(str) {
|
|
13296
13517
|
return JSON.stringify(str);
|
|
13297
13518
|
}
|
|
13298
|
-
function
|
|
13519
|
+
function slugify3(input2) {
|
|
13299
13520
|
return input2.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
13300
13521
|
}
|
|
13301
13522
|
function isObject(data) {
|
|
@@ -23429,7 +23650,7 @@ function _toUpperCase() {
|
|
|
23429
23650
|
}
|
|
23430
23651
|
// @__NO_SIDE_EFFECTS__
|
|
23431
23652
|
function _slugify() {
|
|
23432
|
-
return /* @__PURE__ */ _overwrite((input2) =>
|
|
23653
|
+
return /* @__PURE__ */ _overwrite((input2) => slugify3(input2));
|
|
23433
23654
|
}
|
|
23434
23655
|
// @__NO_SIDE_EFFECTS__
|
|
23435
23656
|
function _array(Class2, element, params) {
|
|
@@ -27494,6 +27715,10 @@ var init_users = __esm({
|
|
|
27494
27715
|
// Public portfolio active
|
|
27495
27716
|
followerDiscountPct: smallint("follower_discount_pct").default(0).notNull(),
|
|
27496
27717
|
// Follower discount: 0, 5, 10, 15, 20
|
|
27718
|
+
// Stripe Integration
|
|
27719
|
+
stripeCustomerId: varchar("stripe_customer_id", { length: 255 }),
|
|
27720
|
+
// Stripe Customer ID (cus_xxx) for payment method reuse
|
|
27721
|
+
metadata: jsonb("metadata").$type().default({}),
|
|
27497
27722
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
27498
27723
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
27499
27724
|
},
|
|
@@ -33953,77 +34178,6 @@ var init_marketing = __esm({
|
|
|
33953
34178
|
}
|
|
33954
34179
|
});
|
|
33955
34180
|
|
|
33956
|
-
// ../../packages/database/src/schema/user-credits.ts
|
|
33957
|
-
var transactionTypeEnum, userCredits2, creditTransactions2;
|
|
33958
|
-
var init_user_credits = __esm({
|
|
33959
|
-
"../../packages/database/src/schema/user-credits.ts"() {
|
|
33960
|
-
"use strict";
|
|
33961
|
-
init_pg_core();
|
|
33962
|
-
init_users();
|
|
33963
|
-
transactionTypeEnum = pgEnum("transaction_type", [
|
|
33964
|
-
"initial_grant",
|
|
33965
|
-
// Credito inicial de $5
|
|
33966
|
-
"purchase",
|
|
33967
|
-
// Compra de creditos
|
|
33968
|
-
"consumption",
|
|
33969
|
-
// Consumo por uso de IA
|
|
33970
|
-
"refund",
|
|
33971
|
-
// Reembolso
|
|
33972
|
-
"adjustment"
|
|
33973
|
-
// Ajuste manual admin
|
|
33974
|
-
]);
|
|
33975
|
-
userCredits2 = pgTable(
|
|
33976
|
-
"user_credits",
|
|
33977
|
-
{
|
|
33978
|
-
id: uuid("id").primaryKey().defaultRandom(),
|
|
33979
|
-
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull().unique(),
|
|
33980
|
-
/** Current balance in USD */
|
|
33981
|
-
balance: decimal("balance", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
33982
|
-
/** Total consumed in USD (absolute value, always positive) */
|
|
33983
|
-
totalConsumed: decimal("total_consumed", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
33984
|
-
/** Total purchased in USD */
|
|
33985
|
-
totalPurchased: decimal("total_purchased", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
33986
|
-
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
33987
|
-
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
33988
|
-
},
|
|
33989
|
-
(table) => ({
|
|
33990
|
-
userIdIdx: index("user_credits_user_id_idx").on(table.userId)
|
|
33991
|
-
})
|
|
33992
|
-
);
|
|
33993
|
-
creditTransactions2 = pgTable(
|
|
33994
|
-
"credit_transactions",
|
|
33995
|
-
{
|
|
33996
|
-
id: uuid("id").primaryKey().defaultRandom(),
|
|
33997
|
-
userId: uuid("user_id").references(() => users.id, { onDelete: "restrict" }).notNull(),
|
|
33998
|
-
type: transactionTypeEnum("type").notNull(),
|
|
33999
|
-
/** Amount in USD (negative for consumption, positive for purchase/grant) */
|
|
34000
|
-
amount: decimal("amount", { precision: 10, scale: 4 }).notNull(),
|
|
34001
|
-
/** Balance after this transaction in USD */
|
|
34002
|
-
balanceAfter: decimal("balance_after", { precision: 10, scale: 4 }).notNull(),
|
|
34003
|
-
description: text("description"),
|
|
34004
|
-
metadata: text("metadata"),
|
|
34005
|
-
// JSON com detalhes (tokens, modelo, etc)
|
|
34006
|
-
// Granular usage tracking columns
|
|
34007
|
-
operation: varchar("operation", { length: 50 }),
|
|
34008
|
-
// 'brainstorm_message', 'generation_outline', etc.
|
|
34009
|
-
model: varchar("model", { length: 100 }),
|
|
34010
|
-
// 'claude-sonnet-4-5-20250929'
|
|
34011
|
-
inputTokens: integer("input_tokens"),
|
|
34012
|
-
outputTokens: integer("output_tokens"),
|
|
34013
|
-
latencyMs: integer("latency_ms"),
|
|
34014
|
-
// DB FK to course_proposals preserved in migration; Drizzle ref removed for schema archival
|
|
34015
|
-
proposalId: uuid("proposal_id"),
|
|
34016
|
-
sessionId: uuid("session_id"),
|
|
34017
|
-
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
34018
|
-
},
|
|
34019
|
-
(table) => ({
|
|
34020
|
-
userIdIdx: index("credit_transactions_user_id_idx").on(table.userId),
|
|
34021
|
-
createdAtIdx: index("credit_transactions_created_at_idx").on(table.createdAt)
|
|
34022
|
-
})
|
|
34023
|
-
);
|
|
34024
|
-
}
|
|
34025
|
-
});
|
|
34026
|
-
|
|
34027
34181
|
// ../../packages/database/src/schema/usage-quotas.ts
|
|
34028
34182
|
var quotaChangeHistory, userUsageQuotas2, usageTierLimits2;
|
|
34029
34183
|
var init_usage_quotas = __esm({
|
|
@@ -34469,74 +34623,72 @@ var init_course_variants = __esm({
|
|
|
34469
34623
|
}
|
|
34470
34624
|
});
|
|
34471
34625
|
|
|
34472
|
-
// ../../packages/database/src/schema/_archived/
|
|
34473
|
-
var
|
|
34474
|
-
var
|
|
34475
|
-
"../../packages/database/src/schema/_archived/
|
|
34626
|
+
// ../../packages/database/src/schema/_archived/user-credits.ts
|
|
34627
|
+
var transactionTypeEnum, userCredits2, creditTransactions2;
|
|
34628
|
+
var init_user_credits = __esm({
|
|
34629
|
+
"../../packages/database/src/schema/_archived/user-credits.ts"() {
|
|
34476
34630
|
"use strict";
|
|
34477
34631
|
init_pg_core();
|
|
34478
34632
|
init_users();
|
|
34479
|
-
|
|
34480
|
-
|
|
34481
|
-
|
|
34482
|
-
|
|
34483
|
-
|
|
34484
|
-
|
|
34485
|
-
|
|
34486
|
-
|
|
34487
|
-
|
|
34488
|
-
|
|
34489
|
-
|
|
34490
|
-
// Creator rejected, needs regeneration
|
|
34491
|
-
]);
|
|
34492
|
-
translationEntityTypeEnum = pgEnum("translation_entity_type", [
|
|
34493
|
-
"matrix",
|
|
34494
|
-
// CourseMatrix (title, description, coreDocument)
|
|
34495
|
-
"module",
|
|
34496
|
-
// MatrixModule (title, description, lessonsContent)
|
|
34497
|
-
"variant"
|
|
34498
|
-
// CourseVariant (name, description)
|
|
34633
|
+
transactionTypeEnum = pgEnum("transaction_type", [
|
|
34634
|
+
"initial_grant",
|
|
34635
|
+
// Credito inicial de $5
|
|
34636
|
+
"purchase",
|
|
34637
|
+
// Compra de creditos
|
|
34638
|
+
"consumption",
|
|
34639
|
+
// Consumo por uso de IA
|
|
34640
|
+
"refund",
|
|
34641
|
+
// Reembolso
|
|
34642
|
+
"adjustment"
|
|
34643
|
+
// Ajuste manual admin
|
|
34499
34644
|
]);
|
|
34500
|
-
|
|
34501
|
-
"
|
|
34645
|
+
userCredits2 = pgTable(
|
|
34646
|
+
"user_credits",
|
|
34502
34647
|
{
|
|
34503
34648
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
34504
|
-
|
|
34505
|
-
|
|
34506
|
-
|
|
34507
|
-
|
|
34508
|
-
|
|
34509
|
-
|
|
34510
|
-
|
|
34511
|
-
sourceLanguage: text("source_language").notNull().default("en"),
|
|
34512
|
-
targetLanguage: text("target_language").notNull(),
|
|
34513
|
-
// Field being translated
|
|
34514
|
-
field: text("field").notNull(),
|
|
34515
|
-
// 'title', 'description', 'content', 'coreDocument', etc.
|
|
34516
|
-
// Translation content
|
|
34517
|
-
originalContent: text("original_content").notNull(),
|
|
34518
|
-
translatedContent: text("translated_content"),
|
|
34519
|
-
// Status
|
|
34520
|
-
status: translationStatusEnum("status").notNull().default("pending"),
|
|
34521
|
-
// Review
|
|
34522
|
-
reviewedAt: timestamp("reviewed_at"),
|
|
34523
|
-
reviewNotes: text("review_notes"),
|
|
34524
|
-
// Timestamps
|
|
34649
|
+
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull().unique(),
|
|
34650
|
+
/** Current balance in USD */
|
|
34651
|
+
balance: decimal("balance", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
34652
|
+
/** Total consumed in USD (absolute value, always positive) */
|
|
34653
|
+
totalConsumed: decimal("total_consumed", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
34654
|
+
/** Total purchased in USD */
|
|
34655
|
+
totalPurchased: decimal("total_purchased", { precision: 10, scale: 4 }).notNull().default("0"),
|
|
34525
34656
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
34526
34657
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
34527
34658
|
},
|
|
34528
34659
|
(table) => ({
|
|
34529
|
-
|
|
34530
|
-
|
|
34531
|
-
|
|
34532
|
-
|
|
34533
|
-
|
|
34534
|
-
|
|
34535
|
-
|
|
34536
|
-
|
|
34537
|
-
|
|
34538
|
-
|
|
34539
|
-
)
|
|
34660
|
+
userIdIdx: index("user_credits_user_id_idx").on(table.userId)
|
|
34661
|
+
})
|
|
34662
|
+
);
|
|
34663
|
+
creditTransactions2 = pgTable(
|
|
34664
|
+
"credit_transactions",
|
|
34665
|
+
{
|
|
34666
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
34667
|
+
userId: uuid("user_id").references(() => users.id, { onDelete: "restrict" }).notNull(),
|
|
34668
|
+
type: transactionTypeEnum("type").notNull(),
|
|
34669
|
+
/** Amount in USD (negative for consumption, positive for purchase/grant) */
|
|
34670
|
+
amount: decimal("amount", { precision: 10, scale: 4 }).notNull(),
|
|
34671
|
+
/** Balance after this transaction in USD */
|
|
34672
|
+
balanceAfter: decimal("balance_after", { precision: 10, scale: 4 }).notNull(),
|
|
34673
|
+
description: text("description"),
|
|
34674
|
+
metadata: text("metadata"),
|
|
34675
|
+
// JSON com detalhes (tokens, modelo, etc)
|
|
34676
|
+
// Granular usage tracking columns
|
|
34677
|
+
operation: varchar("operation", { length: 50 }),
|
|
34678
|
+
// 'brainstorm_message', 'generation_outline', etc.
|
|
34679
|
+
model: varchar("model", { length: 100 }),
|
|
34680
|
+
// 'claude-sonnet-4-5-20250929'
|
|
34681
|
+
inputTokens: integer("input_tokens"),
|
|
34682
|
+
outputTokens: integer("output_tokens"),
|
|
34683
|
+
latencyMs: integer("latency_ms"),
|
|
34684
|
+
// DB FK to course_proposals preserved in migration; Drizzle ref removed for schema archival
|
|
34685
|
+
proposalId: uuid("proposal_id"),
|
|
34686
|
+
sessionId: uuid("session_id"),
|
|
34687
|
+
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
34688
|
+
},
|
|
34689
|
+
(table) => ({
|
|
34690
|
+
userIdIdx: index("credit_transactions_user_id_idx").on(table.userId),
|
|
34691
|
+
createdAtIdx: index("credit_transactions_created_at_idx").on(table.createdAt)
|
|
34540
34692
|
})
|
|
34541
34693
|
);
|
|
34542
34694
|
}
|
|
@@ -34550,7 +34702,7 @@ var init_archived = __esm({
|
|
|
34550
34702
|
init_course_matrices();
|
|
34551
34703
|
init_matrix_modules();
|
|
34552
34704
|
init_course_variants();
|
|
34553
|
-
|
|
34705
|
+
init_user_credits();
|
|
34554
34706
|
}
|
|
34555
34707
|
});
|
|
34556
34708
|
|
|
@@ -35325,76 +35477,89 @@ var init_llm_analytics = __esm({
|
|
|
35325
35477
|
init_users();
|
|
35326
35478
|
init_courses3();
|
|
35327
35479
|
init_llm_pricing();
|
|
35328
|
-
llmInteractions = pgTable(
|
|
35329
|
-
|
|
35330
|
-
|
|
35331
|
-
|
|
35332
|
-
|
|
35333
|
-
|
|
35334
|
-
|
|
35335
|
-
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
35341
|
-
|
|
35342
|
-
|
|
35343
|
-
|
|
35344
|
-
|
|
35345
|
-
|
|
35346
|
-
|
|
35347
|
-
|
|
35348
|
-
|
|
35349
|
-
|
|
35350
|
-
|
|
35351
|
-
|
|
35352
|
-
|
|
35353
|
-
|
|
35354
|
-
|
|
35355
|
-
|
|
35356
|
-
|
|
35357
|
-
|
|
35358
|
-
|
|
35359
|
-
|
|
35360
|
-
|
|
35361
|
-
|
|
35362
|
-
|
|
35363
|
-
|
|
35364
|
-
|
|
35365
|
-
|
|
35366
|
-
|
|
35367
|
-
|
|
35368
|
-
|
|
35369
|
-
|
|
35370
|
-
|
|
35371
|
-
|
|
35372
|
-
|
|
35373
|
-
|
|
35374
|
-
|
|
35375
|
-
|
|
35376
|
-
|
|
35377
|
-
|
|
35378
|
-
|
|
35379
|
-
|
|
35380
|
-
|
|
35381
|
-
|
|
35382
|
-
|
|
35383
|
-
|
|
35384
|
-
|
|
35385
|
-
|
|
35386
|
-
|
|
35387
|
-
|
|
35388
|
-
|
|
35389
|
-
|
|
35390
|
-
|
|
35391
|
-
|
|
35392
|
-
|
|
35393
|
-
|
|
35394
|
-
|
|
35395
|
-
|
|
35396
|
-
|
|
35397
|
-
|
|
35480
|
+
llmInteractions = pgTable(
|
|
35481
|
+
"llm_interactions",
|
|
35482
|
+
{
|
|
35483
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
35484
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
35485
|
+
// Operation type
|
|
35486
|
+
operationType: varchar("operation_type", { length: 50 }).notNull(),
|
|
35487
|
+
// Provider (references llm_provider enum from llm-pricing.ts)
|
|
35488
|
+
provider: llmProviderEnum("provider").notNull().default("anthropic"),
|
|
35489
|
+
// Tracing
|
|
35490
|
+
correlationId: varchar("correlation_id", { length: 64 }),
|
|
35491
|
+
// Relationships
|
|
35492
|
+
userId: uuid("user_id").references(() => users.id, { onDelete: "set null" }),
|
|
35493
|
+
creatorId: uuid("creator_id").references(() => users.id, { onDelete: "set null" }),
|
|
35494
|
+
courseId: uuid("course_id").references(() => courses.id, { onDelete: "set null" }),
|
|
35495
|
+
sessionId: uuid("session_id"),
|
|
35496
|
+
variantId: uuid("variant_id"),
|
|
35497
|
+
// Denormalized from metadata for faster queries
|
|
35498
|
+
// Request
|
|
35499
|
+
model: varchar("model", { length: 50 }).notNull(),
|
|
35500
|
+
promptText: text("prompt_text"),
|
|
35501
|
+
promptTokens: integer("prompt_tokens").notNull(),
|
|
35502
|
+
// Response
|
|
35503
|
+
responseText: text("response_text"),
|
|
35504
|
+
responseTokens: integer("response_tokens").notNull(),
|
|
35505
|
+
// Cost & Revenue
|
|
35506
|
+
costUsd: decimal("cost_usd", { precision: 10, scale: 6 }).notNull(),
|
|
35507
|
+
revenueUsd: decimal("revenue_usd", { precision: 10, scale: 6 }).notNull().default("0"),
|
|
35508
|
+
// Cache metrics (prompt caching)
|
|
35509
|
+
cacheCreationTokens: integer("cache_creation_tokens").default(0),
|
|
35510
|
+
cacheReadTokens: integer("cache_read_tokens").default(0),
|
|
35511
|
+
cacheHit: integer("cache_hit").default(0),
|
|
35512
|
+
// 0 = false, 1 = true (SQLite-compatible)
|
|
35513
|
+
// Performance
|
|
35514
|
+
latencyMs: integer("latency_ms").notNull(),
|
|
35515
|
+
status: varchar("status", { length: 20 }).notNull(),
|
|
35516
|
+
errorMessage: text("error_message"),
|
|
35517
|
+
// Streaming metrics (null for non-streaming calls)
|
|
35518
|
+
timeToFirstTokenMs: integer("time_to_first_token_ms"),
|
|
35519
|
+
streamDurationMs: integer("stream_duration_ms"),
|
|
35520
|
+
// Model version and metadata
|
|
35521
|
+
modelVersion: varchar("model_version", { length: 100 }),
|
|
35522
|
+
metadata: jsonb("metadata").$type()
|
|
35523
|
+
},
|
|
35524
|
+
(table) => ({
|
|
35525
|
+
creatorIdx: index("idx_llm_interactions_creator").on(table.creatorId, table.createdAt),
|
|
35526
|
+
operationIdx: index("idx_llm_interactions_operation").on(table.operationType, table.createdAt),
|
|
35527
|
+
correlationIdx: index("idx_llm_interactions_correlation").on(table.correlationId),
|
|
35528
|
+
providerIdx: index("idx_llm_interactions_provider").on(table.provider),
|
|
35529
|
+
variantIdx: index("idx_llm_interactions_variant").on(table.variantId),
|
|
35530
|
+
creatorVariantDateIdx: index("idx_llm_interactions_creator_variant_date").on(
|
|
35531
|
+
table.creatorId,
|
|
35532
|
+
table.variantId,
|
|
35533
|
+
table.createdAt
|
|
35534
|
+
)
|
|
35535
|
+
})
|
|
35536
|
+
);
|
|
35537
|
+
llmUsageDaily = pgTable(
|
|
35538
|
+
"llm_usage_daily",
|
|
35539
|
+
{
|
|
35540
|
+
date: timestamp("date", { mode: "date" }).notNull(),
|
|
35541
|
+
operationType: varchar("operation_type", { length: 50 }).notNull(),
|
|
35542
|
+
creatorId: uuid("creator_id").notNull(),
|
|
35543
|
+
// No FK — sentinel UUID '00000000-...' used for system-level aggregation
|
|
35544
|
+
// Aggregated metrics
|
|
35545
|
+
totalRequests: integer("total_requests").notNull().default(0),
|
|
35546
|
+
totalPromptTokens: integer("total_prompt_tokens").notNull().default(0),
|
|
35547
|
+
totalResponseTokens: integer("total_response_tokens").notNull().default(0),
|
|
35548
|
+
totalCostUsd: decimal("total_cost_usd", { precision: 12, scale: 4 }).notNull().default("0"),
|
|
35549
|
+
totalRevenueUsd: decimal("total_revenue_usd", { precision: 12, scale: 4 }).notNull().default("0"),
|
|
35550
|
+
avgLatencyMs: integer("avg_latency_ms"),
|
|
35551
|
+
errorCount: integer("error_count").notNull().default(0),
|
|
35552
|
+
// Cache aggregated metrics
|
|
35553
|
+
totalCacheCreationTokens: integer("total_cache_creation_tokens").notNull().default(0),
|
|
35554
|
+
totalCacheReadTokens: integer("total_cache_read_tokens").notNull().default(0),
|
|
35555
|
+
totalCacheHits: integer("total_cache_hits").notNull().default(0)
|
|
35556
|
+
},
|
|
35557
|
+
(table) => ({
|
|
35558
|
+
pk: primaryKey({ columns: [table.date, table.operationType, table.creatorId] }),
|
|
35559
|
+
dateIdx: index("idx_llm_usage_daily_date").on(table.date),
|
|
35560
|
+
creatorIdx: index("idx_llm_usage_daily_creator").on(table.creatorId, table.date)
|
|
35561
|
+
})
|
|
35562
|
+
);
|
|
35398
35563
|
}
|
|
35399
35564
|
});
|
|
35400
35565
|
|
|
@@ -36958,7 +37123,12 @@ var init_video_intros = __esm({
|
|
|
36958
37123
|
"minimal-dark",
|
|
36959
37124
|
"gradient-bold",
|
|
36960
37125
|
"corporate-clean",
|
|
36961
|
-
"warm-organic"
|
|
37126
|
+
"warm-organic",
|
|
37127
|
+
"neon-tech",
|
|
37128
|
+
"playful-bright",
|
|
37129
|
+
"culinary-warm",
|
|
37130
|
+
"academic-serif",
|
|
37131
|
+
"music-rhythm"
|
|
36962
37132
|
]);
|
|
36963
37133
|
renderJobStatusEnum = pgEnum("render_job_status", [
|
|
36964
37134
|
"queued",
|
|
@@ -36984,6 +37154,8 @@ var init_video_intros = __esm({
|
|
|
36984
37154
|
durationSeconds: integer("duration_seconds"),
|
|
36985
37155
|
metadata: jsonb("metadata"),
|
|
36986
37156
|
sceneConfig: jsonb("scene_config").$type(),
|
|
37157
|
+
generationHistory: jsonb("generation_history").default([]).$type(),
|
|
37158
|
+
themeOverrides: jsonb("theme_overrides").$type(),
|
|
36987
37159
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
36988
37160
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
36989
37161
|
},
|
|
@@ -38217,7 +38389,6 @@ __export(schema_exports, {
|
|
|
38217
38389
|
creditSubscriptionStatusEnum: () => creditSubscriptionStatusEnum,
|
|
38218
38390
|
creditSubscriptions: () => creditSubscriptions,
|
|
38219
38391
|
creditTransactions: () => creditTransactions2,
|
|
38220
|
-
creditTransactionsRelations: () => creditTransactionsRelations2,
|
|
38221
38392
|
creditWalletTransactionTypeEnum: () => creditWalletTransactionTypeEnum,
|
|
38222
38393
|
creditWalletTransactions: () => creditWalletTransactions,
|
|
38223
38394
|
creditWallets: () => creditWallets,
|
|
@@ -38298,7 +38469,6 @@ __export(schema_exports, {
|
|
|
38298
38469
|
marketingContentTypeEnum: () => marketingContentTypeEnum,
|
|
38299
38470
|
matrixModules: () => matrixModules,
|
|
38300
38471
|
matrixStatusEnum: () => matrixStatusEnum,
|
|
38301
|
-
matrixTranslations: () => matrixTranslations,
|
|
38302
38472
|
mcpSessions: () => mcpSessions2,
|
|
38303
38473
|
mcpSessionsRelations: () => mcpSessionsRelations2,
|
|
38304
38474
|
mediaAssetDomainEnum: () => mediaAssetDomainEnum,
|
|
@@ -38509,8 +38679,6 @@ __export(schema_exports, {
|
|
|
38509
38679
|
transactionsRelations: () => transactionsRelations2,
|
|
38510
38680
|
transferStatusEnum: () => transferStatusEnum,
|
|
38511
38681
|
transferTypeEnum: () => transferTypeEnum,
|
|
38512
|
-
translationEntityTypeEnum: () => translationEntityTypeEnum,
|
|
38513
|
-
translationStatusEnum: () => translationStatusEnum,
|
|
38514
38682
|
tutorContentIssues: () => tutorContentIssues,
|
|
38515
38683
|
tutorContentIssuesRelations: () => tutorContentIssuesRelations,
|
|
38516
38684
|
tutorEvaluations: () => tutorEvaluations,
|
|
@@ -38524,7 +38692,6 @@ __export(schema_exports, {
|
|
|
38524
38692
|
userChallengeScores: () => userChallengeScores,
|
|
38525
38693
|
userChallengeScoresRelations: () => userChallengeScoresRelations,
|
|
38526
38694
|
userCredits: () => userCredits2,
|
|
38527
|
-
userCreditsRelations: () => userCreditsRelations2,
|
|
38528
38695
|
userFollows: () => userFollows2,
|
|
38529
38696
|
userFollowsRelations: () => userFollowsRelations2,
|
|
38530
38697
|
userPathEnrollments: () => userPathEnrollments,
|
|
@@ -38561,7 +38728,7 @@ __export(schema_exports, {
|
|
|
38561
38728
|
webhookEvents: () => webhookEvents2,
|
|
38562
38729
|
wishlists: () => wishlists
|
|
38563
38730
|
});
|
|
38564
|
-
var usersRelations2, onboardingAnalyticsRelations2, accountsRelations2, sessionsRelations2, browserSessionsRelations, courseCategoriesRelations, coursesRelations2, certificatesRelations2, enrollmentsRelations2, modulesRelations2, lessonsRelations2, progressRelations2, mentorshipThreadsRelations2, mentorshipMessagesRelations2, reviewsRelations2, payoutsRelations2, payoutTransactionsRelations2, creatorApplicationsRelations2, transactionsRelations2, couponsRelations2, couponUsagesRelations2, userPreferencesRelations2, mcpSessionsRelations2, syncLogsRelations2, slashCommandAnalyticsRelations2, conceptsRelations2, badgesRelations2, userBadgesRelations2, validationAttemptsRelations2, notificationLogsRelations2, mentorshipTemplatesRelations2, notificationsRelations2, funnelEventsRelations2, courseReviewsRelations2, courseReportsRelations2, mentorshipServicesRelations2, mentorAvailabilityRelations2, mentorAvailabilityExceptionsRelations2, mentorshipSessionsRelations2, sessionParticipantsRelations2, sessionResourcesRelations2, sessionWaitlistRelations2, mentorshipTransactionsRelations2, mentorshipPackagesRelations2, mentorshipCreditsRelations2, refundAuditLogRelations2, sessionReviewsRelations2, sessionReviewVotesRelations2, communityPostsRelations2, communityCommentsRelations2, communityLikesRelations2, userFollowsRelations2, sparkChatSessionsRelations2, studyChatSessionsRelations, studyChatMessagesRelations, studyChatArtifactsRelations, studyModuleSessionsIndexRelations, studyLessonContextsIndexRelations, studyChatMessagesV2Relations, generationStateRelations2, creatorTestimonialsRelations2, marketingContentRelations2,
|
|
38731
|
+
var usersRelations2, onboardingAnalyticsRelations2, accountsRelations2, sessionsRelations2, browserSessionsRelations, courseCategoriesRelations, coursesRelations2, certificatesRelations2, enrollmentsRelations2, modulesRelations2, lessonsRelations2, progressRelations2, mentorshipThreadsRelations2, mentorshipMessagesRelations2, reviewsRelations2, payoutsRelations2, payoutTransactionsRelations2, creatorApplicationsRelations2, transactionsRelations2, couponsRelations2, couponUsagesRelations2, userPreferencesRelations2, mcpSessionsRelations2, syncLogsRelations2, slashCommandAnalyticsRelations2, conceptsRelations2, badgesRelations2, userBadgesRelations2, validationAttemptsRelations2, notificationLogsRelations2, mentorshipTemplatesRelations2, notificationsRelations2, funnelEventsRelations2, courseReviewsRelations2, courseReportsRelations2, mentorshipServicesRelations2, mentorAvailabilityRelations2, mentorAvailabilityExceptionsRelations2, mentorshipSessionsRelations2, sessionParticipantsRelations2, sessionResourcesRelations2, sessionWaitlistRelations2, mentorshipTransactionsRelations2, mentorshipPackagesRelations2, mentorshipCreditsRelations2, refundAuditLogRelations2, sessionReviewsRelations2, sessionReviewVotesRelations2, communityPostsRelations2, communityCommentsRelations2, communityLikesRelations2, userFollowsRelations2, sparkChatSessionsRelations2, studyChatSessionsRelations, studyChatMessagesRelations, studyChatArtifactsRelations, studyModuleSessionsIndexRelations, studyLessonContextsIndexRelations, studyChatMessagesV2Relations, generationStateRelations2, creatorTestimonialsRelations2, marketingContentRelations2, brainstormingsRelations, ideasRelations, coursePublicationsRelations, publicationReviewHistoryRelations, studentNotesRelations2, learningStreaksRelations, dailyGoalsRelations, dailyGoalProgressRelations, countriesRelations, userRegionalSettingsRelations, courseProjectsRelations, sourceExtractionsRelations, projectGenerationStatesRelations, projectContentPoolRelations, projectVariantModulesRelations, exchangeRatesRelations, lessonRefinementsRelations, courseReviewSnapshotsRelations, learningPathsRelations2, pathCoursesRelations2, pathMilestonesRelations2, userPathEnrollmentsRelations, courseGraphsRelations, graphNodesRelations, graphEdgesRelations, projectTopicsRelations, graphNodeProgressRelations, creatorPortfolioCoursesRelations, portfolioViewsRelations, variationAxesRelations, creatorVariationAxesRelations, courseQaReportsRelations, studentWorkspacesRelations, projectSnapshotsRelations, tutorEvaluationsRelations, tutorContentIssuesRelations, mobileRefreshTokensRelations;
|
|
38565
38732
|
var init_schema3 = __esm({
|
|
38566
38733
|
"../../packages/database/src/schema/index.ts"() {
|
|
38567
38734
|
"use strict";
|
|
@@ -38621,7 +38788,6 @@ var init_schema3 = __esm({
|
|
|
38621
38788
|
init_generation_state();
|
|
38622
38789
|
init_security_audit_log();
|
|
38623
38790
|
init_marketing();
|
|
38624
|
-
init_user_credits();
|
|
38625
38791
|
init_usage_quotas();
|
|
38626
38792
|
init_brainstormings();
|
|
38627
38793
|
init_ideas();
|
|
@@ -38721,7 +38887,6 @@ var init_schema3 = __esm({
|
|
|
38721
38887
|
init_study_module_sessions();
|
|
38722
38888
|
init_generation_state();
|
|
38723
38889
|
init_marketing();
|
|
38724
|
-
init_user_credits();
|
|
38725
38890
|
init_brainstormings();
|
|
38726
38891
|
init_ideas();
|
|
38727
38892
|
init_course_publications();
|
|
@@ -38835,9 +39000,6 @@ var init_schema3 = __esm({
|
|
|
38835
39000
|
// Users this user follows
|
|
38836
39001
|
// Story 21.1: Spark chat sessions
|
|
38837
39002
|
sparkChatSessions: many(sparkChatSessions2),
|
|
38838
|
-
// Creator flow: Token credits
|
|
38839
|
-
credits: one(userCredits2),
|
|
38840
|
-
creditTransactions: many(creditTransactions2),
|
|
38841
39003
|
// Creator flow: New brainstormings
|
|
38842
39004
|
brainstormings: many(brainstormings),
|
|
38843
39005
|
// Creator flow: Ideas notepad
|
|
@@ -39586,18 +39748,6 @@ var init_schema3 = __esm({
|
|
|
39586
39748
|
references: [users.id]
|
|
39587
39749
|
})
|
|
39588
39750
|
}));
|
|
39589
|
-
userCreditsRelations2 = relations(userCredits2, ({ one }) => ({
|
|
39590
|
-
user: one(users, {
|
|
39591
|
-
fields: [userCredits2.userId],
|
|
39592
|
-
references: [users.id]
|
|
39593
|
-
})
|
|
39594
|
-
}));
|
|
39595
|
-
creditTransactionsRelations2 = relations(creditTransactions2, ({ one }) => ({
|
|
39596
|
-
user: one(users, {
|
|
39597
|
-
fields: [creditTransactions2.userId],
|
|
39598
|
-
references: [users.id]
|
|
39599
|
-
})
|
|
39600
|
-
}));
|
|
39601
39751
|
brainstormingsRelations = relations(brainstormings, ({ one }) => ({
|
|
39602
39752
|
creator: one(users, {
|
|
39603
39753
|
fields: [brainstormings.creatorId],
|
|
@@ -40024,7 +40174,6 @@ var init_src4 = __esm({
|
|
|
40024
40174
|
init_platform_settings();
|
|
40025
40175
|
init_marketing();
|
|
40026
40176
|
init_security_audit_log();
|
|
40027
|
-
init_user_credits();
|
|
40028
40177
|
init_gamification();
|
|
40029
40178
|
init_creator_portfolio_courses();
|
|
40030
40179
|
init_portfolio_views();
|
|
@@ -40144,6 +40293,15 @@ var init_next_lesson_full = __esm({
|
|
|
40144
40293
|
}
|
|
40145
40294
|
});
|
|
40146
40295
|
|
|
40296
|
+
// ../../packages/tostudy-core/src/memory/student-memory.ts
|
|
40297
|
+
var init_student_memory = __esm({
|
|
40298
|
+
"../../packages/tostudy-core/src/memory/student-memory.ts"() {
|
|
40299
|
+
"use strict";
|
|
40300
|
+
init_src4();
|
|
40301
|
+
init_src();
|
|
40302
|
+
}
|
|
40303
|
+
});
|
|
40304
|
+
|
|
40147
40305
|
// ../../packages/tostudy-core/src/learning/validate-solution-full.ts
|
|
40148
40306
|
var init_validate_solution_full = __esm({
|
|
40149
40307
|
"../../packages/tostudy-core/src/learning/validate-solution-full.ts"() {
|
|
@@ -40153,6 +40311,7 @@ var init_validate_solution_full = __esm({
|
|
|
40153
40311
|
init_exercise_types();
|
|
40154
40312
|
init_study_state_sync();
|
|
40155
40313
|
init_sync_enrollment_progress();
|
|
40314
|
+
init_student_memory();
|
|
40156
40315
|
}
|
|
40157
40316
|
});
|
|
40158
40317
|
|
|
@@ -40274,7 +40433,7 @@ async function runStart(opts, deps = defaultDeps2) {
|
|
|
40274
40433
|
deps.error(msg);
|
|
40275
40434
|
}
|
|
40276
40435
|
}
|
|
40277
|
-
var
|
|
40436
|
+
var logger6, defaultDeps2, StartBlockedError, startCommand;
|
|
40278
40437
|
var init_start = __esm({
|
|
40279
40438
|
"src/commands/start.ts"() {
|
|
40280
40439
|
"use strict";
|
|
@@ -40284,7 +40443,7 @@ var init_start = __esm({
|
|
|
40284
40443
|
init_session();
|
|
40285
40444
|
init_status();
|
|
40286
40445
|
init_formatter();
|
|
40287
|
-
|
|
40446
|
+
logger6 = createLogger("cli:start");
|
|
40288
40447
|
defaultDeps2 = {
|
|
40289
40448
|
requireSession,
|
|
40290
40449
|
requireActiveCourse,
|
|
@@ -40297,7 +40456,7 @@ var init_start = __esm({
|
|
|
40297
40456
|
output,
|
|
40298
40457
|
error,
|
|
40299
40458
|
stderrWrite: (message) => process.stderr.write(message),
|
|
40300
|
-
logger:
|
|
40459
|
+
logger: logger6
|
|
40301
40460
|
};
|
|
40302
40461
|
StartBlockedError = class extends Error {
|
|
40303
40462
|
};
|
|
@@ -40309,7 +40468,7 @@ var init_start = __esm({
|
|
|
40309
40468
|
|
|
40310
40469
|
// src/commands/start-next.ts
|
|
40311
40470
|
import { Command as Command9 } from "commander";
|
|
40312
|
-
var
|
|
40471
|
+
var logger7, startNextCommand;
|
|
40313
40472
|
var init_start_next = __esm({
|
|
40314
40473
|
"src/commands/start-next.ts"() {
|
|
40315
40474
|
"use strict";
|
|
@@ -40318,7 +40477,7 @@ var init_start_next = __esm({
|
|
|
40318
40477
|
init_http2();
|
|
40319
40478
|
init_session();
|
|
40320
40479
|
init_formatter();
|
|
40321
|
-
|
|
40480
|
+
logger7 = createLogger("cli:start-next");
|
|
40322
40481
|
startNextCommand = new Command9("start-next").description("Transition to the next module after completing the current one").option("--json", "Output structured JSON").action(async (opts) => {
|
|
40323
40482
|
try {
|
|
40324
40483
|
const session = await requireSession();
|
|
@@ -40326,7 +40485,7 @@ var init_start_next = __esm({
|
|
|
40326
40485
|
const driftWarning = await checkCourseDrift();
|
|
40327
40486
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
40328
40487
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
40329
|
-
const deps = { data, logger:
|
|
40488
|
+
const deps = { data, logger: logger7 };
|
|
40330
40489
|
const moduleData = await startNextModule({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
40331
40490
|
await setActiveCourse({ ...activeCourse, currentLessonId: moduleData.firstLesson.id });
|
|
40332
40491
|
if (opts.json) {
|
|
@@ -40349,7 +40508,7 @@ var init_start_next = __esm({
|
|
|
40349
40508
|
|
|
40350
40509
|
// src/commands/next.ts
|
|
40351
40510
|
import { Command as Command10 } from "commander";
|
|
40352
|
-
var
|
|
40511
|
+
var logger8, nextCommand;
|
|
40353
40512
|
var init_next = __esm({
|
|
40354
40513
|
"src/commands/next.ts"() {
|
|
40355
40514
|
"use strict";
|
|
@@ -40358,7 +40517,7 @@ var init_next = __esm({
|
|
|
40358
40517
|
init_http2();
|
|
40359
40518
|
init_session();
|
|
40360
40519
|
init_formatter();
|
|
40361
|
-
|
|
40520
|
+
logger8 = createLogger("cli:next");
|
|
40362
40521
|
nextCommand = new Command10("next").description("Advance to the next lesson in the active course").option("--json", "Output structured JSON").action(async (opts) => {
|
|
40363
40522
|
try {
|
|
40364
40523
|
const session = await requireSession();
|
|
@@ -40366,7 +40525,7 @@ var init_next = __esm({
|
|
|
40366
40525
|
const driftWarning = await checkCourseDrift();
|
|
40367
40526
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
40368
40527
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
40369
|
-
const deps = { data, logger:
|
|
40528
|
+
const deps = { data, logger: logger8 };
|
|
40370
40529
|
const lessonData = await nextLesson(
|
|
40371
40530
|
{ enrollmentId: activeCourse.enrollmentId, userConfirmation: "cli-next" },
|
|
40372
40531
|
deps
|
|
@@ -40447,7 +40606,7 @@ function formatLessonContent(data) {
|
|
|
40447
40606
|
}
|
|
40448
40607
|
return lines.join("\n");
|
|
40449
40608
|
}
|
|
40450
|
-
var
|
|
40609
|
+
var logger9, lessonCommand;
|
|
40451
40610
|
var init_lesson = __esm({
|
|
40452
40611
|
"src/commands/lesson.ts"() {
|
|
40453
40612
|
"use strict";
|
|
@@ -40457,7 +40616,7 @@ var init_lesson = __esm({
|
|
|
40457
40616
|
init_session();
|
|
40458
40617
|
init_formatter();
|
|
40459
40618
|
init_resolve();
|
|
40460
|
-
|
|
40619
|
+
logger9 = createLogger("cli:lesson");
|
|
40461
40620
|
lessonCommand = new Command11("lesson").description("Show the content of the current lesson").option("--json", "Output structured JSON").action(async (opts) => {
|
|
40462
40621
|
try {
|
|
40463
40622
|
const session = await requireSession();
|
|
@@ -40465,7 +40624,7 @@ var init_lesson = __esm({
|
|
|
40465
40624
|
const driftWarning = await checkCourseDrift();
|
|
40466
40625
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
40467
40626
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
40468
|
-
const deps = { data, logger:
|
|
40627
|
+
const deps = { data, logger: logger9 };
|
|
40469
40628
|
const lessonId = activeCourse.currentLessonId;
|
|
40470
40629
|
if (!lessonId) {
|
|
40471
40630
|
error("Nenhuma li\xE7\xE3o ativa encontrada. Rode: tostudy start ou tostudy next");
|
|
@@ -40494,7 +40653,7 @@ var init_lesson = __esm({
|
|
|
40494
40653
|
|
|
40495
40654
|
// src/commands/hint.ts
|
|
40496
40655
|
import { Command as Command12 } from "commander";
|
|
40497
|
-
var
|
|
40656
|
+
var logger10, hintCommand;
|
|
40498
40657
|
var init_hint = __esm({
|
|
40499
40658
|
"src/commands/hint.ts"() {
|
|
40500
40659
|
"use strict";
|
|
@@ -40503,7 +40662,7 @@ var init_hint = __esm({
|
|
|
40503
40662
|
init_http2();
|
|
40504
40663
|
init_session();
|
|
40505
40664
|
init_formatter();
|
|
40506
|
-
|
|
40665
|
+
logger10 = createLogger("cli:hint");
|
|
40507
40666
|
hintCommand = new Command12("hint").description("Get a progressive hint for the current exercise").option("--json", "Output structured JSON").action(async (opts) => {
|
|
40508
40667
|
try {
|
|
40509
40668
|
const session = await requireSession();
|
|
@@ -40511,7 +40670,7 @@ var init_hint = __esm({
|
|
|
40511
40670
|
const driftWarning = await checkCourseDrift();
|
|
40512
40671
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
40513
40672
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
40514
|
-
const deps = { data, logger:
|
|
40673
|
+
const deps = { data, logger: logger10 };
|
|
40515
40674
|
const hint = await getHint(
|
|
40516
40675
|
{ userId: session.userId, enrollmentId: activeCourse.enrollmentId },
|
|
40517
40676
|
deps
|
|
@@ -40802,7 +40961,7 @@ var init_init_template = __esm({
|
|
|
40802
40961
|
import fs8 from "node:fs";
|
|
40803
40962
|
import path7 from "node:path";
|
|
40804
40963
|
import { Command as Command13 } from "commander";
|
|
40805
|
-
var
|
|
40964
|
+
var logger11, validateCommand;
|
|
40806
40965
|
var init_validate = __esm({
|
|
40807
40966
|
"src/commands/validate.ts"() {
|
|
40808
40967
|
"use strict";
|
|
@@ -40812,7 +40971,7 @@ var init_validate = __esm({
|
|
|
40812
40971
|
init_session();
|
|
40813
40972
|
init_formatter();
|
|
40814
40973
|
init_init_template();
|
|
40815
|
-
|
|
40974
|
+
logger11 = createLogger("cli:validate");
|
|
40816
40975
|
validateCommand = new Command13("validate").description("Validate your solution for the current exercise").argument("[file]", "Path to the solution file to read").option("--stdin", "Read solution from stdin instead of a file").option("--json", "Output structured JSON").action(async (file2, opts) => {
|
|
40817
40976
|
try {
|
|
40818
40977
|
const session = await requireSession();
|
|
@@ -40871,7 +41030,7 @@ var init_validate = __esm({
|
|
|
40871
41030
|
}
|
|
40872
41031
|
}
|
|
40873
41032
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
40874
|
-
const deps = { data, logger:
|
|
41033
|
+
const deps = { data, logger: logger11 };
|
|
40875
41034
|
const result = await validateSolution(
|
|
40876
41035
|
{
|
|
40877
41036
|
lessonId,
|
|
@@ -41217,6 +41376,26 @@ Rode \`tostudy select <n\xFAmero>\` para ativar um curso.`,
|
|
|
41217
41376
|
source: "cli"
|
|
41218
41377
|
});
|
|
41219
41378
|
await deps.saveCourseLearnerProfile(activeCourse, learnerProfile, artifacts);
|
|
41379
|
+
try {
|
|
41380
|
+
generateInstructionFiles(
|
|
41381
|
+
{
|
|
41382
|
+
courseTitle: matchedCourse.title,
|
|
41383
|
+
courseId: activeCourse.courseId,
|
|
41384
|
+
progress: progressData?.coursePercent ?? matchedCourse.progress ?? 0,
|
|
41385
|
+
moduleCount: progressData?.currentModule?.totalModules ?? 0,
|
|
41386
|
+
lessonCount: progressData?.currentLesson?.totalLessons ?? 0,
|
|
41387
|
+
currentModuleTitle: progressData?.currentModule?.title,
|
|
41388
|
+
currentLessonTitle: progressData?.currentLesson?.title,
|
|
41389
|
+
courseDescription: matchedCourse.description ?? void 0
|
|
41390
|
+
},
|
|
41391
|
+
learnerProfile
|
|
41392
|
+
);
|
|
41393
|
+
deps.logger.info("Instruction files enriched with learner profile");
|
|
41394
|
+
} catch (err) {
|
|
41395
|
+
deps.logger.warn("Failed to update instruction files", {
|
|
41396
|
+
error: err instanceof Error ? err.message : String(err)
|
|
41397
|
+
});
|
|
41398
|
+
}
|
|
41220
41399
|
try {
|
|
41221
41400
|
await deps.setLastInitCourseId(activeCourse.courseId);
|
|
41222
41401
|
} catch (err) {
|
|
@@ -41225,7 +41404,7 @@ Rode \`tostudy select <n\xFAmero>\` para ativar um curso.`,
|
|
|
41225
41404
|
deps.output(artifacts.tutorInstructions, { json: false });
|
|
41226
41405
|
deps.output(artifacts.learnerBrief, { json: false });
|
|
41227
41406
|
}
|
|
41228
|
-
var
|
|
41407
|
+
var logger12, defaultDeps3, initCommand;
|
|
41229
41408
|
var init_init = __esm({
|
|
41230
41409
|
"src/commands/init.ts"() {
|
|
41231
41410
|
"use strict";
|
|
@@ -41237,7 +41416,8 @@ var init_init = __esm({
|
|
|
41237
41416
|
init_init_template();
|
|
41238
41417
|
init_learner_context();
|
|
41239
41418
|
init_api2();
|
|
41240
|
-
|
|
41419
|
+
init_instruction_files();
|
|
41420
|
+
logger12 = createLogger("cli:init");
|
|
41241
41421
|
defaultDeps3 = {
|
|
41242
41422
|
getSession,
|
|
41243
41423
|
getActiveCourse,
|
|
@@ -41251,7 +41431,7 @@ var init_init = __esm({
|
|
|
41251
41431
|
saveCourseLearnerProfile,
|
|
41252
41432
|
buildInitArtifacts,
|
|
41253
41433
|
output,
|
|
41254
|
-
logger:
|
|
41434
|
+
logger: logger12,
|
|
41255
41435
|
createHttpProvider
|
|
41256
41436
|
};
|
|
41257
41437
|
initCommand = new Command15("init").description("Generate tutor instructions and learner brief for the active course").action(async () => {
|
|
@@ -41571,14 +41751,14 @@ import { Command as Command16 } from "commander";
|
|
|
41571
41751
|
import path10 from "node:path";
|
|
41572
41752
|
import os7 from "node:os";
|
|
41573
41753
|
import fs11 from "node:fs/promises";
|
|
41574
|
-
var
|
|
41754
|
+
var logger13, workspaceCommand;
|
|
41575
41755
|
var init_workspace2 = __esm({
|
|
41576
41756
|
"src/commands/workspace.ts"() {
|
|
41577
41757
|
"use strict";
|
|
41578
41758
|
init_src();
|
|
41579
41759
|
init_workspace();
|
|
41580
41760
|
init_session();
|
|
41581
|
-
|
|
41761
|
+
logger13 = createLogger("cli:workspace");
|
|
41582
41762
|
workspaceCommand = new Command16("workspace").description(
|
|
41583
41763
|
"Gerenciar workspace de estudo local"
|
|
41584
41764
|
);
|
|
@@ -41609,7 +41789,7 @@ Pr\xF3ximo passo: tostudy export
|
|
|
41609
41789
|
);
|
|
41610
41790
|
}
|
|
41611
41791
|
} catch (err) {
|
|
41612
|
-
|
|
41792
|
+
logger13.error("workspace setup failed", { error: err });
|
|
41613
41793
|
process.stderr.write(`\u274C ${err instanceof Error ? err.message : String(err)}
|
|
41614
41794
|
`);
|
|
41615
41795
|
process.exit(1);
|
|
@@ -41711,7 +41891,7 @@ Pr\xF3ximo passo: tostudy export
|
|
|
41711
41891
|
import { Command as Command17 } from "commander";
|
|
41712
41892
|
import path11 from "node:path";
|
|
41713
41893
|
import os8 from "node:os";
|
|
41714
|
-
var
|
|
41894
|
+
var logger14, exportCommand;
|
|
41715
41895
|
var init_export = __esm({
|
|
41716
41896
|
"src/commands/export.ts"() {
|
|
41717
41897
|
"use strict";
|
|
@@ -41720,7 +41900,7 @@ var init_export = __esm({
|
|
|
41720
41900
|
init_http2();
|
|
41721
41901
|
init_session();
|
|
41722
41902
|
init_resolve();
|
|
41723
|
-
|
|
41903
|
+
logger14 = createLogger("cli:export");
|
|
41724
41904
|
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", path11.join(os8.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
41725
41905
|
try {
|
|
41726
41906
|
const session = await requireSession();
|
|
@@ -41765,7 +41945,7 @@ ${result.files.map((f) => ` \u{1F4C4} ${f}`).join("\n")}
|
|
|
41765
41945
|
);
|
|
41766
41946
|
}
|
|
41767
41947
|
} catch (err) {
|
|
41768
|
-
|
|
41948
|
+
logger14.error("export failed", { error: err });
|
|
41769
41949
|
process.stderr.write(`\u274C ${err instanceof Error ? err.message : String(err)}
|
|
41770
41950
|
`);
|
|
41771
41951
|
process.exit(1);
|
|
@@ -41790,13 +41970,13 @@ async function findWorkspacePath(courseTitle, basePath) {
|
|
|
41790
41970
|
return null;
|
|
41791
41971
|
}
|
|
41792
41972
|
}
|
|
41793
|
-
var
|
|
41973
|
+
var logger15, openCommand;
|
|
41794
41974
|
var init_open = __esm({
|
|
41795
41975
|
"src/commands/open.ts"() {
|
|
41796
41976
|
"use strict";
|
|
41797
41977
|
init_src();
|
|
41798
41978
|
init_session();
|
|
41799
|
-
|
|
41979
|
+
logger15 = createLogger("cli:open");
|
|
41800
41980
|
openCommand = new Command18("open").description("Abrir workspace do curso na IDE").option("--path <dir>", "Diret\xF3rio base do workspace", path12.join(os9.homedir(), "study")).action(async (opts) => {
|
|
41801
41981
|
try {
|
|
41802
41982
|
const activeCourse = await requireActiveCourse();
|
|
@@ -41810,7 +41990,7 @@ var init_open = __esm({
|
|
|
41810
41990
|
const editor = process.env["EDITOR"] ?? "code";
|
|
41811
41991
|
execFile3(editor, [workspacePath], (err) => {
|
|
41812
41992
|
if (err) {
|
|
41813
|
-
|
|
41993
|
+
logger15.error("open failed", { editor, workspacePath });
|
|
41814
41994
|
process.stderr.write(`\u274C Falha ao abrir: ${err.message}
|
|
41815
41995
|
`);
|
|
41816
41996
|
process.exit(1);
|
|
@@ -41819,7 +41999,7 @@ var init_open = __esm({
|
|
|
41819
41999
|
`);
|
|
41820
42000
|
});
|
|
41821
42001
|
} catch (err) {
|
|
41822
|
-
|
|
42002
|
+
logger15.error("open command failed", { error: err });
|
|
41823
42003
|
process.stderr.write(`\u274C ${err instanceof Error ? err.message : String(err)}
|
|
41824
42004
|
`);
|
|
41825
42005
|
process.exit(1);
|
|
@@ -41891,7 +42071,7 @@ import { Command as Command19 } from "commander";
|
|
|
41891
42071
|
import path14 from "node:path";
|
|
41892
42072
|
import os10 from "node:os";
|
|
41893
42073
|
import fs14 from "node:fs/promises";
|
|
41894
|
-
var
|
|
42074
|
+
var logger16, vaultCommand;
|
|
41895
42075
|
var init_vault2 = __esm({
|
|
41896
42076
|
"src/commands/vault.ts"() {
|
|
41897
42077
|
"use strict";
|
|
@@ -41900,7 +42080,7 @@ var init_vault2 = __esm({
|
|
|
41900
42080
|
init_courses();
|
|
41901
42081
|
init_http2();
|
|
41902
42082
|
init_session();
|
|
41903
|
-
|
|
42083
|
+
logger16 = createLogger("cli:vault");
|
|
41904
42084
|
vaultCommand = new Command19("vault").description("Gerenciar vault Obsidian do curso");
|
|
41905
42085
|
vaultCommand.command("init").description("Gerar vault Obsidian para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace", path14.join(os10.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
41906
42086
|
try {
|
|
@@ -41934,7 +42114,7 @@ var init_vault2 = __esm({
|
|
|
41934
42114
|
activeCourse.courseId,
|
|
41935
42115
|
courseSlug2
|
|
41936
42116
|
);
|
|
41937
|
-
|
|
42117
|
+
logger16.info("Vault generated", {
|
|
41938
42118
|
courseId: activeCourse.courseId,
|
|
41939
42119
|
vaultPath: result.vaultPath,
|
|
41940
42120
|
filesWritten: result.filesWritten
|
|
@@ -41967,7 +42147,7 @@ Para visualizar:
|
|
|
41967
42147
|
);
|
|
41968
42148
|
}
|
|
41969
42149
|
} catch (err) {
|
|
41970
|
-
|
|
42150
|
+
logger16.error("vault init failed", { error: err });
|
|
41971
42151
|
process.stderr.write(`\u274C ${err instanceof Error ? err.message : String(err)}
|
|
41972
42152
|
`);
|
|
41973
42153
|
process.exit(1);
|
|
@@ -41988,7 +42168,7 @@ Para visualizar:
|
|
|
41988
42168
|
process.exit(1);
|
|
41989
42169
|
}
|
|
41990
42170
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
41991
|
-
const deps = { data, logger:
|
|
42171
|
+
const deps = { data, logger: logger16 };
|
|
41992
42172
|
const progress3 = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
41993
42173
|
const markerPath = path14.join(vaultPath, ".ana-vault.json");
|
|
41994
42174
|
const markerRaw = await fs14.readFile(markerPath, "utf-8");
|
|
@@ -42042,7 +42222,7 @@ Para visualizar:
|
|
|
42042
42222
|
);
|
|
42043
42223
|
}
|
|
42044
42224
|
} catch (err) {
|
|
42045
|
-
|
|
42225
|
+
logger16.error("vault sync failed", { error: err });
|
|
42046
42226
|
process.stderr.write(`\u274C ${err instanceof Error ? err.message : String(err)}
|
|
42047
42227
|
`);
|
|
42048
42228
|
process.exit(1);
|
|
@@ -42105,7 +42285,7 @@ var init_cli = __esm({
|
|
|
42105
42285
|
init_export();
|
|
42106
42286
|
init_open();
|
|
42107
42287
|
init_vault2();
|
|
42108
|
-
CLI_VERSION = "0.
|
|
42288
|
+
CLI_VERSION = true ? "0.7.2" : "0.7.1";
|
|
42109
42289
|
}
|
|
42110
42290
|
});
|
|
42111
42291
|
|