@tostudy-ai/cli 0.11.1 → 0.12.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 +1151 -421
- package/dist/cli.js.map +4 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -5,11 +5,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __esm = (fn, res) => function __init() {
|
|
9
|
-
|
|
8
|
+
var __esm = (fn, res, err) => function __init() {
|
|
9
|
+
if (err) throw err[0];
|
|
10
|
+
try {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw err = [e], e;
|
|
14
|
+
}
|
|
10
15
|
};
|
|
11
16
|
var __commonJS = (cb, mod) => function __require() {
|
|
12
|
-
|
|
17
|
+
try {
|
|
18
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw mod = 0, e;
|
|
21
|
+
}
|
|
13
22
|
};
|
|
14
23
|
var __export = (target, all) => {
|
|
15
24
|
for (var name in all)
|
|
@@ -104,7 +113,7 @@ var require_picocolors = __commonJS({
|
|
|
104
113
|
}
|
|
105
114
|
});
|
|
106
115
|
|
|
107
|
-
// ../../node_modules/@parisgroup-ai/logger/dist/logger.base-
|
|
116
|
+
// ../../node_modules/@parisgroup-ai/logger/dist/logger.base-DJVL2Rjl.mjs
|
|
108
117
|
function formatJson(entry) {
|
|
109
118
|
const { timestamp: timestamp2, level, message, service, environment, context, data, error: error49 } = entry;
|
|
110
119
|
const output3 = {
|
|
@@ -226,18 +235,24 @@ function isSensitiveKey(key) {
|
|
|
226
235
|
].some((p) => lowerKey.includes(p));
|
|
227
236
|
});
|
|
228
237
|
}
|
|
229
|
-
function serializeError(error49) {
|
|
238
|
+
function serializeError(error49, visited = /* @__PURE__ */ new WeakSet()) {
|
|
230
239
|
const serialized = {
|
|
231
240
|
name: error49.name,
|
|
232
241
|
message: error49.message
|
|
233
242
|
};
|
|
234
243
|
if (error49.stack) serialized.stack = error49.stack;
|
|
235
244
|
if ("code" in error49 && typeof error49.code === "string") serialized.code = error49.code;
|
|
236
|
-
|
|
245
|
+
visited.add(error49);
|
|
246
|
+
if (error49.cause instanceof Error) serialized.cause = visited.has(error49.cause) ? {
|
|
247
|
+
name: error49.cause.name,
|
|
248
|
+
message: "[Circular]"
|
|
249
|
+
} : serializeError(error49.cause, visited);
|
|
237
250
|
return serialized;
|
|
238
251
|
}
|
|
239
|
-
function object(obj, additionalSensitiveKeys) {
|
|
252
|
+
function object(obj, additionalSensitiveKeys, visited = /* @__PURE__ */ new WeakSet()) {
|
|
240
253
|
if (!obj || typeof obj !== "object") return obj;
|
|
254
|
+
if (visited.has(obj)) return "[Circular]";
|
|
255
|
+
visited.add(obj);
|
|
241
256
|
const sanitized = { ...obj };
|
|
242
257
|
for (const [key, value] of Object.entries(sanitized)) {
|
|
243
258
|
const isAdditionalKey = additionalSensitiveKeys?.some((k) => key.toLowerCase() === k.toLowerCase());
|
|
@@ -250,15 +265,23 @@ function object(obj, additionalSensitiveKeys) {
|
|
|
250
265
|
continue;
|
|
251
266
|
}
|
|
252
267
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
253
|
-
|
|
268
|
+
if (visited.has(value)) {
|
|
269
|
+
sanitized[key] = "[Circular]";
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
sanitized[key] = object(value, additionalSensitiveKeys, visited);
|
|
254
273
|
continue;
|
|
255
274
|
}
|
|
256
275
|
if (Array.isArray(value)) sanitized[key] = value.map((item) => {
|
|
257
276
|
if (item instanceof Error) return serializeError(item);
|
|
258
|
-
if (item && typeof item === "object" && !Array.isArray(item))
|
|
277
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
278
|
+
if (visited.has(item)) return "[Circular]";
|
|
279
|
+
return object(item, additionalSensitiveKeys, visited);
|
|
280
|
+
}
|
|
259
281
|
return item;
|
|
260
282
|
});
|
|
261
283
|
}
|
|
284
|
+
visited.delete(obj);
|
|
262
285
|
return sanitized;
|
|
263
286
|
}
|
|
264
287
|
function headers(hdrs) {
|
|
@@ -273,19 +296,24 @@ function headers(hdrs) {
|
|
|
273
296
|
for (const key of Object.keys(sanitized)) if (sensitiveHeaders.some((h) => key.toLowerCase() === h)) sanitized[key] = "[REDACTED]";
|
|
274
297
|
return sanitized;
|
|
275
298
|
}
|
|
276
|
-
function extractErrorInfo(error49, includeStack) {
|
|
299
|
+
function extractErrorInfo(error49, includeStack, visited = /* @__PURE__ */ new WeakSet()) {
|
|
277
300
|
const info = {
|
|
278
301
|
name: error49.name,
|
|
279
302
|
message: error49.message
|
|
280
303
|
};
|
|
281
304
|
if (includeStack && error49.stack) info.stack = error49.stack;
|
|
282
305
|
if ("code" in error49 && typeof error49.code === "string") info.code = error49.code;
|
|
283
|
-
|
|
306
|
+
visited.add(error49);
|
|
307
|
+
if (error49.cause instanceof Error) if (visited.has(error49.cause)) info.cause = {
|
|
308
|
+
name: error49.cause.name,
|
|
309
|
+
message: "[Circular]"
|
|
310
|
+
};
|
|
311
|
+
else info.cause = extractErrorInfo(error49.cause, includeStack, visited);
|
|
284
312
|
return info;
|
|
285
313
|
}
|
|
286
314
|
var import_picocolors, LOG_LEVELS, LEVEL_COLORS, LEVEL_WIDTH, SENSITIVE_FIELDS, sanitize, BaseLogger;
|
|
287
|
-
var
|
|
288
|
-
"../../node_modules/@parisgroup-ai/logger/dist/logger.base-
|
|
315
|
+
var init_logger_base_DJVL2Rjl = __esm({
|
|
316
|
+
"../../node_modules/@parisgroup-ai/logger/dist/logger.base-DJVL2Rjl.mjs"() {
|
|
289
317
|
import_picocolors = __toESM(require_picocolors(), 1);
|
|
290
318
|
LOG_LEVELS = {
|
|
291
319
|
trace: 0,
|
|
@@ -611,7 +639,7 @@ function createLogger(module, options) {
|
|
|
611
639
|
var asyncLocalStorage, ConsoleTransport, FileTransport, HttpTransport, SINGLETON_KEY, Logger, logger;
|
|
612
640
|
var init_dist = __esm({
|
|
613
641
|
"../../node_modules/@parisgroup-ai/logger/dist/index.mjs"() {
|
|
614
|
-
|
|
642
|
+
init_logger_base_DJVL2Rjl();
|
|
615
643
|
asyncLocalStorage = new AsyncLocalStorage();
|
|
616
644
|
ConsoleTransport = class {
|
|
617
645
|
log(entry, formatted) {
|
|
@@ -784,14 +812,6 @@ var init_dist = __esm({
|
|
|
784
812
|
}
|
|
785
813
|
});
|
|
786
814
|
|
|
787
|
-
// ../../packages/logger/src/index.ts
|
|
788
|
-
var init_src = __esm({
|
|
789
|
-
"../../packages/logger/src/index.ts"() {
|
|
790
|
-
"use strict";
|
|
791
|
-
init_dist();
|
|
792
|
-
}
|
|
793
|
-
});
|
|
794
|
-
|
|
795
815
|
// ../../packages/tostudy-core/src/courses/list-courses.ts
|
|
796
816
|
async function listCourses(input2, deps) {
|
|
797
817
|
deps.logger.info("tostudy-core: listCourses", { userId: input2.userId });
|
|
@@ -836,7 +856,7 @@ var init_courses = __esm({
|
|
|
836
856
|
});
|
|
837
857
|
|
|
838
858
|
// ../../packages/tostudy-core/src/adapters/http.ts
|
|
839
|
-
async function
|
|
859
|
+
async function cliApiFetch(url2, token2, init) {
|
|
840
860
|
const response = await fetch(url2, {
|
|
841
861
|
...init,
|
|
842
862
|
headers: {
|
|
@@ -856,7 +876,7 @@ function createHttpProvider(apiUrl, token2) {
|
|
|
856
876
|
return {
|
|
857
877
|
courses: {
|
|
858
878
|
list: async (_userId) => {
|
|
859
|
-
const res = await
|
|
879
|
+
const res = await cliApiFetch(`${base}/courses`, token2);
|
|
860
880
|
return res.courses;
|
|
861
881
|
},
|
|
862
882
|
listCreatorCourses: async (filters) => {
|
|
@@ -868,26 +888,29 @@ function createHttpProvider(apiUrl, token2) {
|
|
|
868
888
|
if (filters.limit) params.append("limit", filters.limit.toString());
|
|
869
889
|
if (filters.offset) params.append("offset", filters.offset.toString());
|
|
870
890
|
if (filters.projectId) params.append("projectId", filters.projectId);
|
|
871
|
-
const res = await
|
|
891
|
+
const res = await cliApiFetch(
|
|
872
892
|
`${base}/creator-courses?${params.toString()}`,
|
|
873
893
|
token2
|
|
874
894
|
);
|
|
875
895
|
return res.courses;
|
|
876
896
|
},
|
|
877
897
|
select: async (_userId, courseId) => {
|
|
878
|
-
const res = await
|
|
898
|
+
const res = await cliApiFetch(`${base}/courses/select`, token2, {
|
|
879
899
|
method: "POST",
|
|
880
900
|
body: JSON.stringify({ courseId })
|
|
881
901
|
});
|
|
882
902
|
return res.course;
|
|
883
903
|
},
|
|
884
904
|
getProgress: async (enrollmentId) => {
|
|
885
|
-
return
|
|
905
|
+
return cliApiFetch(
|
|
906
|
+
`${base}/progress?enrollmentId=${encodeURIComponent(enrollmentId)}`,
|
|
907
|
+
token2
|
|
908
|
+
);
|
|
886
909
|
}
|
|
887
910
|
},
|
|
888
911
|
lessons: {
|
|
889
912
|
next: async (enrollmentId, userConfirmation) => {
|
|
890
|
-
return
|
|
913
|
+
return cliApiFetch(`${base}/lessons/next`, token2, {
|
|
891
914
|
method: "POST",
|
|
892
915
|
body: JSON.stringify({ enrollmentId, userConfirmation })
|
|
893
916
|
});
|
|
@@ -895,22 +918,22 @@ function createHttpProvider(apiUrl, token2) {
|
|
|
895
918
|
getContent: async (lessonId, enrollmentId) => {
|
|
896
919
|
const params = new URLSearchParams({ lessonId });
|
|
897
920
|
if (enrollmentId) params.set("enrollmentId", enrollmentId);
|
|
898
|
-
return
|
|
921
|
+
return cliApiFetch(`${base}/lessons/content?${params.toString()}`, token2);
|
|
899
922
|
},
|
|
900
923
|
getHint: async (_userId, enrollmentId) => {
|
|
901
|
-
return
|
|
924
|
+
return cliApiFetch(`${base}/lessons/hint`, token2, {
|
|
902
925
|
method: "POST",
|
|
903
926
|
body: JSON.stringify({ enrollmentId })
|
|
904
927
|
});
|
|
905
928
|
},
|
|
906
929
|
startModule: async (enrollmentId) => {
|
|
907
|
-
return
|
|
930
|
+
return cliApiFetch(`${base}/modules/start`, token2, {
|
|
908
931
|
method: "POST",
|
|
909
932
|
body: JSON.stringify({ enrollmentId })
|
|
910
933
|
});
|
|
911
934
|
},
|
|
912
935
|
startNextModule: async (enrollmentId) => {
|
|
913
|
-
return
|
|
936
|
+
return cliApiFetch(`${base}/modules/start-next`, token2, {
|
|
914
937
|
method: "POST",
|
|
915
938
|
body: JSON.stringify({ enrollmentId })
|
|
916
939
|
});
|
|
@@ -933,17 +956,17 @@ function createHttpProvider(apiUrl, token2) {
|
|
|
933
956
|
},
|
|
934
957
|
exercises: {
|
|
935
958
|
validate: async (lessonId, solution, _userId, enrollmentId) => {
|
|
936
|
-
return
|
|
959
|
+
return cliApiFetch(`${base}/exercises/validate`, token2, {
|
|
937
960
|
method: "POST",
|
|
938
961
|
body: JSON.stringify({ lessonId, solution, enrollmentId })
|
|
939
962
|
});
|
|
940
963
|
},
|
|
941
964
|
getEnrollmentLevels: async (enrollmentId) => {
|
|
942
965
|
const params = new URLSearchParams({ enrollmentId });
|
|
943
|
-
return
|
|
966
|
+
return cliApiFetch(`${base}/enrollments/levels?${params.toString()}`, token2);
|
|
944
967
|
},
|
|
945
968
|
setEnrollmentLevel: async (enrollmentId, level) => {
|
|
946
|
-
return
|
|
969
|
+
return cliApiFetch(`${base}/enrollments/levels`, token2, {
|
|
947
970
|
method: "POST",
|
|
948
971
|
body: JSON.stringify({ enrollmentId, level })
|
|
949
972
|
});
|
|
@@ -955,6 +978,16 @@ function createHttpProvider(apiUrl, token2) {
|
|
|
955
978
|
"createModuleSession is not available via HTTP adapter. Use the Drizzle adapter for session management."
|
|
956
979
|
);
|
|
957
980
|
}
|
|
981
|
+
},
|
|
982
|
+
memory: {
|
|
983
|
+
getContext: async (courseId, enrollmentId) => {
|
|
984
|
+
const params = new URLSearchParams({ courseId, enrollmentId });
|
|
985
|
+
return cliApiFetch(`${base}/memory?${params.toString()}`, token2);
|
|
986
|
+
},
|
|
987
|
+
recordInsight: async (input2) => cliApiFetch(`${base}/memory/record-insight`, token2, {
|
|
988
|
+
method: "POST",
|
|
989
|
+
body: JSON.stringify(input2)
|
|
990
|
+
})
|
|
958
991
|
}
|
|
959
992
|
};
|
|
960
993
|
}
|
|
@@ -968,6 +1001,7 @@ var init_http = __esm({
|
|
|
968
1001
|
this.status = status;
|
|
969
1002
|
this.name = "CliApiError";
|
|
970
1003
|
}
|
|
1004
|
+
status;
|
|
971
1005
|
};
|
|
972
1006
|
}
|
|
973
1007
|
});
|
|
@@ -1310,10 +1344,19 @@ function formatProgress(data) {
|
|
|
1310
1344
|
`Li\xE7\xF5es conclu\xEDdas: ${data.completedLessons}`,
|
|
1311
1345
|
`Tempo restante estimado: ~${data.estimatedMinutesRemaining} min`,
|
|
1312
1346
|
"\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\u2500\u2500\u2500\u2500",
|
|
1313
|
-
""
|
|
1314
|
-
"\u2192 tostudy next para avan\xE7ar para a pr\xF3xima li\xE7\xE3o",
|
|
1315
|
-
"\u2192 tostudy lesson para ver o conte\xFAdo da li\xE7\xE3o atual"
|
|
1347
|
+
""
|
|
1316
1348
|
];
|
|
1349
|
+
if (data.isArchived) {
|
|
1350
|
+
lines.push(
|
|
1351
|
+
"\u26A0 Curso arquivado \u2014 somente leitura.",
|
|
1352
|
+
"\u2192 tostudy lesson para reler o conte\xFAdo j\xE1 estudado"
|
|
1353
|
+
);
|
|
1354
|
+
} else {
|
|
1355
|
+
lines.push(
|
|
1356
|
+
"\u2192 tostudy next para avan\xE7ar para a pr\xF3xima li\xE7\xE3o",
|
|
1357
|
+
"\u2192 tostudy lesson para ver o conte\xFAdo da li\xE7\xE3o atual"
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1317
1360
|
return lines.join("\n");
|
|
1318
1361
|
}
|
|
1319
1362
|
function formatLesson(data) {
|
|
@@ -1598,8 +1641,9 @@ Rode \`tostudy context --json\` em sil\xEAncio para descobrir o estado do aluno.
|
|
|
1598
1641
|
### Se tudo pronto (workspace + curso + contexto):
|
|
1599
1642
|
|
|
1600
1643
|
1. Leia os \`moduleSummaries\` do resultado para saber o que o aluno j\xE1 estudou.
|
|
1601
|
-
2.
|
|
1602
|
-
3.
|
|
1644
|
+
2. Rode \`tostudy memory --json\` em sil\xEAncio para carregar o perfil do aluno (dificuldades conhecidas, pontos fortes) e os resumos das li\xE7\xF5es recentes. Use esse contexto para adaptar a aula \u2014 n\xE3o repita o que o aluno j\xE1 domina, e reforce os pontos onde ele teve dificuldade. NUNCA mostre esse bloco cru ao aluno.
|
|
1645
|
+
3. Se houver summaries, mencione brevemente: "Da \xFAltima vez paramos em {ultimoModulo}. Pronto pra continuar?"
|
|
1646
|
+
4. Siga "Como Conduzir a Aula" abaixo.`);
|
|
1603
1647
|
sections.push(renderHowToConduct());
|
|
1604
1648
|
sections.push(renderSilentTools());
|
|
1605
1649
|
sections.push(`## Compacta\xE7\xE3o de Contexto (Autom\xE1tico)
|
|
@@ -1799,6 +1843,10 @@ Estes comandos s\xE3o suas ferramentas. Rode em sil\xEAncio (sem anunciar), use
|
|
|
1799
1843
|
- \`tostudy hint --json\` \u2014 dica progressiva (3 n\xEDveis).
|
|
1800
1844
|
- \`tostudy validate <arquivo>\` \u2014 valida exerc\xEDcio (exit 0 = passou, 1 = falhou).
|
|
1801
1845
|
|
|
1846
|
+
- \`tostudy insight <tipo> "<descri\xE7\xE3o>" --json\` \u2014 registra na mem\xF3ria do curso um sinal cognitivo do aluno. Tipos: \`difficulty\` (travou ou confundiu um conceito), \`breakthrough\` (teve um clique, dominou algo), \`question\` (d\xFAvida recorrente).
|
|
1847
|
+
|
|
1848
|
+
**Quando registrar insight:** em sil\xEAncio, ao perceber um desses sinais *reais* durante a aula \u2014 priorize \`difficulty\` (\xE9 o mais valioso pra adaptar as pr\xF3ximas li\xE7\xF5es). Use uma frase curta e espec\xEDfica (\u2264240 caracteres), no idioma do aluno. N\xE3o registre trivialidades nem repita o mesmo insight; no m\xE1ximo um ou dois por li\xE7\xE3o.
|
|
1849
|
+
|
|
1802
1850
|
Voc\xEA nunca menciona estes comandos ao aluno. Ele fala com VOC\xCA, n\xE3o com o CLI.`;
|
|
1803
1851
|
}
|
|
1804
1852
|
function renderHandlingSituations() {
|
|
@@ -1819,6 +1867,7 @@ function renderTechnicalReference() {
|
|
|
1819
1867
|
- Use \`--json\` em qualquer comando para sa\xEDda estruturada.
|
|
1820
1868
|
- \`tostudy validate\` retorna exit code 0 (aprovado) ou 1 (reprovado).
|
|
1821
1869
|
- \`tostudy validate --stdin\` aceita solu\xE7\xE3o via pipe.
|
|
1870
|
+
- \`tostudy insight <difficulty|breakthrough|question> "<texto>"\` persiste um insight na mem\xF3ria cold do aluno (dedup autom\xE1tico; falha non-fatal).
|
|
1822
1871
|
- \`tostudy lesson --json\` retorna \`{ type, title, content, hints, acceptanceCriteria }\`.
|
|
1823
1872
|
- \`tostudy progress --json\` retorna \`{ coursePercent, currentModule, currentLesson }\`.`;
|
|
1824
1873
|
}
|
|
@@ -1930,7 +1979,7 @@ var logger2;
|
|
|
1930
1979
|
var init_instruction_files = __esm({
|
|
1931
1980
|
"src/workspace/instruction-files.ts"() {
|
|
1932
1981
|
"use strict";
|
|
1933
|
-
|
|
1982
|
+
init_dist();
|
|
1934
1983
|
init_instruction_template_v3();
|
|
1935
1984
|
logger2 = createLogger("cli:instruction-files");
|
|
1936
1985
|
}
|
|
@@ -1939,6 +1988,72 @@ var init_instruction_files = __esm({
|
|
|
1939
1988
|
// src/commands/login.ts
|
|
1940
1989
|
import { Command } from "commander";
|
|
1941
1990
|
import { execFile as execFile2 } from "node:child_process";
|
|
1991
|
+
function assertTrustedApiUrl(apiUrl) {
|
|
1992
|
+
let url2;
|
|
1993
|
+
try {
|
|
1994
|
+
url2 = new URL(apiUrl);
|
|
1995
|
+
} catch {
|
|
1996
|
+
throw new Error(`API URL inv\xE1lida: ${apiUrl}`);
|
|
1997
|
+
}
|
|
1998
|
+
const host = url2.hostname.toLowerCase();
|
|
1999
|
+
const isLocalhost = host === "localhost" || host === "127.0.0.1" || host === "::1";
|
|
2000
|
+
const isToStudy = host === "tostudy.ai" || host.endsWith(".tostudy.ai");
|
|
2001
|
+
if (isToStudy && url2.protocol === "https:") return;
|
|
2002
|
+
if (isLocalhost && (url2.protocol === "https:" || url2.protocol === "http:")) return;
|
|
2003
|
+
throw new Error(
|
|
2004
|
+
`API URL n\xE3o confi\xE1vel: ${apiUrl}. Use https://tostudy.ai (ou um subdom\xEDnio) ou localhost.`
|
|
2005
|
+
);
|
|
2006
|
+
}
|
|
2007
|
+
async function persistSession(data, apiUrl) {
|
|
2008
|
+
await saveSession({
|
|
2009
|
+
token: data.token,
|
|
2010
|
+
refreshToken: data.refreshToken,
|
|
2011
|
+
sessionId: data.sessionId,
|
|
2012
|
+
userId: data.userId,
|
|
2013
|
+
userName: data.userName,
|
|
2014
|
+
expiresAt: data.expiresAt,
|
|
2015
|
+
apiUrl
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
async function loginWithCode(code, apiUrl) {
|
|
2019
|
+
assertTrustedApiUrl(apiUrl);
|
|
2020
|
+
const res = await fetch(`${apiUrl}/api/cli/auth/exchange`, {
|
|
2021
|
+
method: "POST",
|
|
2022
|
+
headers: { "Content-Type": "application/json" },
|
|
2023
|
+
body: JSON.stringify({ code, client: "cli" })
|
|
2024
|
+
});
|
|
2025
|
+
if (!res.ok) {
|
|
2026
|
+
const body = await res.json().catch(() => ({}));
|
|
2027
|
+
throw new Error(body.error ?? "Falha na autentica\xE7\xE3o");
|
|
2028
|
+
}
|
|
2029
|
+
const data = await res.json();
|
|
2030
|
+
await persistSession(data, apiUrl);
|
|
2031
|
+
return data;
|
|
2032
|
+
}
|
|
2033
|
+
async function loginWithMagicLink(magicLinkUrl, apiUrl) {
|
|
2034
|
+
assertTrustedApiUrl(apiUrl);
|
|
2035
|
+
let token2;
|
|
2036
|
+
try {
|
|
2037
|
+
token2 = new URL(magicLinkUrl).searchParams.get("token");
|
|
2038
|
+
} catch {
|
|
2039
|
+
throw new Error("URL de magic-link inv\xE1lida");
|
|
2040
|
+
}
|
|
2041
|
+
if (!token2) {
|
|
2042
|
+
throw new Error("Magic-link sem par\xE2metro token");
|
|
2043
|
+
}
|
|
2044
|
+
const res = await fetch(`${apiUrl}/api/cli/auth/exchange-magic-link`, {
|
|
2045
|
+
method: "POST",
|
|
2046
|
+
headers: { "Content-Type": "application/json" },
|
|
2047
|
+
body: JSON.stringify({ token: token2 })
|
|
2048
|
+
});
|
|
2049
|
+
if (!res.ok) {
|
|
2050
|
+
const body = await res.json().catch(() => ({}));
|
|
2051
|
+
throw new Error(body.error ?? "Falha na autentica\xE7\xE3o");
|
|
2052
|
+
}
|
|
2053
|
+
const data = await res.json();
|
|
2054
|
+
await persistSession(data, apiUrl);
|
|
2055
|
+
return data;
|
|
2056
|
+
}
|
|
1942
2057
|
function ideToPlatform(ideName) {
|
|
1943
2058
|
const lower = ideName.toLowerCase();
|
|
1944
2059
|
if (lower.includes("claude")) return "claude";
|
|
@@ -1952,7 +2067,7 @@ var logger3, DEFAULT_API_URL, PORT, loginCommand;
|
|
|
1952
2067
|
var init_login = __esm({
|
|
1953
2068
|
"src/commands/login.ts"() {
|
|
1954
2069
|
"use strict";
|
|
1955
|
-
|
|
2070
|
+
init_dist();
|
|
1956
2071
|
init_courses();
|
|
1957
2072
|
init_http();
|
|
1958
2073
|
init_oauth_server();
|
|
@@ -1961,8 +2076,30 @@ var init_login = __esm({
|
|
|
1961
2076
|
logger3 = createLogger("cli:login");
|
|
1962
2077
|
DEFAULT_API_URL = "https://tostudy.ai";
|
|
1963
2078
|
PORT = 9876;
|
|
1964
|
-
loginCommand = new Command("login").description("Autentica no ToStudy via browser").option("--manual", "Login manual (sem browser)").option("--api-url <url>", "API URL override", DEFAULT_API_URL).action(async (opts) => {
|
|
2079
|
+
loginCommand = new Command("login").description("Autentica no ToStudy via browser").option("--manual", "Login manual (sem browser)").option("--code <code>", "Login n\xE3o-interativo via c\xF3digo de autentica\xE7\xE3o").option("--magic-link <url>", "Login via URL de magic-link (recupera\xE7\xE3o)").option("--api-url <url>", "API URL override", DEFAULT_API_URL).action(async (opts) => {
|
|
1965
2080
|
const apiUrl = opts.apiUrl;
|
|
2081
|
+
if (opts.code) {
|
|
2082
|
+
try {
|
|
2083
|
+
const data = await loginWithCode(opts.code, apiUrl);
|
|
2084
|
+
console.log(`
|
|
2085
|
+
\u2713 Logado como ${data.userName}
|
|
2086
|
+
`);
|
|
2087
|
+
return;
|
|
2088
|
+
} catch (err) {
|
|
2089
|
+
error(err instanceof Error ? err.message : "Login falhou");
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
if (opts.magicLink) {
|
|
2093
|
+
try {
|
|
2094
|
+
const data = await loginWithMagicLink(opts.magicLink, apiUrl);
|
|
2095
|
+
console.log(`
|
|
2096
|
+
\u2713 Logado como ${data.userName}
|
|
2097
|
+
`);
|
|
2098
|
+
return;
|
|
2099
|
+
} catch (err) {
|
|
2100
|
+
error(err instanceof Error ? err.message : "Login falhou");
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
1966
2103
|
if (opts.manual) {
|
|
1967
2104
|
console.log(`
|
|
1968
2105
|
Acesse este endere\xE7o no seu browser:`);
|
|
@@ -2323,7 +2460,9 @@ var init_errors_pt_br = __esm({
|
|
|
2323
2460
|
logoutSuccess: "\n Deslogado com sucesso.\n",
|
|
2324
2461
|
workspaceCommandDescription: "Gerenciar workspace de estudo local",
|
|
2325
2462
|
workspaceSetupDescription: "Criar estrutura do workspace para o curso ativo",
|
|
2326
|
-
insufficientCredits: "\u274C Voc\xEA est\xE1 sem cr\xE9ditos. Cada resposta do tutor de IA consome cr\xE9ditos para cobrir o processamento. Recarregue em https://tostudy.ai/student/credits para continuar de onde parou.\n"
|
|
2463
|
+
insufficientCredits: "\u274C Voc\xEA est\xE1 sem cr\xE9ditos. Cada resposta do tutor de IA consome cr\xE9ditos para cobrir o processamento. Recarregue em https://tostudy.ai/student/credits para continuar de onde parou.\n",
|
|
2464
|
+
courseArchived: "Este curso foi arquivado e est\xE1 dispon\xEDvel somente para leitura.\nUse `tostudy lesson` para revisar o conte\xFAdo j\xE1 estudado.\n",
|
|
2465
|
+
enrollmentNotEntitled: "\u{1F6AB} Sua matr\xEDcula neste curso n\xE3o est\xE1 mais ativa (reembolso, cancelamento ou preview expirado).\nPara voltar a estudar, adquira o curso novamente em https://tostudy.ai.\n"
|
|
2327
2466
|
};
|
|
2328
2467
|
}
|
|
2329
2468
|
});
|
|
@@ -2341,7 +2480,9 @@ var init_errors_en_us = __esm({
|
|
|
2341
2480
|
logoutSuccess: "\n Logged out successfully.\n",
|
|
2342
2481
|
workspaceCommandDescription: "Manage local study workspace",
|
|
2343
2482
|
workspaceSetupDescription: "Create the workspace structure for the active course",
|
|
2344
|
-
insufficientCredits: "\u274C You're out of credits. Every reply from the AI tutor uses credits to cover processing. Top up at https://tostudy.ai/student/credits to continue from where you stopped.\n"
|
|
2483
|
+
insufficientCredits: "\u274C You're out of credits. Every reply from the AI tutor uses credits to cover processing. Top up at https://tostudy.ai/student/credits to continue from where you stopped.\n",
|
|
2484
|
+
courseArchived: "This course has been archived and is available for reading only.\nUse `tostudy lesson` to review the content you've already studied.\n",
|
|
2485
|
+
enrollmentNotEntitled: "\u{1F6AB} Your enrollment in this course is no longer active (refund, cancellation, or expired preview).\nTo study again, purchase the course at https://tostudy.ai.\n"
|
|
2345
2486
|
};
|
|
2346
2487
|
}
|
|
2347
2488
|
});
|
|
@@ -2373,6 +2514,14 @@ function isInsufficientCreditsError(err) {
|
|
|
2373
2514
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2374
2515
|
return msg.includes("INSUFFICIENT_CREDITS");
|
|
2375
2516
|
}
|
|
2517
|
+
function isCourseArchivedError(err) {
|
|
2518
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2519
|
+
return msg.includes("COURSE_ARCHIVED");
|
|
2520
|
+
}
|
|
2521
|
+
function isEnrollmentNotEntitledError(err) {
|
|
2522
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2523
|
+
return msg.includes("ENROLLMENT_NOT_ENTITLED");
|
|
2524
|
+
}
|
|
2376
2525
|
var BUNDLES, _cachedLocale;
|
|
2377
2526
|
var init_errors = __esm({
|
|
2378
2527
|
"src/errors/index.ts"() {
|
|
@@ -2569,7 +2718,7 @@ var CLI_VERSION;
|
|
|
2569
2718
|
var init_version = __esm({
|
|
2570
2719
|
"src/version.ts"() {
|
|
2571
2720
|
"use strict";
|
|
2572
|
-
CLI_VERSION = true ? "0.
|
|
2721
|
+
CLI_VERSION = true ? "0.12.0" : "0.7.1";
|
|
2573
2722
|
}
|
|
2574
2723
|
});
|
|
2575
2724
|
|
|
@@ -2583,16 +2732,9 @@ __export(update_checker_exports, {
|
|
|
2583
2732
|
});
|
|
2584
2733
|
import fs7 from "node:fs";
|
|
2585
2734
|
import path9 from "node:path";
|
|
2586
|
-
import os6 from "node:os";
|
|
2587
|
-
function getConfigDir2() {
|
|
2588
|
-
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2589
|
-
return path9.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2590
|
-
}
|
|
2591
|
-
return path9.join(os6.homedir(), ".tostudy");
|
|
2592
|
-
}
|
|
2593
2735
|
function readCache() {
|
|
2594
2736
|
try {
|
|
2595
|
-
const p = path9.join(
|
|
2737
|
+
const p = path9.join(getConfigDir(), CACHE_FILE);
|
|
2596
2738
|
if (!fs7.existsSync(p)) return null;
|
|
2597
2739
|
return JSON.parse(fs7.readFileSync(p, "utf-8"));
|
|
2598
2740
|
} catch {
|
|
@@ -2601,7 +2743,7 @@ function readCache() {
|
|
|
2601
2743
|
}
|
|
2602
2744
|
function writeCache(cache) {
|
|
2603
2745
|
try {
|
|
2604
|
-
const dir =
|
|
2746
|
+
const dir = getConfigDir();
|
|
2605
2747
|
fs7.mkdirSync(dir, { recursive: true });
|
|
2606
2748
|
fs7.writeFileSync(path9.join(dir, CACHE_FILE), JSON.stringify(cache));
|
|
2607
2749
|
} catch {
|
|
@@ -2664,6 +2806,7 @@ var PACKAGE_NAME, CACHE_FILE, CHECK_INTERVAL_MS, REGISTRY_TIMEOUT_MS;
|
|
|
2664
2806
|
var init_update_checker = __esm({
|
|
2665
2807
|
"src/update-checker.ts"() {
|
|
2666
2808
|
"use strict";
|
|
2809
|
+
init_config_dir();
|
|
2667
2810
|
PACKAGE_NAME = "@tostudy-ai/cli";
|
|
2668
2811
|
CACHE_FILE = "update-check.json";
|
|
2669
2812
|
CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2673,19 +2816,12 @@ var init_update_checker = __esm({
|
|
|
2673
2816
|
|
|
2674
2817
|
// src/learner-brief/cache.ts
|
|
2675
2818
|
import fs8 from "node:fs";
|
|
2676
|
-
import os7 from "node:os";
|
|
2677
2819
|
import path10 from "node:path";
|
|
2678
|
-
function getDefaultConfigDir() {
|
|
2679
|
-
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2680
|
-
return path10.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2681
|
-
}
|
|
2682
|
-
return path10.join(os7.homedir(), ".tostudy");
|
|
2683
|
-
}
|
|
2684
2820
|
function resolveCachePath(configDir) {
|
|
2685
2821
|
return path10.join(configDir, "student-brief.json");
|
|
2686
2822
|
}
|
|
2687
2823
|
async function readBriefCache(configDir) {
|
|
2688
|
-
const dir = configDir ??
|
|
2824
|
+
const dir = configDir ?? getConfigDir();
|
|
2689
2825
|
const p = resolveCachePath(dir);
|
|
2690
2826
|
if (!fs8.existsSync(p)) return null;
|
|
2691
2827
|
try {
|
|
@@ -2696,26 +2832,20 @@ async function readBriefCache(configDir) {
|
|
|
2696
2832
|
}
|
|
2697
2833
|
}
|
|
2698
2834
|
async function writeBriefCache(configDir, cache) {
|
|
2699
|
-
const dir = configDir ??
|
|
2835
|
+
const dir = configDir ?? getConfigDir();
|
|
2700
2836
|
fs8.mkdirSync(dir, { recursive: true });
|
|
2701
2837
|
fs8.writeFileSync(resolveCachePath(dir), JSON.stringify(cache, null, 2), { mode: 384 });
|
|
2702
2838
|
}
|
|
2703
2839
|
var init_cache = __esm({
|
|
2704
2840
|
"src/learner-brief/cache.ts"() {
|
|
2705
2841
|
"use strict";
|
|
2842
|
+
init_config_dir();
|
|
2706
2843
|
}
|
|
2707
2844
|
});
|
|
2708
2845
|
|
|
2709
2846
|
// src/tutor-persona/cache.ts
|
|
2710
2847
|
import fs9 from "node:fs";
|
|
2711
|
-
import os8 from "node:os";
|
|
2712
2848
|
import path11 from "node:path";
|
|
2713
|
-
function getDefaultConfigDir2() {
|
|
2714
|
-
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2715
|
-
return path11.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2716
|
-
}
|
|
2717
|
-
return path11.join(os8.homedir(), ".tostudy");
|
|
2718
|
-
}
|
|
2719
2849
|
function resolveCachePath2(configDir) {
|
|
2720
2850
|
return path11.join(configDir, "tutor-personalities.json");
|
|
2721
2851
|
}
|
|
@@ -2733,12 +2863,12 @@ function writeAll(configDir, cache) {
|
|
|
2733
2863
|
fs9.writeFileSync(resolveCachePath2(configDir), JSON.stringify(cache, null, 2), { mode: 384 });
|
|
2734
2864
|
}
|
|
2735
2865
|
async function readPersonaCacheForCourse(configDir, courseId) {
|
|
2736
|
-
const dir = configDir ??
|
|
2866
|
+
const dir = configDir ?? getConfigDir();
|
|
2737
2867
|
const all = readAll(dir);
|
|
2738
2868
|
return all[courseId] ?? null;
|
|
2739
2869
|
}
|
|
2740
2870
|
async function writePersonaCacheForCourse(configDir, courseId, entry) {
|
|
2741
|
-
const dir = configDir ??
|
|
2871
|
+
const dir = configDir ?? getConfigDir();
|
|
2742
2872
|
const all = readAll(dir);
|
|
2743
2873
|
all[courseId] = entry;
|
|
2744
2874
|
writeAll(dir, all);
|
|
@@ -2746,6 +2876,7 @@ async function writePersonaCacheForCourse(configDir, courseId, entry) {
|
|
|
2746
2876
|
var init_cache2 = __esm({
|
|
2747
2877
|
"src/tutor-persona/cache.ts"() {
|
|
2748
2878
|
"use strict";
|
|
2879
|
+
init_config_dir();
|
|
2749
2880
|
}
|
|
2750
2881
|
});
|
|
2751
2882
|
|
|
@@ -2966,7 +3097,7 @@ var logger4, coursesCommand;
|
|
|
2966
3097
|
var init_courses2 = __esm({
|
|
2967
3098
|
"src/commands/courses.ts"() {
|
|
2968
3099
|
"use strict";
|
|
2969
|
-
|
|
3100
|
+
init_dist();
|
|
2970
3101
|
init_courses();
|
|
2971
3102
|
init_http();
|
|
2972
3103
|
init_guards();
|
|
@@ -3002,7 +3133,7 @@ var init_courses2 = __esm({
|
|
|
3002
3133
|
// src/workspace/resolve.ts
|
|
3003
3134
|
import fs10 from "node:fs/promises";
|
|
3004
3135
|
import path12 from "node:path";
|
|
3005
|
-
import
|
|
3136
|
+
import os6 from "node:os";
|
|
3006
3137
|
function courseSlug(title) {
|
|
3007
3138
|
return title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
3008
3139
|
}
|
|
@@ -3033,7 +3164,7 @@ async function resolveCwdWorkspacePath(cwd = process.cwd()) {
|
|
|
3033
3164
|
return null;
|
|
3034
3165
|
}
|
|
3035
3166
|
}
|
|
3036
|
-
async function findCwdWorkspaceUpwards(startCwd = process.cwd(), homeDir =
|
|
3167
|
+
async function findCwdWorkspaceUpwards(startCwd = process.cwd(), homeDir = os6.homedir()) {
|
|
3037
3168
|
const home = path12.resolve(homeDir);
|
|
3038
3169
|
let current = path12.resolve(startCwd);
|
|
3039
3170
|
while (true) {
|
|
@@ -3064,7 +3195,7 @@ async function findExistingVault(workspacePath, slug) {
|
|
|
3064
3195
|
return null;
|
|
3065
3196
|
}
|
|
3066
3197
|
}
|
|
3067
|
-
async function resolveEffectiveWorkspace(courseTitle, storedPath, cwd = process.cwd(), defaultBasePath = DEFAULT_BASE, homeDir =
|
|
3198
|
+
async function resolveEffectiveWorkspace(courseTitle, storedPath, cwd = process.cwd(), defaultBasePath = DEFAULT_BASE, homeDir = os6.homedir()) {
|
|
3068
3199
|
const cwdWorkspace = await findCwdWorkspaceUpwards(cwd, homeDir);
|
|
3069
3200
|
if (cwdWorkspace) {
|
|
3070
3201
|
return { found: true, workspacePath: cwdWorkspace, source: "cwd" };
|
|
@@ -3086,7 +3217,7 @@ var DEFAULT_BASE;
|
|
|
3086
3217
|
var init_resolve = __esm({
|
|
3087
3218
|
"src/workspace/resolve.ts"() {
|
|
3088
3219
|
"use strict";
|
|
3089
|
-
DEFAULT_BASE = path12.join(
|
|
3220
|
+
DEFAULT_BASE = path12.join(os6.homedir(), "study");
|
|
3090
3221
|
}
|
|
3091
3222
|
});
|
|
3092
3223
|
|
|
@@ -3115,31 +3246,15 @@ var init_status = __esm({
|
|
|
3115
3246
|
});
|
|
3116
3247
|
|
|
3117
3248
|
// src/learner-brief/api.ts
|
|
3118
|
-
async function apiFetch2(url2, token2, init) {
|
|
3119
|
-
const response = await fetch(url2, {
|
|
3120
|
-
method: init?.method ?? "GET",
|
|
3121
|
-
body: init?.body,
|
|
3122
|
-
headers: {
|
|
3123
|
-
"Content-Type": "application/json",
|
|
3124
|
-
Authorization: `Bearer ${token2}`,
|
|
3125
|
-
...init?.headers ?? {}
|
|
3126
|
-
}
|
|
3127
|
-
});
|
|
3128
|
-
const body = await response.json();
|
|
3129
|
-
if (!response.ok) {
|
|
3130
|
-
throw new CliApiError(body.error ?? `API error ${response.status}`, response.status);
|
|
3131
|
-
}
|
|
3132
|
-
return body;
|
|
3133
|
-
}
|
|
3134
3249
|
async function fetchLearnerBrief(input2) {
|
|
3135
|
-
const response = await
|
|
3250
|
+
const response = await cliApiFetch(
|
|
3136
3251
|
`${input2.apiUrl}/api/cli/student/learner-brief`,
|
|
3137
3252
|
input2.token
|
|
3138
3253
|
);
|
|
3139
3254
|
return response.brief;
|
|
3140
3255
|
}
|
|
3141
3256
|
async function upsertLearnerBrief(input2) {
|
|
3142
|
-
const response = await
|
|
3257
|
+
const response = await cliApiFetch(
|
|
3143
3258
|
`${input2.apiUrl}/api/cli/student/learner-brief`,
|
|
3144
3259
|
input2.token,
|
|
3145
3260
|
{
|
|
@@ -3250,32 +3365,17 @@ var init_api2 = __esm({
|
|
|
3250
3365
|
});
|
|
3251
3366
|
|
|
3252
3367
|
// src/onboarding/api.ts
|
|
3253
|
-
async function apiFetch3(url2, token2, init) {
|
|
3254
|
-
const response = await fetch(url2, {
|
|
3255
|
-
...init,
|
|
3256
|
-
headers: {
|
|
3257
|
-
"Content-Type": "application/json",
|
|
3258
|
-
Authorization: `Bearer ${token2}`,
|
|
3259
|
-
...init?.headers
|
|
3260
|
-
}
|
|
3261
|
-
});
|
|
3262
|
-
const body = await response.json();
|
|
3263
|
-
if (!response.ok) {
|
|
3264
|
-
throw new CliApiError(body.error ?? `API error ${response.status}`, response.status);
|
|
3265
|
-
}
|
|
3266
|
-
return body;
|
|
3267
|
-
}
|
|
3268
3368
|
async function getRemoteEnrollmentOnboarding(input2) {
|
|
3269
3369
|
const url2 = new URL(`${input2.apiUrl}/api/cli/onboarding`);
|
|
3270
3370
|
url2.searchParams.set("enrollmentId", input2.enrollmentId);
|
|
3271
|
-
const response = await
|
|
3371
|
+
const response = await cliApiFetch(
|
|
3272
3372
|
url2.toString(),
|
|
3273
3373
|
input2.token
|
|
3274
3374
|
);
|
|
3275
3375
|
return response.onboarding;
|
|
3276
3376
|
}
|
|
3277
3377
|
async function saveRemoteEnrollmentOnboarding(input2) {
|
|
3278
|
-
const response = await
|
|
3378
|
+
const response = await cliApiFetch(
|
|
3279
3379
|
`${input2.apiUrl}/api/cli/onboarding`,
|
|
3280
3380
|
input2.token,
|
|
3281
3381
|
{
|
|
@@ -3450,7 +3550,7 @@ var logger5, defaultDeps2;
|
|
|
3450
3550
|
var init_instruction_pipeline = __esm({
|
|
3451
3551
|
"src/instruction-pipeline.ts"() {
|
|
3452
3552
|
"use strict";
|
|
3453
|
-
|
|
3553
|
+
init_dist();
|
|
3454
3554
|
init_workspace_marker();
|
|
3455
3555
|
init_workspace_state();
|
|
3456
3556
|
init_api();
|
|
@@ -3554,7 +3654,7 @@ var logger6;
|
|
|
3554
3654
|
var init_pipeline_deps = __esm({
|
|
3555
3655
|
"src/commands/_shared/pipeline-deps.ts"() {
|
|
3556
3656
|
"use strict";
|
|
3557
|
-
|
|
3657
|
+
init_dist();
|
|
3558
3658
|
init_courses();
|
|
3559
3659
|
init_http();
|
|
3560
3660
|
init_instruction_pipeline();
|
|
@@ -3565,18 +3665,19 @@ var init_pipeline_deps = __esm({
|
|
|
3565
3665
|
|
|
3566
3666
|
// src/commands/select.ts
|
|
3567
3667
|
import { Command as Command6 } from "commander";
|
|
3568
|
-
import
|
|
3668
|
+
import os7 from "node:os";
|
|
3569
3669
|
var logger7, selectCommand;
|
|
3570
3670
|
var init_select = __esm({
|
|
3571
3671
|
"src/commands/select.ts"() {
|
|
3572
3672
|
"use strict";
|
|
3573
|
-
|
|
3673
|
+
init_dist();
|
|
3574
3674
|
init_courses();
|
|
3575
3675
|
init_http();
|
|
3576
3676
|
init_guards();
|
|
3577
3677
|
init_workspace_marker();
|
|
3578
3678
|
init_resolve();
|
|
3579
3679
|
init_formatter();
|
|
3680
|
+
init_errors();
|
|
3580
3681
|
init_status();
|
|
3581
3682
|
init_instruction_pipeline();
|
|
3582
3683
|
init_pipeline_deps();
|
|
@@ -3649,7 +3750,7 @@ var init_select = __esm({
|
|
|
3649
3750
|
);
|
|
3650
3751
|
} else {
|
|
3651
3752
|
const slashCmd = courseSlug2 ? `/tostudy-${courseSlug2}` : "/tostudy";
|
|
3652
|
-
const home =
|
|
3753
|
+
const home = os7.homedir();
|
|
3653
3754
|
const cwd = process.cwd();
|
|
3654
3755
|
const namespacedPath = `${cwd}/.tostudy`;
|
|
3655
3756
|
let wsLine;
|
|
@@ -3684,6 +3785,10 @@ var init_select = __esm({
|
|
|
3684
3785
|
output(lines.join("\n"), { json: false });
|
|
3685
3786
|
}
|
|
3686
3787
|
} catch (err) {
|
|
3788
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
3789
|
+
process.stderr.write(getErrors().enrollmentNotEntitled);
|
|
3790
|
+
process.exit(1);
|
|
3791
|
+
}
|
|
3687
3792
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3688
3793
|
error(msg);
|
|
3689
3794
|
}
|
|
@@ -3697,12 +3802,13 @@ var logger8, progressCommand;
|
|
|
3697
3802
|
var init_progress = __esm({
|
|
3698
3803
|
"src/commands/progress.ts"() {
|
|
3699
3804
|
"use strict";
|
|
3700
|
-
|
|
3805
|
+
init_dist();
|
|
3701
3806
|
init_courses();
|
|
3702
3807
|
init_http();
|
|
3703
3808
|
init_guards();
|
|
3704
3809
|
init_course_state();
|
|
3705
3810
|
init_formatter();
|
|
3811
|
+
init_errors();
|
|
3706
3812
|
logger8 = createLogger("cli:progress");
|
|
3707
3813
|
progressCommand = new Command7("progress").description("Show your progress in the active course").option("--json", "Output structured JSON").action(async (opts) => {
|
|
3708
3814
|
try {
|
|
@@ -3719,6 +3825,10 @@ var init_progress = __esm({
|
|
|
3719
3825
|
output(formatProgress(progress3), { json: false });
|
|
3720
3826
|
}
|
|
3721
3827
|
} catch (err) {
|
|
3828
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
3829
|
+
process.stderr.write(getErrors().enrollmentNotEntitled);
|
|
3830
|
+
process.exit(1);
|
|
3831
|
+
}
|
|
3722
3832
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3723
3833
|
error(msg);
|
|
3724
3834
|
}
|
|
@@ -5272,7 +5382,7 @@ var init_query_promise = __esm({
|
|
|
5272
5382
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
5273
5383
|
const nullifyMap = {};
|
|
5274
5384
|
const result = columns.reduce(
|
|
5275
|
-
(result2, { path:
|
|
5385
|
+
(result2, { path: path23, field }, columnIndex) => {
|
|
5276
5386
|
let decoder;
|
|
5277
5387
|
if (is(field, Column)) {
|
|
5278
5388
|
decoder = field;
|
|
@@ -5284,8 +5394,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
5284
5394
|
decoder = field.sql.decoder;
|
|
5285
5395
|
}
|
|
5286
5396
|
let node = result2;
|
|
5287
|
-
for (const [pathChunkIndex, pathChunk] of
|
|
5288
|
-
if (pathChunkIndex <
|
|
5397
|
+
for (const [pathChunkIndex, pathChunk] of path23.entries()) {
|
|
5398
|
+
if (pathChunkIndex < path23.length - 1) {
|
|
5289
5399
|
if (!(pathChunk in node)) {
|
|
5290
5400
|
node[pathChunk] = {};
|
|
5291
5401
|
}
|
|
@@ -5293,8 +5403,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
5293
5403
|
} else {
|
|
5294
5404
|
const rawValue = row[columnIndex];
|
|
5295
5405
|
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
5296
|
-
if (joinsNotNullableMap && is(field, Column) &&
|
|
5297
|
-
const objectName =
|
|
5406
|
+
if (joinsNotNullableMap && is(field, Column) && path23.length === 2) {
|
|
5407
|
+
const objectName = path23[0];
|
|
5298
5408
|
if (!(objectName in nullifyMap)) {
|
|
5299
5409
|
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
5300
5410
|
} else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
@@ -9241,13 +9351,13 @@ function Subscribe(postgres2, options) {
|
|
|
9241
9351
|
}
|
|
9242
9352
|
}
|
|
9243
9353
|
function handle(a, b2) {
|
|
9244
|
-
const
|
|
9354
|
+
const path23 = b2.relation.schema + "." + b2.relation.table;
|
|
9245
9355
|
call("*", a, b2);
|
|
9246
|
-
call("*:" +
|
|
9247
|
-
b2.relation.keys.length && call("*:" +
|
|
9356
|
+
call("*:" + path23, a, b2);
|
|
9357
|
+
b2.relation.keys.length && call("*:" + path23 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
|
|
9248
9358
|
call(b2.command, a, b2);
|
|
9249
|
-
call(b2.command + ":" +
|
|
9250
|
-
b2.relation.keys.length && call(b2.command + ":" +
|
|
9359
|
+
call(b2.command + ":" + path23, a, b2);
|
|
9360
|
+
b2.relation.keys.length && call(b2.command + ":" + path23 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
|
|
9251
9361
|
}
|
|
9252
9362
|
function pong() {
|
|
9253
9363
|
const x2 = Buffer.alloc(34);
|
|
@@ -9360,8 +9470,8 @@ function parseEvent(x) {
|
|
|
9360
9470
|
const xs = x.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i) || [];
|
|
9361
9471
|
if (!xs)
|
|
9362
9472
|
throw new Error("Malformed subscribe pattern: " + x);
|
|
9363
|
-
const [, command,
|
|
9364
|
-
return (command || "*") + (
|
|
9473
|
+
const [, command, path23, key] = xs;
|
|
9474
|
+
return (command || "*") + (path23 ? ":" + (path23.indexOf(".") === -1 ? "public." + path23 : path23) : "") + (key ? "=" + key : "");
|
|
9365
9475
|
}
|
|
9366
9476
|
var noop2;
|
|
9367
9477
|
var init_subscribe = __esm({
|
|
@@ -9442,7 +9552,7 @@ var init_large = __esm({
|
|
|
9442
9552
|
});
|
|
9443
9553
|
|
|
9444
9554
|
// ../../node_modules/postgres/src/index.js
|
|
9445
|
-
import
|
|
9555
|
+
import os8 from "os";
|
|
9446
9556
|
import fs11 from "fs";
|
|
9447
9557
|
function Postgres(a, b2) {
|
|
9448
9558
|
const options = parseOptions(a, b2), subscribe = options.no_subscribe || Subscribe(Postgres, { ...options });
|
|
@@ -9499,10 +9609,10 @@ function Postgres(a, b2) {
|
|
|
9499
9609
|
});
|
|
9500
9610
|
return query;
|
|
9501
9611
|
}
|
|
9502
|
-
function file2(
|
|
9612
|
+
function file2(path23, args = [], options2 = {}) {
|
|
9503
9613
|
arguments.length === 2 && !Array.isArray(args) && (options2 = args, args = []);
|
|
9504
9614
|
const query = new Query([], args, (query2) => {
|
|
9505
|
-
fs11.readFile(
|
|
9615
|
+
fs11.readFile(path23, "utf8", (err, string4) => {
|
|
9506
9616
|
if (err)
|
|
9507
9617
|
return query2.reject(err);
|
|
9508
9618
|
query2.strings = [string4];
|
|
@@ -9820,13 +9930,13 @@ function parseUrl(url2) {
|
|
|
9820
9930
|
}
|
|
9821
9931
|
function osUsername() {
|
|
9822
9932
|
try {
|
|
9823
|
-
return
|
|
9933
|
+
return os8.userInfo().username;
|
|
9824
9934
|
} catch (_) {
|
|
9825
9935
|
return process.env.USERNAME || process.env.USER || process.env.LOGNAME;
|
|
9826
9936
|
}
|
|
9827
9937
|
}
|
|
9828
9938
|
var src_default;
|
|
9829
|
-
var
|
|
9939
|
+
var init_src = __esm({
|
|
9830
9940
|
"../../node_modules/postgres/src/index.js"() {
|
|
9831
9941
|
init_types();
|
|
9832
9942
|
init_connection();
|
|
@@ -14081,12 +14191,12 @@ var init_session2 = __esm({
|
|
|
14081
14191
|
init_tracing();
|
|
14082
14192
|
init_utils();
|
|
14083
14193
|
PostgresJsPreparedQuery = class extends PgPreparedQuery {
|
|
14084
|
-
constructor(client, queryString, params,
|
|
14194
|
+
constructor(client, queryString, params, logger33, cache, queryMetadata, cacheConfig, fields, _isResponseInArrayMode, customResultMapper) {
|
|
14085
14195
|
super({ sql: queryString, params }, cache, queryMetadata, cacheConfig);
|
|
14086
14196
|
this.client = client;
|
|
14087
14197
|
this.queryString = queryString;
|
|
14088
14198
|
this.params = params;
|
|
14089
|
-
this.logger =
|
|
14199
|
+
this.logger = logger33;
|
|
14090
14200
|
this.fields = fields;
|
|
14091
14201
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
14092
14202
|
this.customResultMapper = customResultMapper;
|
|
@@ -14227,11 +14337,11 @@ function construct(client, config2 = {}) {
|
|
|
14227
14337
|
client.options.serializers["114"] = transparentParser;
|
|
14228
14338
|
client.options.serializers["3802"] = transparentParser;
|
|
14229
14339
|
const dialect = new PgDialect({ casing: config2.casing });
|
|
14230
|
-
let
|
|
14340
|
+
let logger33;
|
|
14231
14341
|
if (config2.logger === true) {
|
|
14232
|
-
|
|
14342
|
+
logger33 = new DefaultLogger();
|
|
14233
14343
|
} else if (config2.logger !== false) {
|
|
14234
|
-
|
|
14344
|
+
logger33 = config2.logger;
|
|
14235
14345
|
}
|
|
14236
14346
|
let schema;
|
|
14237
14347
|
if (config2.schema) {
|
|
@@ -14245,7 +14355,7 @@ function construct(client, config2 = {}) {
|
|
|
14245
14355
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
14246
14356
|
};
|
|
14247
14357
|
}
|
|
14248
|
-
const session = new PostgresJsSession(client, dialect, schema, { logger:
|
|
14358
|
+
const session = new PostgresJsSession(client, dialect, schema, { logger: logger33, cache: config2.cache });
|
|
14249
14359
|
const db2 = new PostgresJsDatabase(dialect, session, schema);
|
|
14250
14360
|
db2.$client = client;
|
|
14251
14361
|
db2.$cache = config2.cache;
|
|
@@ -14275,7 +14385,7 @@ function drizzle(...params) {
|
|
|
14275
14385
|
var PostgresJsDatabase;
|
|
14276
14386
|
var init_driver = __esm({
|
|
14277
14387
|
"../../node_modules/drizzle-orm/postgres-js/driver.js"() {
|
|
14278
|
-
|
|
14388
|
+
init_src();
|
|
14279
14389
|
init_entity();
|
|
14280
14390
|
init_logger();
|
|
14281
14391
|
init_db();
|
|
@@ -14560,10 +14670,10 @@ function mergeDefs(...defs) {
|
|
|
14560
14670
|
function cloneDef(schema) {
|
|
14561
14671
|
return mergeDefs(schema._zod.def);
|
|
14562
14672
|
}
|
|
14563
|
-
function getElementAtPath(obj,
|
|
14564
|
-
if (!
|
|
14673
|
+
function getElementAtPath(obj, path23) {
|
|
14674
|
+
if (!path23)
|
|
14565
14675
|
return obj;
|
|
14566
|
-
return
|
|
14676
|
+
return path23.reduce((acc, key) => acc?.[key], obj);
|
|
14567
14677
|
}
|
|
14568
14678
|
function promiseAllObject(promisesObj) {
|
|
14569
14679
|
const keys = Object.keys(promisesObj);
|
|
@@ -14875,11 +14985,11 @@ function aborted(x, startIndex = 0) {
|
|
|
14875
14985
|
}
|
|
14876
14986
|
return false;
|
|
14877
14987
|
}
|
|
14878
|
-
function prefixIssues(
|
|
14988
|
+
function prefixIssues(path23, issues) {
|
|
14879
14989
|
return issues.map((iss) => {
|
|
14880
14990
|
var _a2;
|
|
14881
14991
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
14882
|
-
iss.path.unshift(
|
|
14992
|
+
iss.path.unshift(path23);
|
|
14883
14993
|
return iss;
|
|
14884
14994
|
});
|
|
14885
14995
|
}
|
|
@@ -15121,7 +15231,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
|
|
|
15121
15231
|
}
|
|
15122
15232
|
function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
15123
15233
|
const result = { errors: [] };
|
|
15124
|
-
const processError = (error50,
|
|
15234
|
+
const processError = (error50, path23 = []) => {
|
|
15125
15235
|
var _a2, _b;
|
|
15126
15236
|
for (const issue2 of error50.issues) {
|
|
15127
15237
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -15131,7 +15241,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
15131
15241
|
} else if (issue2.code === "invalid_element") {
|
|
15132
15242
|
processError({ issues: issue2.issues }, issue2.path);
|
|
15133
15243
|
} else {
|
|
15134
|
-
const fullpath = [...
|
|
15244
|
+
const fullpath = [...path23, ...issue2.path];
|
|
15135
15245
|
if (fullpath.length === 0) {
|
|
15136
15246
|
result.errors.push(mapper(issue2));
|
|
15137
15247
|
continue;
|
|
@@ -15163,8 +15273,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
15163
15273
|
}
|
|
15164
15274
|
function toDotPath(_path) {
|
|
15165
15275
|
const segs = [];
|
|
15166
|
-
const
|
|
15167
|
-
for (const seg of
|
|
15276
|
+
const path23 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
15277
|
+
for (const seg of path23) {
|
|
15168
15278
|
if (typeof seg === "number")
|
|
15169
15279
|
segs.push(`[${seg}]`);
|
|
15170
15280
|
else if (typeof seg === "symbol")
|
|
@@ -27858,13 +27968,13 @@ function resolveRef(ref, ctx) {
|
|
|
27858
27968
|
if (!ref.startsWith("#")) {
|
|
27859
27969
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
27860
27970
|
}
|
|
27861
|
-
const
|
|
27862
|
-
if (
|
|
27971
|
+
const path23 = ref.slice(1).split("/").filter(Boolean);
|
|
27972
|
+
if (path23.length === 0) {
|
|
27863
27973
|
return ctx.rootSchema;
|
|
27864
27974
|
}
|
|
27865
27975
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
27866
|
-
if (
|
|
27867
|
-
const key =
|
|
27976
|
+
if (path23[0] === defsKey) {
|
|
27977
|
+
const key = path23[1];
|
|
27868
27978
|
if (!key || !ctx.defs[key]) {
|
|
27869
27979
|
throw new Error(`Reference not found: ${ref}`);
|
|
27870
27980
|
}
|
|
@@ -28629,6 +28739,7 @@ var init_users = __esm({
|
|
|
28629
28739
|
"../../packages/database/src/schema/users.ts"() {
|
|
28630
28740
|
"use strict";
|
|
28631
28741
|
init_pg_core();
|
|
28742
|
+
init_drizzle_orm();
|
|
28632
28743
|
userRoleEnum = pgEnum("user_role", [
|
|
28633
28744
|
"student",
|
|
28634
28745
|
"creator_provisional",
|
|
@@ -28676,7 +28787,7 @@ var init_users = __esm({
|
|
|
28676
28787
|
photoUrl: text("photo_url"),
|
|
28677
28788
|
// Cloudflare R2 URL for custom uploaded photo
|
|
28678
28789
|
studentRole: studentRoleEnum("student_role"),
|
|
28679
|
-
//
|
|
28790
|
+
// learner self-id, any role may set it (GH #657 — calibrates exercise difficulty): PM, Developer, Designer, Manager, Outros
|
|
28680
28791
|
referralSource: varchar("referral_source", { length: 50 }),
|
|
28681
28792
|
// How the user heard about tostudy (optional, for attribution)
|
|
28682
28793
|
expertise: varchar("expertise", { length: 200 }),
|
|
@@ -28791,7 +28902,12 @@ var init_users = __esm({
|
|
|
28791
28902
|
externalIdIdx: index("idx_users_external_id").on(
|
|
28792
28903
|
table.provisioningSource,
|
|
28793
28904
|
table.externalUserId
|
|
28794
|
-
)
|
|
28905
|
+
),
|
|
28906
|
+
// Partial UNIQUE guard (migration 0015): prevents two concurrent paris
|
|
28907
|
+
// provisioning inserts with the same external_user_id from creating two
|
|
28908
|
+
// distinct users. Partial (WHERE provisioning_source IS NOT NULL) so it
|
|
28909
|
+
// never conflicts with self-service users whose provisioning_source is null.
|
|
28910
|
+
uniqueParisProvisioningIdx: uniqueIndex("idx_unique_paris_provisioning").on(table.provisioningSource, table.externalUserId).where(sql`${table.provisioningSource} IS NOT NULL`)
|
|
28795
28911
|
})
|
|
28796
28912
|
);
|
|
28797
28913
|
}
|
|
@@ -28932,6 +29048,14 @@ var init_user_preferences = __esm({
|
|
|
28932
29048
|
emailNewReplies: boolean("email_new_replies").default(true).notNull(),
|
|
28933
29049
|
/** Whether user wants push notifications for mentorship (via MCP) */
|
|
28934
29050
|
pushMentoria: boolean("push_mentoria").default(true).notNull(),
|
|
29051
|
+
// Marketing email preferences (FEAT-1285)
|
|
29052
|
+
/**
|
|
29053
|
+
* Whether user wants marketing/nurture emails (day-3/day-7 nurture,
|
|
29054
|
+
* course recommendations). Defaults true (opt-out) to preserve the
|
|
29055
|
+
* pre-existing behavior where these sends were gated only by the
|
|
29056
|
+
* `emailNotifications` master toggle.
|
|
29057
|
+
*/
|
|
29058
|
+
marketingEmails: boolean("marketing_emails").default(true).notNull(),
|
|
28935
29059
|
// i18n nickname pilot column (dogfooding)
|
|
28936
29060
|
nicknameI18n: jsonb("nickname_i18n").$type(),
|
|
28937
29061
|
// Timestamps
|
|
@@ -29194,7 +29318,6 @@ var init_courses3 = __esm({
|
|
|
29194
29318
|
tags: jsonb("tags").$type().default([]).notNull(),
|
|
29195
29319
|
// Search tags: ['agent', 'mcp', 'automation', 'claude-code']
|
|
29196
29320
|
categoryId: uuid("category_id").references(() => courseCategories.id, { onDelete: "set null" }),
|
|
29197
|
-
enrollmentCount: integer("enrollment_count").default(0).notNull(),
|
|
29198
29321
|
thumbnailUrl: varchar("thumbnail_url", { length: 500 }),
|
|
29199
29322
|
videoIntroUrl: varchar("video_intro_url", { length: 500 }),
|
|
29200
29323
|
// Story 10.8: Video upload integration
|
|
@@ -29299,8 +29422,6 @@ var init_courses3 = __esm({
|
|
|
29299
29422
|
// B-tree index for essential course filter
|
|
29300
29423
|
createdAtIdx: index("courses_created_at_idx").on(table.createdAt),
|
|
29301
29424
|
// B-tree index for newest sort
|
|
29302
|
-
enrollmentCountIdx: index("courses_enrollment_count_idx").on(table.enrollmentCount),
|
|
29303
|
-
// B-tree for best-sellers sort
|
|
29304
29425
|
// Story 11.1: Curadoria queue sorting and filtering indexes
|
|
29305
29426
|
statusIdx: index("courses_status_idx").on(table.status),
|
|
29306
29427
|
// B-tree for status filtering
|
|
@@ -29644,6 +29765,18 @@ var init_credit_wallets = __esm({
|
|
|
29644
29765
|
walletCreatedAtIdx: index("cwt_wallet_created_at_idx").on(table.walletId, table.createdAt),
|
|
29645
29766
|
walletTypeIdx: index("cwt_wallet_type_idx").on(table.walletId, table.type),
|
|
29646
29767
|
referenceIdx: index("cwt_reference_idx").on(table.referenceId, table.referenceType),
|
|
29768
|
+
// TASK-1841 (GH #712 follow-up): partial UNIQUE closes the residual
|
|
29769
|
+
// concurrency window in ClawbackCourseSaleCreditUseCase — two distinct
|
|
29770
|
+
// `charge.refunded` deliveries for the same enrollment can both pass the
|
|
29771
|
+
// in-tx idempotency check before either commits (read committed never sees
|
|
29772
|
+
// the other's uncommitted insert), producing a double `refund_debit`. The
|
|
29773
|
+
// index makes the DB the final arbiter; the use-case catches 23505 as an
|
|
29774
|
+
// idempotent skip. Scoped to reference_type='enrollment' ONLY: RefundBooking
|
|
29775
|
+
// also writes `refund_debit` (reference_type='booking') with no idempotency
|
|
29776
|
+
// guard, so a general `type='refund_debit'` index could 23505 a legitimate
|
|
29777
|
+
// re-booking refund. Raw `sql` literal (not eq()) to dodge the drizzle-kit
|
|
29778
|
+
// `$N` placeholder DDL bug — see packages/database/AGENTS.md.
|
|
29779
|
+
refundDebitEnrollmentUnique: uniqueIndex("cwt_refund_debit_enrollment_unique").on(table.referenceId, table.referenceType, table.type).where(sql`${table.type} = 'refund_debit' AND ${table.referenceType} = 'enrollment'`),
|
|
29647
29780
|
referenceTypeCheck: check(
|
|
29648
29781
|
"cwt_reference_type_check",
|
|
29649
29782
|
sql`${table.referenceType} IS NULL OR ${table.referenceType} IN (
|
|
@@ -30187,7 +30320,7 @@ var init_errors6 = __esm({
|
|
|
30187
30320
|
});
|
|
30188
30321
|
|
|
30189
30322
|
// ../../packages/types/src/index.ts
|
|
30190
|
-
var
|
|
30323
|
+
var init_src2 = __esm({
|
|
30191
30324
|
"../../packages/types/src/index.ts"() {
|
|
30192
30325
|
"use strict";
|
|
30193
30326
|
init_user();
|
|
@@ -30209,7 +30342,7 @@ var init_course_reviews = __esm({
|
|
|
30209
30342
|
init_pg_core();
|
|
30210
30343
|
init_users();
|
|
30211
30344
|
init_courses3();
|
|
30212
|
-
|
|
30345
|
+
init_src2();
|
|
30213
30346
|
courseReviewStatusEnum = pgEnum("course_review_status", [
|
|
30214
30347
|
"pending",
|
|
30215
30348
|
"approved",
|
|
@@ -30317,6 +30450,7 @@ var init_enrollments = __esm({
|
|
|
30317
30450
|
"../../packages/database/src/schema/enrollments.ts"() {
|
|
30318
30451
|
"use strict";
|
|
30319
30452
|
init_pg_core();
|
|
30453
|
+
init_drizzle_orm();
|
|
30320
30454
|
init_users();
|
|
30321
30455
|
init_courses3();
|
|
30322
30456
|
init_cohorts();
|
|
@@ -30397,7 +30531,14 @@ var init_enrollments = __esm({
|
|
|
30397
30531
|
table.currentLevel
|
|
30398
30532
|
),
|
|
30399
30533
|
// Paris Group integration: partial index for cohort lookups.
|
|
30400
|
-
cohortIdIdx: index("idx_enrollments_cohort_id").on(table.cohortId)
|
|
30534
|
+
cohortIdIdx: index("idx_enrollments_cohort_id").on(table.cohortId),
|
|
30535
|
+
// TASK-1765 (GH #660 Q2): at most ONE active enrollment per (user, course).
|
|
30536
|
+
// Partial on status='active' so refunded/cancelled/completed history rows
|
|
30537
|
+
// can coexist (re-purchase after refund creates a fresh active row).
|
|
30538
|
+
// Raw sql in .where() — drizzle-kit serializes eq() as a `$1` placeholder
|
|
30539
|
+
// (42P02, see AGENTS.md). Backfill of the 3 prod duplicate pairs lives in
|
|
30540
|
+
// migration 0023.
|
|
30541
|
+
uniqueActivePerUserCourse: uniqueIndex("enrollments_user_course_active_unique").on(table.userId, table.courseId).where(sql`${table.status} = 'active'`)
|
|
30401
30542
|
})
|
|
30402
30543
|
);
|
|
30403
30544
|
}
|
|
@@ -33900,6 +34041,34 @@ var init_mentor_availability = __esm({
|
|
|
33900
34041
|
}
|
|
33901
34042
|
});
|
|
33902
34043
|
|
|
34044
|
+
// ../../packages/database/src/schema/mentor-specializations.ts
|
|
34045
|
+
var mentorSpecializations;
|
|
34046
|
+
var init_mentor_specializations = __esm({
|
|
34047
|
+
"../../packages/database/src/schema/mentor-specializations.ts"() {
|
|
34048
|
+
"use strict";
|
|
34049
|
+
init_pg_core();
|
|
34050
|
+
init_users();
|
|
34051
|
+
mentorSpecializations = pgTable(
|
|
34052
|
+
"mentor_specializations",
|
|
34053
|
+
{
|
|
34054
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
34055
|
+
creatorId: uuid("creator_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
34056
|
+
name: varchar("name", { length: 50 }).notNull(),
|
|
34057
|
+
// Display order — mirrors the order the creator typed the chips in
|
|
34058
|
+
position: integer("position").default(0).notNull(),
|
|
34059
|
+
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
34060
|
+
},
|
|
34061
|
+
(table) => ({
|
|
34062
|
+
creatorIdIdx: index("mentor_specializations_creator_id_idx").on(table.creatorId),
|
|
34063
|
+
creatorNameUq: uniqueIndex("mentor_specializations_creator_name_uq").on(
|
|
34064
|
+
table.creatorId,
|
|
34065
|
+
table.name
|
|
34066
|
+
)
|
|
34067
|
+
})
|
|
34068
|
+
);
|
|
34069
|
+
}
|
|
34070
|
+
});
|
|
34071
|
+
|
|
33903
34072
|
// ../../packages/database/src/schema/mentorship-sessions.ts
|
|
33904
34073
|
var mentorshipSessions2, sessionParticipants2, sessionWaitlist2;
|
|
33905
34074
|
var init_mentorship_sessions = __esm({
|
|
@@ -34163,14 +34332,16 @@ var init_mentorship_packages = __esm({
|
|
|
34163
34332
|
function isCreditUsable(credit) {
|
|
34164
34333
|
return credit.status === "active" && credit.creditsRemaining > 0 && new Date(credit.expiresAt) > /* @__PURE__ */ new Date();
|
|
34165
34334
|
}
|
|
34166
|
-
var creditStatusEnum, mentorshipCredits2, insertMentorshipCreditSchema;
|
|
34335
|
+
var creditStatusEnum, creditOriginEnum, mentorshipCredits2, insertMentorshipCreditSchema;
|
|
34167
34336
|
var init_mentorship_credits = __esm({
|
|
34168
34337
|
"../../packages/database/src/schema/mentorship-credits.ts"() {
|
|
34169
34338
|
"use strict";
|
|
34170
34339
|
init_pg_core();
|
|
34340
|
+
init_drizzle_orm();
|
|
34171
34341
|
init_users();
|
|
34172
34342
|
init_mentorship_packages();
|
|
34173
34343
|
init_mentorship_services();
|
|
34344
|
+
init_enrollments();
|
|
34174
34345
|
init_zod();
|
|
34175
34346
|
creditStatusEnum = pgEnum("mentorship_credit_status", [
|
|
34176
34347
|
"active",
|
|
@@ -34180,12 +34351,17 @@ var init_mentorship_credits = __esm({
|
|
|
34180
34351
|
"expired"
|
|
34181
34352
|
// Credits expired (not used before expiration date)
|
|
34182
34353
|
]);
|
|
34354
|
+
creditOriginEnum = pgEnum("mentorship_credit_origin", ["package", "course_purchase"]);
|
|
34183
34355
|
mentorshipCredits2 = pgTable(
|
|
34184
34356
|
"mentorship_credits",
|
|
34185
34357
|
{
|
|
34186
34358
|
id: uuid("id").defaultRandom().primaryKey(),
|
|
34187
34359
|
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
34188
|
-
|
|
34360
|
+
// FEAT-1288: nullable since course-purchase grants have no package. The
|
|
34361
|
+
// origin-consistency CHECK below keeps package rows package-backed.
|
|
34362
|
+
packageId: uuid("package_id").references(() => mentorshipPackages2.id, {
|
|
34363
|
+
onDelete: "cascade"
|
|
34364
|
+
}),
|
|
34189
34365
|
mentorId: uuid("mentor_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
34190
34366
|
serviceId: uuid("service_id").references(() => mentorshipServices2.id, { onDelete: "cascade" }).notNull(),
|
|
34191
34367
|
// Credit balance
|
|
@@ -34195,6 +34371,12 @@ var init_mentorship_credits = __esm({
|
|
|
34195
34371
|
// Current available credits
|
|
34196
34372
|
// Status tracking
|
|
34197
34373
|
status: creditStatusEnum("status").default("active").notNull(),
|
|
34374
|
+
// FEAT-1288: grant origin + the enrollment that granted course credits
|
|
34375
|
+
// (refund revoke looks credits up by enrollment_id).
|
|
34376
|
+
origin: creditOriginEnum("origin").default("package").notNull(),
|
|
34377
|
+
enrollmentId: uuid("enrollment_id").references(() => enrollments.id, {
|
|
34378
|
+
onDelete: "cascade"
|
|
34379
|
+
}),
|
|
34198
34380
|
// Payment reference
|
|
34199
34381
|
stripePaymentIntentId: varchar("stripe_payment_intent_id", { length: 100 }),
|
|
34200
34382
|
// Dates
|
|
@@ -34240,21 +34422,47 @@ var init_mentorship_credits = __esm({
|
|
|
34240
34422
|
table.stripePaymentIntentId
|
|
34241
34423
|
),
|
|
34242
34424
|
// ORDER BY purchasedAt DESC (credit transaction history)
|
|
34243
|
-
purchasedAtIdx: index("mentorship_credits_purchased_at_idx").on(table.purchasedAt)
|
|
34425
|
+
purchasedAtIdx: index("mentorship_credits_purchased_at_idx").on(table.purchasedAt),
|
|
34426
|
+
// FEAT-1288: refund revoke looks up course-granted credits by enrollment
|
|
34427
|
+
enrollmentIdIdx: index("mentorship_credits_enrollment_id_idx").on(table.enrollmentId),
|
|
34428
|
+
// FEAT-1288: each origin carries its tracing FK — package rows keep a
|
|
34429
|
+
// package_id, course-purchase rows keep an enrollment_id.
|
|
34430
|
+
originConsistencyCheck: check(
|
|
34431
|
+
"mentorship_credits_origin_consistency_check",
|
|
34432
|
+
sql`(${table.origin} = 'package' AND ${table.packageId} IS NOT NULL) OR (${table.origin} = 'course_purchase' AND ${table.enrollmentId} IS NOT NULL)`
|
|
34433
|
+
)
|
|
34244
34434
|
})
|
|
34245
34435
|
);
|
|
34246
34436
|
insertMentorshipCreditSchema = external_exports.object({
|
|
34247
34437
|
userId: external_exports.string().uuid(),
|
|
34248
|
-
|
|
34438
|
+
// FEAT-1288: optional — required iff origin === "package" (refinement below)
|
|
34439
|
+
packageId: external_exports.string().uuid().optional().nullable(),
|
|
34249
34440
|
mentorId: external_exports.string().uuid(),
|
|
34250
34441
|
serviceId: external_exports.string().uuid(),
|
|
34251
34442
|
totalCredits: external_exports.number().int().positive(),
|
|
34252
34443
|
creditsRemaining: external_exports.number().int().min(0),
|
|
34253
34444
|
status: external_exports.enum(["active", "depleted", "expired"]).optional().default("active"),
|
|
34445
|
+
origin: external_exports.enum(["package", "course_purchase"]).optional().default("package"),
|
|
34446
|
+
enrollmentId: external_exports.string().uuid().optional().nullable(),
|
|
34254
34447
|
stripePaymentIntentId: external_exports.string().max(100).optional().nullable(),
|
|
34255
34448
|
expiresAt: external_exports.date(),
|
|
34256
34449
|
reminderSent30d: external_exports.boolean().optional().default(false),
|
|
34257
34450
|
reminderSent7d: external_exports.boolean().optional().default(false)
|
|
34451
|
+
}).superRefine((value, ctx) => {
|
|
34452
|
+
if (value.origin === "package" && value.packageId == null) {
|
|
34453
|
+
ctx.addIssue({
|
|
34454
|
+
code: external_exports.ZodIssueCode.custom,
|
|
34455
|
+
path: ["packageId"],
|
|
34456
|
+
message: "packageId is required when origin is 'package'"
|
|
34457
|
+
});
|
|
34458
|
+
}
|
|
34459
|
+
if (value.origin === "course_purchase" && value.enrollmentId == null) {
|
|
34460
|
+
ctx.addIssue({
|
|
34461
|
+
code: external_exports.ZodIssueCode.custom,
|
|
34462
|
+
path: ["enrollmentId"],
|
|
34463
|
+
message: "enrollmentId is required when origin is 'course_purchase'"
|
|
34464
|
+
});
|
|
34465
|
+
}
|
|
34258
34466
|
});
|
|
34259
34467
|
}
|
|
34260
34468
|
});
|
|
@@ -34453,6 +34661,55 @@ var init_mentorship_transactions = __esm({
|
|
|
34453
34661
|
}
|
|
34454
34662
|
});
|
|
34455
34663
|
|
|
34664
|
+
// ../../packages/database/src/schema/course-mentoria-offers.ts
|
|
34665
|
+
var courseMentoriaOffers, insertCourseMentoriaOfferSchema;
|
|
34666
|
+
var init_course_mentoria_offers = __esm({
|
|
34667
|
+
"../../packages/database/src/schema/course-mentoria-offers.ts"() {
|
|
34668
|
+
"use strict";
|
|
34669
|
+
init_pg_core();
|
|
34670
|
+
init_drizzle_orm();
|
|
34671
|
+
init_zod();
|
|
34672
|
+
init_courses3();
|
|
34673
|
+
init_mentorship_services();
|
|
34674
|
+
courseMentoriaOffers = pgTable(
|
|
34675
|
+
"course_mentoria_offers",
|
|
34676
|
+
{
|
|
34677
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
34678
|
+
courseId: uuid("course_id").references(() => courses.id, { onDelete: "cascade" }).notNull(),
|
|
34679
|
+
serviceId: uuid("service_id").references(() => mentorshipServices2.id, { onDelete: "cascade" }).notNull(),
|
|
34680
|
+
/** Sessions granted to the buyer (mentorship_credits) on hybrid purchase. */
|
|
34681
|
+
sessionsIncluded: integer("sessions_included").notNull(),
|
|
34682
|
+
/** Credit validity window, mirrors mentorship_packages (3/6/12). */
|
|
34683
|
+
validityMonths: integer("validity_months").default(6).notNull(),
|
|
34684
|
+
/** Draft offers (e.g. creator without availability) stay inactive. */
|
|
34685
|
+
isActive: boolean("is_active").default(false).notNull(),
|
|
34686
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
34687
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
34688
|
+
},
|
|
34689
|
+
(table) => ({
|
|
34690
|
+
// 1 offer per course — the checkout gate lookup key.
|
|
34691
|
+
courseIdUnique: uniqueIndex("course_mentoria_offers_course_id_unique").on(table.courseId),
|
|
34692
|
+
serviceIdIdx: index("course_mentoria_offers_service_id_idx").on(table.serviceId),
|
|
34693
|
+
sessionsIncludedCheck: check(
|
|
34694
|
+
"course_mentoria_offers_sessions_included_check",
|
|
34695
|
+
sql`${table.sessionsIncluded} >= 1`
|
|
34696
|
+
),
|
|
34697
|
+
validityMonthsCheck: check(
|
|
34698
|
+
"course_mentoria_offers_validity_months_check",
|
|
34699
|
+
sql`${table.validityMonths} IN (3, 6, 12)`
|
|
34700
|
+
)
|
|
34701
|
+
})
|
|
34702
|
+
);
|
|
34703
|
+
insertCourseMentoriaOfferSchema = external_exports.object({
|
|
34704
|
+
courseId: external_exports.string().uuid(),
|
|
34705
|
+
serviceId: external_exports.string().uuid(),
|
|
34706
|
+
sessionsIncluded: external_exports.number().int().min(1),
|
|
34707
|
+
validityMonths: external_exports.union([external_exports.literal(3), external_exports.literal(6), external_exports.literal(12)]).default(6),
|
|
34708
|
+
isActive: external_exports.boolean().default(false)
|
|
34709
|
+
});
|
|
34710
|
+
}
|
|
34711
|
+
});
|
|
34712
|
+
|
|
34456
34713
|
// ../../packages/database/src/schema/session-reviews.ts
|
|
34457
34714
|
var REVIEW_TAGS, sessionReviews2, sessionReviewVotes2;
|
|
34458
34715
|
var init_session_reviews = __esm({
|
|
@@ -34537,11 +34794,13 @@ var init_mentorship_index = __esm({
|
|
|
34537
34794
|
init_mentorship_templates();
|
|
34538
34795
|
init_mentorship_services();
|
|
34539
34796
|
init_mentor_availability();
|
|
34797
|
+
init_mentor_specializations();
|
|
34540
34798
|
init_mentorship_sessions();
|
|
34541
34799
|
init_session_resources();
|
|
34542
34800
|
init_mentorship_transactions();
|
|
34543
34801
|
init_mentorship_packages();
|
|
34544
34802
|
init_mentorship_credits();
|
|
34803
|
+
init_course_mentoria_offers();
|
|
34545
34804
|
init_session_reviews();
|
|
34546
34805
|
}
|
|
34547
34806
|
});
|
|
@@ -34617,6 +34876,7 @@ var init_transactions = __esm({
|
|
|
34617
34876
|
init_pg_core();
|
|
34618
34877
|
init_courses3();
|
|
34619
34878
|
init_users();
|
|
34879
|
+
init_enrollments();
|
|
34620
34880
|
transactions2 = pgTable(
|
|
34621
34881
|
"transactions",
|
|
34622
34882
|
{
|
|
@@ -34629,6 +34889,15 @@ var init_transactions = __esm({
|
|
|
34629
34889
|
courseId: uuid("course_id").notNull().references(() => courses.id, { onDelete: "restrict" }),
|
|
34630
34890
|
creatorId: uuid("creator_id").notNull().references(() => users.id, { onDelete: "restrict" }),
|
|
34631
34891
|
studentId: uuid("student_id").notNull().references(() => users.id, { onDelete: "restrict" }),
|
|
34892
|
+
// CHORE-1676: links the transaction to the exact enrollment it paid for so
|
|
34893
|
+
// the charge.refunded webhook (ProcessRefundUseCase) flips ONLY that row,
|
|
34894
|
+
// never collateral (user, course) history rows. Nullable: historical txns
|
|
34895
|
+
// (pre-link) and TOCTOU-refused purchases (no enrollment created) leave it
|
|
34896
|
+
// null; the refund then falls back to a status-filtered (user, course) match.
|
|
34897
|
+
// onDelete: 'set null' preserves the financial record if the enrollment is deleted.
|
|
34898
|
+
enrollmentId: uuid("enrollment_id").references(() => enrollments.id, {
|
|
34899
|
+
onDelete: "set null"
|
|
34900
|
+
}),
|
|
34632
34901
|
// Financial details (all amounts in cents)
|
|
34633
34902
|
amount: integer("amount").notNull(),
|
|
34634
34903
|
// Total amount charged
|
|
@@ -34648,11 +34917,24 @@ var init_transactions = __esm({
|
|
|
34648
34917
|
paymentMethod: varchar("payment_method", { length: 50 }),
|
|
34649
34918
|
// 'card' or 'pix'
|
|
34650
34919
|
status: varchar("status", { length: 20 }).notNull().default("pending"),
|
|
34651
|
-
// 'pending', 'succeeded', 'failed', 'refunded'
|
|
34920
|
+
// 'pending', 'succeeded', 'failed', 'refunded', 'disputed' (GH #718 chargeback)
|
|
34652
34921
|
// Timestamps
|
|
34653
34922
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
34654
34923
|
processedAt: timestamp("processed_at"),
|
|
34655
34924
|
refundedAt: timestamp("refunded_at"),
|
|
34925
|
+
refundedAmount: integer("refunded_amount").default(0).notNull(),
|
|
34926
|
+
// Cumulative amount refunded in cents
|
|
34927
|
+
refusalReason: varchar("refusal_reason", { length: 50 }),
|
|
34928
|
+
// TOCTOU refusal marker (e.g. 'toctou_course_status')
|
|
34929
|
+
// GH #718: Stripe chargeback/dispute tracking. disputedAt is stamped when a
|
|
34930
|
+
// charge.dispute.created arrives (status flips to 'disputed') and on a lost
|
|
34931
|
+
// dispute (charge.dispute.closed status=lost). disputeFee is the platform's
|
|
34932
|
+
// ~$15 chargeback fee (cents), recorded only on a lost dispute and netted
|
|
34933
|
+
// out of netPlatformRevenue. Both nullable — non-disputed transactions leave
|
|
34934
|
+
// them null.
|
|
34935
|
+
disputedAt: timestamp("disputed_at"),
|
|
34936
|
+
disputeFee: integer("dispute_fee"),
|
|
34937
|
+
// Stripe dispute fee in cents (lost disputes only)
|
|
34656
34938
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
34657
34939
|
},
|
|
34658
34940
|
(table) => ({
|
|
@@ -34739,6 +35021,56 @@ var init_payouts = __esm({
|
|
|
34739
35021
|
}
|
|
34740
35022
|
});
|
|
34741
35023
|
|
|
35024
|
+
// ../../packages/database/src/schema/subscription-pools.ts
|
|
35025
|
+
var subscriptionPoolStatusEnum, subscriptionSplitStatusEnum, catalogSubscriptionRevenuePools, catalogSubscriptionCreatorSplits;
|
|
35026
|
+
var init_subscription_pools = __esm({
|
|
35027
|
+
"../../packages/database/src/schema/subscription-pools.ts"() {
|
|
35028
|
+
"use strict";
|
|
35029
|
+
init_pg_core();
|
|
35030
|
+
init_users();
|
|
35031
|
+
subscriptionPoolStatusEnum = pgEnum("subscription_pool_status", [
|
|
35032
|
+
"open",
|
|
35033
|
+
"calculating",
|
|
35034
|
+
"distributed"
|
|
35035
|
+
]);
|
|
35036
|
+
subscriptionSplitStatusEnum = pgEnum("subscription_split_status", [
|
|
35037
|
+
"pending",
|
|
35038
|
+
"paid",
|
|
35039
|
+
"failed"
|
|
35040
|
+
]);
|
|
35041
|
+
catalogSubscriptionRevenuePools = pgTable("catalog_subscription_revenue_pools", {
|
|
35042
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
35043
|
+
month: varchar("month", { length: 7 }).notNull().unique(),
|
|
35044
|
+
// "YYYY-MM"
|
|
35045
|
+
totalAmount: integer("total_amount").notNull(),
|
|
35046
|
+
// pool amount in BRL cents
|
|
35047
|
+
status: subscriptionPoolStatusEnum("status").default("open").notNull(),
|
|
35048
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
35049
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
35050
|
+
});
|
|
35051
|
+
catalogSubscriptionCreatorSplits = pgTable(
|
|
35052
|
+
"catalog_subscription_creator_splits",
|
|
35053
|
+
{
|
|
35054
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
35055
|
+
poolId: uuid("pool_id").references(() => catalogSubscriptionRevenuePools.id, { onDelete: "cascade" }).notNull(),
|
|
35056
|
+
creatorId: uuid("creator_id").references(() => users.id, { onDelete: "restrict" }).notNull(),
|
|
35057
|
+
viewsCount: integer("views_count").notNull(),
|
|
35058
|
+
sharePercentage: numeric("share_percentage", { precision: 10, scale: 6 }).notNull(),
|
|
35059
|
+
// e.g. 0.354123
|
|
35060
|
+
allocatedAmount: integer("allocated_amount").notNull(),
|
|
35061
|
+
// share amount in BRL cents
|
|
35062
|
+
status: subscriptionSplitStatusEnum("status").default("pending").notNull(),
|
|
35063
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
35064
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
35065
|
+
},
|
|
35066
|
+
(table) => ({
|
|
35067
|
+
poolIdIdx: index("idx_csc_splits_pool_id").on(table.poolId),
|
|
35068
|
+
creatorIdIdx: index("idx_csc_splits_creator_id").on(table.creatorId)
|
|
35069
|
+
})
|
|
35070
|
+
);
|
|
35071
|
+
}
|
|
35072
|
+
});
|
|
35073
|
+
|
|
34742
35074
|
// ../../packages/database/src/schema/creator-applications.ts
|
|
34743
35075
|
var creatorApplications2;
|
|
34744
35076
|
var init_creator_applications = __esm({
|
|
@@ -35001,7 +35333,10 @@ var init_course_project_enums = __esm({
|
|
|
35001
35333
|
});
|
|
35002
35334
|
|
|
35003
35335
|
// ../../packages/database/src/schema/course-project-types.ts
|
|
35004
|
-
|
|
35336
|
+
function v3CancelReasonRedisKey(courseId) {
|
|
35337
|
+
return `v3:cancel-reason:${courseId}`;
|
|
35338
|
+
}
|
|
35339
|
+
var CANCEL_REASONS, V3_CANCEL_REASON_TTL_SECONDS;
|
|
35005
35340
|
var init_course_project_types = __esm({
|
|
35006
35341
|
"../../packages/database/src/schema/course-project-types.ts"() {
|
|
35007
35342
|
"use strict";
|
|
@@ -35012,6 +35347,7 @@ var init_course_project_types = __esm({
|
|
|
35012
35347
|
"incomplete_stream",
|
|
35013
35348
|
"unknown"
|
|
35014
35349
|
];
|
|
35350
|
+
V3_CANCEL_REASON_TTL_SECONDS = 86400;
|
|
35015
35351
|
}
|
|
35016
35352
|
});
|
|
35017
35353
|
|
|
@@ -35051,6 +35387,7 @@ var init_course_projects = __esm({
|
|
|
35051
35387
|
"../../packages/database/src/schema/course-projects.ts"() {
|
|
35052
35388
|
"use strict";
|
|
35053
35389
|
init_pg_core();
|
|
35390
|
+
init_drizzle_orm();
|
|
35054
35391
|
init_users();
|
|
35055
35392
|
init_brainstormings();
|
|
35056
35393
|
init_courses3();
|
|
@@ -35169,7 +35506,9 @@ var init_course_projects = __esm({
|
|
|
35169
35506
|
statusIdx: index("course_projects_status_idx").on(table.status),
|
|
35170
35507
|
currentPhaseIdx: index("course_projects_current_phase_idx").on(table.currentPhase),
|
|
35171
35508
|
sourceTypeIdx: index("course_projects_source_type_idx").on(table.sourceType),
|
|
35172
|
-
|
|
35509
|
+
// CHORE-1709: one durable project per source idea. Partial UNIQUE keeps
|
|
35510
|
+
// manual/context projects (NULL source_idea_id) unconstrained.
|
|
35511
|
+
sourceIdeaIdUnique: uniqueIndex("course_projects_source_idea_id_unique").on(table.sourceIdeaId).where(sql`${table.sourceIdeaId} IS NOT NULL`),
|
|
35173
35512
|
categoryIdIdx: index("course_projects_category_id_idx").on(table.categoryId),
|
|
35174
35513
|
// ORDER BY createdAt/updatedAt DESC (project listing + creator initial state)
|
|
35175
35514
|
createdAtIdx: index("course_projects_created_at_idx").on(table.createdAt),
|
|
@@ -36988,6 +37327,12 @@ var init_security_audit_log = __esm({
|
|
|
36988
37327
|
"account.role_change",
|
|
36989
37328
|
"account.profile_update",
|
|
36990
37329
|
"account.delete",
|
|
37330
|
+
"account.data_export",
|
|
37331
|
+
// LGPD Art. 18 I/II — personal-data export (GH #608)
|
|
37332
|
+
"account.deletion_requested",
|
|
37333
|
+
// LGPD Art. 18 VI (GH #609)
|
|
37334
|
+
"account.restored",
|
|
37335
|
+
"account.hard_deleted",
|
|
36991
37336
|
// Admin events
|
|
36992
37337
|
"admin.user_suspend",
|
|
36993
37338
|
"admin.user_unsuspend",
|
|
@@ -37113,7 +37458,7 @@ var init_credit_movement_audit_log = __esm({
|
|
|
37113
37458
|
});
|
|
37114
37459
|
|
|
37115
37460
|
// ../../packages/database/src/schema/marketing.ts
|
|
37116
|
-
var testimonialStatusEnum, marketingContentTypeEnum, creatorTestimonials2, marketingContent2, newsletterSubscribers, contactSubmissions;
|
|
37461
|
+
var testimonialStatusEnum, testimonialPlacementEnum, marketingContentTypeEnum, creatorTestimonials2, marketingContent2, newsletterSubscribers, contactSubmissions;
|
|
37117
37462
|
var init_marketing = __esm({
|
|
37118
37463
|
"../../packages/database/src/schema/marketing.ts"() {
|
|
37119
37464
|
"use strict";
|
|
@@ -37124,6 +37469,11 @@ var init_marketing = __esm({
|
|
|
37124
37469
|
"published",
|
|
37125
37470
|
"archived"
|
|
37126
37471
|
]);
|
|
37472
|
+
testimonialPlacementEnum = pgEnum("testimonial_placement", [
|
|
37473
|
+
"homepage",
|
|
37474
|
+
"creators",
|
|
37475
|
+
"both"
|
|
37476
|
+
]);
|
|
37127
37477
|
marketingContentTypeEnum = pgEnum("marketing_content_type", [
|
|
37128
37478
|
"text",
|
|
37129
37479
|
// Simple text content
|
|
@@ -37158,6 +37508,7 @@ var init_marketing = __esm({
|
|
|
37158
37508
|
featured: boolean("featured").default(false).notNull(),
|
|
37159
37509
|
// Show in carousel
|
|
37160
37510
|
displayOrder: integer("display_order").default(0).notNull(),
|
|
37511
|
+
placement: testimonialPlacementEnum("placement").default("creators").notNull(),
|
|
37161
37512
|
// Localization support (null = applies to all locales)
|
|
37162
37513
|
locale: varchar("locale", { length: 10 }),
|
|
37163
37514
|
// Metadata
|
|
@@ -37170,7 +37521,8 @@ var init_marketing = __esm({
|
|
|
37170
37521
|
statusIdx: index("creator_testimonials_status_idx").on(table.status),
|
|
37171
37522
|
featuredIdx: index("creator_testimonials_featured_idx").on(table.featured),
|
|
37172
37523
|
displayOrderIdx: index("creator_testimonials_display_order_idx").on(table.displayOrder),
|
|
37173
|
-
localeIdx: index("creator_testimonials_locale_idx").on(table.locale)
|
|
37524
|
+
localeIdx: index("creator_testimonials_locale_idx").on(table.locale),
|
|
37525
|
+
placementIdx: index("creator_testimonials_placement_idx").on(table.placement)
|
|
37174
37526
|
})
|
|
37175
37527
|
);
|
|
37176
37528
|
marketingContent2 = pgTable(
|
|
@@ -38023,12 +38375,14 @@ var init_system_config = __esm({
|
|
|
38023
38375
|
"ai.context.compression_threshold": "ai.context.compression_threshold",
|
|
38024
38376
|
// Business - Pricing
|
|
38025
38377
|
"business.pricing.min_course_price_brl": "business.pricing.min_course_price_brl",
|
|
38026
|
-
"business.pricing.mentorship_platform_fee_percent": "business.pricing.mentorship_platform_fee_percent",
|
|
38027
38378
|
"business.pricing.course_mentoria_creator_share": "business.pricing.course_mentoria_creator_share",
|
|
38028
38379
|
"business.pricing.course_mentoria_platform_share": "business.pricing.course_mentoria_platform_share",
|
|
38029
|
-
"business.pricing.course_selfpaced_creator_share": "business.pricing.course_selfpaced_creator_share",
|
|
38030
|
-
"business.pricing.course_selfpaced_platform_share": "business.pricing.course_selfpaced_platform_share",
|
|
38031
38380
|
"business.pricing.ai_margin_percent": "business.pricing.ai_margin_percent",
|
|
38381
|
+
"business.pricing.course_creator_share": "business.pricing.course_creator_share",
|
|
38382
|
+
"business.pricing.course_platform_share": "business.pricing.course_platform_share",
|
|
38383
|
+
"business.pricing.mentorship_creator_share": "business.pricing.mentorship_creator_share",
|
|
38384
|
+
"business.pricing.mentorship_platform_share": "business.pricing.mentorship_platform_share",
|
|
38385
|
+
"business.pricing.subscription_creator_share": "business.pricing.subscription_creator_share",
|
|
38032
38386
|
// Business - Monitoring Thresholds
|
|
38033
38387
|
"business.monitoring.cache_success_threshold": "business.monitoring.cache_success_threshold",
|
|
38034
38388
|
"business.monitoring.cache_warning_threshold": "business.monitoring.cache_warning_threshold",
|
|
@@ -38617,7 +38971,7 @@ var init_course_transfer_logs = __esm({
|
|
|
38617
38971
|
"use strict";
|
|
38618
38972
|
init_pg_core();
|
|
38619
38973
|
init_users();
|
|
38620
|
-
transferTypeEnum = pgEnum("transfer_type", ["export", "import"]);
|
|
38974
|
+
transferTypeEnum = pgEnum("transfer_type", ["export", "import", "reassign"]);
|
|
38621
38975
|
transferStatusEnum = pgEnum("transfer_status", [
|
|
38622
38976
|
"pending",
|
|
38623
38977
|
"processing",
|
|
@@ -38632,6 +38986,8 @@ var init_course_transfer_logs = __esm({
|
|
|
38632
38986
|
adminId: uuid("admin_id").references(() => users.id, { onDelete: "restrict" }).notNull(),
|
|
38633
38987
|
type: transferTypeEnum("type").notNull(),
|
|
38634
38988
|
courseId: uuid("course_id"),
|
|
38989
|
+
fromCreatorId: uuid("from_creator_id").references(() => users.id, { onDelete: "set null" }),
|
|
38990
|
+
toCreatorId: uuid("to_creator_id").references(() => users.id, { onDelete: "set null" }),
|
|
38635
38991
|
courseName: text("course_name").notNull(),
|
|
38636
38992
|
sourceEnvironment: text("source_environment"),
|
|
38637
38993
|
status: transferStatusEnum("status").default("pending").notNull(),
|
|
@@ -38646,9 +39002,7 @@ var init_course_transfer_logs = __esm({
|
|
|
38646
39002
|
adminIdIdx: index("course_transfer_logs_admin_id_idx").on(table.adminId),
|
|
38647
39003
|
typeIdx: index("course_transfer_logs_type_idx").on(table.type),
|
|
38648
39004
|
statusIdx: index("course_transfer_logs_status_idx").on(table.status),
|
|
38649
|
-
createdAtIdx: index("course_transfer_logs_created_at_idx").on(
|
|
38650
|
-
table.createdAt
|
|
38651
|
-
)
|
|
39005
|
+
createdAtIdx: index("course_transfer_logs_created_at_idx").on(table.createdAt)
|
|
38652
39006
|
})
|
|
38653
39007
|
);
|
|
38654
39008
|
}
|
|
@@ -40687,34 +41041,6 @@ var init_magic_link_tokens = __esm({
|
|
|
40687
41041
|
}
|
|
40688
41042
|
});
|
|
40689
41043
|
|
|
40690
|
-
// ../../packages/database/src/schema/platform-fees.ts
|
|
40691
|
-
var platformFeeTypeEnum, platformFees;
|
|
40692
|
-
var init_platform_fees = __esm({
|
|
40693
|
-
"../../packages/database/src/schema/platform-fees.ts"() {
|
|
40694
|
-
"use strict";
|
|
40695
|
-
init_pg_core();
|
|
40696
|
-
platformFeeTypeEnum = pgEnum("platform_fee_type", ["course", "mentorship"]);
|
|
40697
|
-
platformFees = pgTable(
|
|
40698
|
-
"platform_fees",
|
|
40699
|
-
{
|
|
40700
|
-
id: uuid("id").defaultRandom().primaryKey(),
|
|
40701
|
-
countryCode: varchar("country_code", { length: 2 }).notNull(),
|
|
40702
|
-
feeType: platformFeeTypeEnum("fee_type").notNull(),
|
|
40703
|
-
feePercent: numeric("fee_percent", { precision: 5, scale: 2 }).notNull(),
|
|
40704
|
-
isActive: boolean("is_active").default(true),
|
|
40705
|
-
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
40706
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
40707
|
-
},
|
|
40708
|
-
(table) => ({
|
|
40709
|
-
countryFeeTypeUniq: unique("platform_fees_country_fee_type_uniq").on(
|
|
40710
|
-
table.countryCode,
|
|
40711
|
-
table.feeType
|
|
40712
|
-
)
|
|
40713
|
-
})
|
|
40714
|
-
);
|
|
40715
|
-
}
|
|
40716
|
-
});
|
|
40717
|
-
|
|
40718
41044
|
// ../../packages/database/src/schema/payout-methods.ts
|
|
40719
41045
|
var payoutMethods, payoutAccounts;
|
|
40720
41046
|
var init_payout_methods = __esm({
|
|
@@ -40754,6 +41080,34 @@ var init_payout_methods = __esm({
|
|
|
40754
41080
|
}
|
|
40755
41081
|
});
|
|
40756
41082
|
|
|
41083
|
+
// ../../packages/database/src/schema/withdrawal-taxes.ts
|
|
41084
|
+
var withdrawalTaxes;
|
|
41085
|
+
var init_withdrawal_taxes = __esm({
|
|
41086
|
+
"../../packages/database/src/schema/withdrawal-taxes.ts"() {
|
|
41087
|
+
"use strict";
|
|
41088
|
+
init_pg_core();
|
|
41089
|
+
init_drizzle_orm();
|
|
41090
|
+
withdrawalTaxes = pgTable(
|
|
41091
|
+
"withdrawal_taxes",
|
|
41092
|
+
{
|
|
41093
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
41094
|
+
countryCode: varchar("country_code", { length: 2 }).notNull(),
|
|
41095
|
+
taxPercent: numeric("tax_percent", { precision: 5, scale: 2 }).notNull(),
|
|
41096
|
+
isActive: boolean("is_active").default(true).notNull(),
|
|
41097
|
+
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
41098
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
41099
|
+
},
|
|
41100
|
+
(table) => ({
|
|
41101
|
+
countryUniq: unique("withdrawal_taxes_country_uniq").on(table.countryCode),
|
|
41102
|
+
taxRange: check(
|
|
41103
|
+
"withdrawal_taxes_tax_range",
|
|
41104
|
+
sql`${table.taxPercent} >= 0 AND ${table.taxPercent} <= 100`
|
|
41105
|
+
)
|
|
41106
|
+
})
|
|
41107
|
+
);
|
|
41108
|
+
}
|
|
41109
|
+
});
|
|
41110
|
+
|
|
40757
41111
|
// ../../packages/database/src/schema/media-assets.ts
|
|
40758
41112
|
var mediaAssetStatusEnum, mediaAssetTypeEnum, mediaAssetDomainEnum, mediaAssets;
|
|
40759
41113
|
var init_media_assets = __esm({
|
|
@@ -40835,7 +41189,7 @@ var init_push_tokens = __esm({
|
|
|
40835
41189
|
});
|
|
40836
41190
|
|
|
40837
41191
|
// ../../packages/database/src/schema/payout.ts
|
|
40838
|
-
var
|
|
41192
|
+
var payoutWithdrawals, payoutBankAccounts, payoutWithdrawalTransitions;
|
|
40839
41193
|
var init_payout = __esm({
|
|
40840
41194
|
"../../packages/database/src/schema/payout.ts"() {
|
|
40841
41195
|
"use strict";
|
|
@@ -40845,22 +41199,6 @@ var init_payout = __esm({
|
|
|
40845
41199
|
init_credit_wallets();
|
|
40846
41200
|
init_credit_wallets();
|
|
40847
41201
|
init_payout_methods();
|
|
40848
|
-
payoutFeeConfig = pgTable(
|
|
40849
|
-
"payout_fee_config",
|
|
40850
|
-
{
|
|
40851
|
-
id: uuid("id").defaultRandom().primaryKey(),
|
|
40852
|
-
mentorId: uuid("mentor_id").references(() => users.id, {
|
|
40853
|
-
onDelete: "cascade"
|
|
40854
|
-
}).unique(),
|
|
40855
|
-
// null = global default
|
|
40856
|
-
feePercent: decimal("fee_percent", { precision: 5, scale: 2 }).notNull(),
|
|
40857
|
-
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
40858
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
40859
|
-
},
|
|
40860
|
-
(table) => ({
|
|
40861
|
-
feeRange: check("pfc_fee_range", sql`${table.feePercent} >= 0 AND ${table.feePercent} <= 100`)
|
|
40862
|
-
})
|
|
40863
|
-
);
|
|
40864
41202
|
payoutWithdrawals = pgTable(
|
|
40865
41203
|
"payout_withdrawals",
|
|
40866
41204
|
{
|
|
@@ -40877,10 +41215,17 @@ var init_payout = __esm({
|
|
|
40877
41215
|
precision: 10,
|
|
40878
41216
|
scale: 4
|
|
40879
41217
|
}).notNull(),
|
|
40880
|
-
|
|
41218
|
+
// Camada 3 (ADR-0169 / FEAT-1287): the deduction at cash-out is the
|
|
41219
|
+
// creator's country-of-residence TAX — never a revenue split. Renamed
|
|
41220
|
+
// from fee_percent/fee_usd (legal: table had 0 rows at rename time).
|
|
41221
|
+
taxPercent: decimal("tax_percent", { precision: 5, scale: 2 }).notNull(),
|
|
40881
41222
|
grossUsd: decimal("gross_usd", { precision: 10, scale: 4 }).notNull(),
|
|
40882
|
-
|
|
41223
|
+
taxUsd: decimal("tax_usd", { precision: 10, scale: 4 }).notNull(),
|
|
40883
41224
|
netUsd: decimal("net_usd", { precision: 10, scale: 4 }).notNull(),
|
|
41225
|
+
// Audit snapshot: which country code resolved the tax at request time
|
|
41226
|
+
// ('*' when the mentor had no confirmed country). Nullable: rows created
|
|
41227
|
+
// before Camada 3 (none in prod) would not have it.
|
|
41228
|
+
taxCountry: varchar("tax_country", { length: 2 }),
|
|
40884
41229
|
exchangeRateBrl: decimal("exchange_rate_brl", {
|
|
40885
41230
|
precision: 10,
|
|
40886
41231
|
scale: 4
|
|
@@ -41079,6 +41424,7 @@ var init_course_allowlist = __esm({
|
|
|
41079
41424
|
"../../packages/database/src/schema/course-allowlist.ts"() {
|
|
41080
41425
|
"use strict";
|
|
41081
41426
|
init_pg_core();
|
|
41427
|
+
init_drizzle_orm();
|
|
41082
41428
|
init_courses3();
|
|
41083
41429
|
init_users();
|
|
41084
41430
|
courseAllowlist = pgTable(
|
|
@@ -41092,58 +41438,172 @@ var init_course_allowlist = __esm({
|
|
|
41092
41438
|
onDelete: "set null"
|
|
41093
41439
|
}),
|
|
41094
41440
|
invitedAt: timestamp("invited_at", { withTimezone: true }).defaultNow().notNull(),
|
|
41095
|
-
resolvedAt: timestamp("resolved_at", { withTimezone: true })
|
|
41441
|
+
resolvedAt: timestamp("resolved_at", { withTimezone: true }),
|
|
41442
|
+
// GH #631: per-invite recipient binding carried in the email link as
|
|
41443
|
+
// ?invite=<accept_token>. NULL = legacy/expired invite (creator must resend).
|
|
41444
|
+
acceptToken: uuid("accept_token"),
|
|
41445
|
+
acceptTokenExpiresAt: timestamp("accept_token_expires_at", { withTimezone: true })
|
|
41096
41446
|
},
|
|
41097
41447
|
(table) => ({
|
|
41098
41448
|
courseEmailUnique: uniqueIndex("course_allowlist_course_email_unique").on(
|
|
41099
41449
|
table.courseId,
|
|
41100
41450
|
table.email
|
|
41101
41451
|
),
|
|
41102
|
-
courseIdIdx: index("course_allowlist_course_id_idx").on(table.courseId)
|
|
41452
|
+
courseIdIdx: index("course_allowlist_course_id_idx").on(table.courseId),
|
|
41453
|
+
// Partial unique index: multiple NULL tokens allowed; minted tokens are globally unique.
|
|
41454
|
+
acceptTokenUnique: uniqueIndex("course_allowlist_accept_token_unique").on(table.acceptToken).where(sql`${table.acceptToken} IS NOT NULL`)
|
|
41103
41455
|
// partial indexes (user_id IS NOT NULL / IS NULL) are created via raw SQL in the migration — see drizzle-kit $N gotcha in packages/database/AGENTS.md
|
|
41104
41456
|
})
|
|
41105
41457
|
);
|
|
41106
41458
|
}
|
|
41107
41459
|
});
|
|
41108
41460
|
|
|
41109
|
-
// ../../
|
|
41461
|
+
// ../../packages/database/src/schema/idempotency.ts
|
|
41110
41462
|
var pgBackendIdempotencyKeys;
|
|
41111
|
-
var
|
|
41112
|
-
"../../
|
|
41463
|
+
var init_idempotency = __esm({
|
|
41464
|
+
"../../packages/database/src/schema/idempotency.ts"() {
|
|
41465
|
+
"use strict";
|
|
41113
41466
|
init_drizzle_orm();
|
|
41114
41467
|
init_pg_core();
|
|
41115
|
-
pgBackendIdempotencyKeys = pgTable(
|
|
41116
|
-
|
|
41117
|
-
|
|
41118
|
-
|
|
41119
|
-
|
|
41120
|
-
|
|
41121
|
-
|
|
41122
|
-
|
|
41123
|
-
|
|
41124
|
-
|
|
41125
|
-
|
|
41126
|
-
|
|
41127
|
-
|
|
41128
|
-
|
|
41129
|
-
|
|
41130
|
-
|
|
41131
|
-
|
|
41468
|
+
pgBackendIdempotencyKeys = pgTable(
|
|
41469
|
+
"pg_backend_idempotency_keys",
|
|
41470
|
+
{
|
|
41471
|
+
reservationId: uuid("reservation_id").primaryKey().defaultRandom(),
|
|
41472
|
+
idempotencyKey: text("idempotency_key").notNull(),
|
|
41473
|
+
resource: text("resource").notNull(),
|
|
41474
|
+
operation: text("operation").notNull(),
|
|
41475
|
+
fingerprint: text("fingerprint").notNull(),
|
|
41476
|
+
scopeKey: text("scope_key"),
|
|
41477
|
+
status: text("status").notNull(),
|
|
41478
|
+
response: jsonb("response"),
|
|
41479
|
+
reservedAt: timestamp("reserved_at", { withTimezone: true }).notNull().defaultNow(),
|
|
41480
|
+
committedAt: timestamp("committed_at", { withTimezone: true }),
|
|
41481
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull()
|
|
41482
|
+
},
|
|
41483
|
+
(t) => [
|
|
41484
|
+
uniqueIndex("pg_backend_idempotency_unique").on(
|
|
41485
|
+
t.idempotencyKey,
|
|
41486
|
+
t.resource,
|
|
41487
|
+
t.operation,
|
|
41488
|
+
sql`COALESCE(${t.scopeKey}, '')`
|
|
41489
|
+
),
|
|
41490
|
+
index("pg_backend_idempotency_expires").on(t.expiresAt),
|
|
41491
|
+
index("pg_backend_idempotency_pending").on(t.status, t.reservedAt)
|
|
41492
|
+
]
|
|
41493
|
+
);
|
|
41132
41494
|
}
|
|
41133
41495
|
});
|
|
41134
41496
|
|
|
41135
|
-
// ../../
|
|
41136
|
-
var
|
|
41137
|
-
|
|
41138
|
-
|
|
41497
|
+
// ../../packages/database/src/schema/user-deletions.ts
|
|
41498
|
+
var userDeletionStatusEnum, userDeletions;
|
|
41499
|
+
var init_user_deletions = __esm({
|
|
41500
|
+
"../../packages/database/src/schema/user-deletions.ts"() {
|
|
41501
|
+
"use strict";
|
|
41502
|
+
init_pg_core();
|
|
41503
|
+
init_users();
|
|
41504
|
+
userDeletionStatusEnum = pgEnum("user_deletion_status", [
|
|
41505
|
+
"pending",
|
|
41506
|
+
// grace period running
|
|
41507
|
+
"restored",
|
|
41508
|
+
// user reverted within grace
|
|
41509
|
+
"hard_deleted"
|
|
41510
|
+
// cron purged the account
|
|
41511
|
+
]);
|
|
41512
|
+
userDeletions = pgTable(
|
|
41513
|
+
"user_deletions",
|
|
41514
|
+
{
|
|
41515
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
41516
|
+
userId: uuid("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
41517
|
+
requestedAt: timestamp("requested_at", { withTimezone: true }).defaultNow().notNull(),
|
|
41518
|
+
scheduledHardDeleteAt: timestamp("scheduled_hard_delete_at", {
|
|
41519
|
+
withTimezone: true
|
|
41520
|
+
}).notNull(),
|
|
41521
|
+
// SHA-256 of the restore JWT (the raw token only lives in the email link).
|
|
41522
|
+
restoreTokenHash: text("restore_token_hash"),
|
|
41523
|
+
reason: text("reason"),
|
|
41524
|
+
status: userDeletionStatusEnum("status").default("pending").notNull(),
|
|
41525
|
+
anonymizedAt: timestamp("anonymized_at", { withTimezone: true })
|
|
41526
|
+
},
|
|
41527
|
+
(table) => ({
|
|
41528
|
+
userIdIdx: index("user_deletions_user_id_idx").on(table.userId),
|
|
41529
|
+
statusScheduledIdx: index("user_deletions_status_scheduled_idx").on(
|
|
41530
|
+
table.status,
|
|
41531
|
+
table.scheduledHardDeleteAt
|
|
41532
|
+
)
|
|
41533
|
+
})
|
|
41534
|
+
);
|
|
41139
41535
|
}
|
|
41140
41536
|
});
|
|
41141
41537
|
|
|
41142
|
-
// ../../packages/database/src/schema/
|
|
41143
|
-
var
|
|
41144
|
-
|
|
41538
|
+
// ../../packages/database/src/schema/user-profiles.ts
|
|
41539
|
+
var profileVisibilityEnum, userProfiles;
|
|
41540
|
+
var init_user_profiles = __esm({
|
|
41541
|
+
"../../packages/database/src/schema/user-profiles.ts"() {
|
|
41145
41542
|
"use strict";
|
|
41146
|
-
|
|
41543
|
+
init_pg_core();
|
|
41544
|
+
init_users();
|
|
41545
|
+
profileVisibilityEnum = pgEnum("profile_visibility", ["public", "private"]);
|
|
41546
|
+
userProfiles = pgTable("user_profiles", {
|
|
41547
|
+
// One row per user — userId is both PK and FK (singleton satellite, same
|
|
41548
|
+
// pattern as user_preferences).
|
|
41549
|
+
userId: uuid("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
|
|
41550
|
+
// Short tagline shown under the name, e.g. "Full-stack dev & educator"
|
|
41551
|
+
headline: varchar("headline", { length: 120 }),
|
|
41552
|
+
// Free-form location, e.g. "São Paulo, Brasil"
|
|
41553
|
+
location: varchar("location", { length: 100 }),
|
|
41554
|
+
// Emoji avatar fallback when no photo is uploaded, e.g. "🧑💻"
|
|
41555
|
+
avatarEmoji: varchar("avatar_emoji", { length: 16 }),
|
|
41556
|
+
// Profile-wide visibility (distinct from users.portfolioPublic, which is
|
|
41557
|
+
// scoped to the creator portfolio feature only)
|
|
41558
|
+
visibility: profileVisibilityEnum("visibility").default("public").notNull(),
|
|
41559
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
41560
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
41561
|
+
});
|
|
41562
|
+
}
|
|
41563
|
+
});
|
|
41564
|
+
|
|
41565
|
+
// ../../packages/database/src/schema/user-resource-audits.ts
|
|
41566
|
+
var userProfileAudits, userPreferencesAudits;
|
|
41567
|
+
var init_user_resource_audits = __esm({
|
|
41568
|
+
"../../packages/database/src/schema/user-resource-audits.ts"() {
|
|
41569
|
+
"use strict";
|
|
41570
|
+
init_pg_core();
|
|
41571
|
+
userProfileAudits = pgTable(
|
|
41572
|
+
"user_profile_audits",
|
|
41573
|
+
{
|
|
41574
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
41575
|
+
resource: text("resource").notNull(),
|
|
41576
|
+
row_id: text("row_id").notNull(),
|
|
41577
|
+
op: text("op").notNull(),
|
|
41578
|
+
actor: jsonb("actor").notNull(),
|
|
41579
|
+
before: jsonb("before"),
|
|
41580
|
+
after: jsonb("after"),
|
|
41581
|
+
at: timestamp("at", { withTimezone: true }).defaultNow().notNull()
|
|
41582
|
+
},
|
|
41583
|
+
(table) => ({
|
|
41584
|
+
resourceIdx: index("user_profile_audits_resource_idx").on(table.resource),
|
|
41585
|
+
rowIdIdx: index("user_profile_audits_row_id_idx").on(table.row_id),
|
|
41586
|
+
atIdx: index("user_profile_audits_at_idx").on(table.at)
|
|
41587
|
+
})
|
|
41588
|
+
);
|
|
41589
|
+
userPreferencesAudits = pgTable(
|
|
41590
|
+
"user_preferences_audits",
|
|
41591
|
+
{
|
|
41592
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
41593
|
+
resource: text("resource").notNull(),
|
|
41594
|
+
row_id: text("row_id").notNull(),
|
|
41595
|
+
op: text("op").notNull(),
|
|
41596
|
+
actor: jsonb("actor").notNull(),
|
|
41597
|
+
before: jsonb("before"),
|
|
41598
|
+
after: jsonb("after"),
|
|
41599
|
+
at: timestamp("at", { withTimezone: true }).defaultNow().notNull()
|
|
41600
|
+
},
|
|
41601
|
+
(table) => ({
|
|
41602
|
+
resourceIdx: index("user_preferences_audits_resource_idx").on(table.resource),
|
|
41603
|
+
rowIdIdx: index("user_preferences_audits_row_id_idx").on(table.row_id),
|
|
41604
|
+
atIdx: index("user_preferences_audits_at_idx").on(table.at)
|
|
41605
|
+
})
|
|
41606
|
+
);
|
|
41147
41607
|
}
|
|
41148
41608
|
});
|
|
41149
41609
|
|
|
@@ -41161,6 +41621,7 @@ __export(schema_exports, {
|
|
|
41161
41621
|
PACKAGE_VALIDITY_OPTIONS: () => PACKAGE_VALIDITY_OPTIONS,
|
|
41162
41622
|
REVIEW_TAGS: () => REVIEW_TAGS,
|
|
41163
41623
|
SUGGESTED_DISCOUNTS: () => SUGGESTED_DISCOUNTS,
|
|
41624
|
+
V3_CANCEL_REASON_TTL_SECONDS: () => V3_CANCEL_REASON_TTL_SECONDS,
|
|
41164
41625
|
accounts: () => accounts,
|
|
41165
41626
|
accountsRelations: () => accountsRelations2,
|
|
41166
41627
|
actionTypeEnum: () => actionTypeEnum,
|
|
@@ -41189,6 +41650,8 @@ __export(schema_exports, {
|
|
|
41189
41650
|
browserSessions: () => browserSessions,
|
|
41190
41651
|
browserSessionsRelations: () => browserSessionsRelations,
|
|
41191
41652
|
cancellationReasonEnum: () => cancellationReasonEnum,
|
|
41653
|
+
catalogSubscriptionCreatorSplits: () => catalogSubscriptionCreatorSplits,
|
|
41654
|
+
catalogSubscriptionRevenuePools: () => catalogSubscriptionRevenuePools,
|
|
41192
41655
|
certificates: () => certificates,
|
|
41193
41656
|
certificatesRelations: () => certificatesRelations2,
|
|
41194
41657
|
challengeType: () => challengeType,
|
|
@@ -41234,6 +41697,7 @@ __export(schema_exports, {
|
|
|
41234
41697
|
courseKnowledgeBases: () => courseKnowledgeBases,
|
|
41235
41698
|
courseKnowledgeBasesRelations: () => courseKnowledgeBasesRelations,
|
|
41236
41699
|
courseLevelEnum: () => courseLevelEnum,
|
|
41700
|
+
courseMentoriaOffers: () => courseMentoriaOffers,
|
|
41237
41701
|
courseProjects: () => courseProjects,
|
|
41238
41702
|
courseProjectsRelations: () => courseProjectsRelations,
|
|
41239
41703
|
courseProposals: () => courseProposals2,
|
|
@@ -41274,6 +41738,7 @@ __export(schema_exports, {
|
|
|
41274
41738
|
creatorVariationAxesRelations: () => creatorVariationAxesRelations,
|
|
41275
41739
|
creditMovementAuditLog: () => creditMovementAuditLog,
|
|
41276
41740
|
creditMovementAuditLogRelations: () => creditMovementAuditLogRelations,
|
|
41741
|
+
creditOriginEnum: () => creditOriginEnum,
|
|
41277
41742
|
creditPackages: () => creditPackages,
|
|
41278
41743
|
creditStatusEnum: () => creditStatusEnum,
|
|
41279
41744
|
creditSubscriptionPlans: () => creditSubscriptionPlans,
|
|
@@ -41323,6 +41788,7 @@ __export(schema_exports, {
|
|
|
41323
41788
|
helpArticleRatings: () => helpArticleRatings,
|
|
41324
41789
|
ideas: () => ideas,
|
|
41325
41790
|
ideasRelations: () => ideasRelations,
|
|
41791
|
+
insertCourseMentoriaOfferSchema: () => insertCourseMentoriaOfferSchema,
|
|
41326
41792
|
insertMentorshipCreditSchema: () => insertMentorshipCreditSchema,
|
|
41327
41793
|
insertMentorshipPackageSchema: () => insertMentorshipPackageSchema,
|
|
41328
41794
|
insertPlatformSettingSchema: () => insertPlatformSettingSchema,
|
|
@@ -41372,6 +41838,7 @@ __export(schema_exports, {
|
|
|
41372
41838
|
mentorAvailabilityExceptions: () => mentorAvailabilityExceptions2,
|
|
41373
41839
|
mentorAvailabilityExceptionsRelations: () => mentorAvailabilityExceptionsRelations2,
|
|
41374
41840
|
mentorAvailabilityRelations: () => mentorAvailabilityRelations2,
|
|
41841
|
+
mentorSpecializations: () => mentorSpecializations,
|
|
41375
41842
|
mentorshipCredits: () => mentorshipCredits2,
|
|
41376
41843
|
mentorshipCreditsRelations: () => mentorshipCreditsRelations2,
|
|
41377
41844
|
mentorshipMessages: () => mentorshipMessages2,
|
|
@@ -41422,7 +41889,6 @@ __export(schema_exports, {
|
|
|
41422
41889
|
pathStatusEnum: () => pathStatusEnum,
|
|
41423
41890
|
payoutAccounts: () => payoutAccounts,
|
|
41424
41891
|
payoutBankAccounts: () => payoutBankAccounts,
|
|
41425
|
-
payoutFeeConfig: () => payoutFeeConfig,
|
|
41426
41892
|
payoutMethods: () => payoutMethods,
|
|
41427
41893
|
payoutStatusEnum: () => payoutStatusEnum,
|
|
41428
41894
|
payoutTransactions: () => payoutTransactions2,
|
|
@@ -41435,8 +41901,6 @@ __export(schema_exports, {
|
|
|
41435
41901
|
pgBackendIdempotencyKeys: () => pgBackendIdempotencyKeys,
|
|
41436
41902
|
pixKeyTypeEnum: () => pixKeyTypeEnum,
|
|
41437
41903
|
platformConfig: () => platformConfig,
|
|
41438
|
-
platformFeeTypeEnum: () => platformFeeTypeEnum,
|
|
41439
|
-
platformFees: () => platformFees,
|
|
41440
41904
|
platformSettings: () => platformSettings2,
|
|
41441
41905
|
playgroundEvalScores: () => playgroundEvalScores,
|
|
41442
41906
|
playgroundEvalScoresRelations: () => playgroundEvalScoresRelations,
|
|
@@ -41454,6 +41918,7 @@ __export(schema_exports, {
|
|
|
41454
41918
|
portfolioViews: () => portfolioViews,
|
|
41455
41919
|
portfolioViewsRelations: () => portfolioViewsRelations,
|
|
41456
41920
|
pricingTiers: () => pricingTiers,
|
|
41921
|
+
profileVisibilityEnum: () => profileVisibilityEnum,
|
|
41457
41922
|
progress: () => progress,
|
|
41458
41923
|
progressRelations: () => progressRelations2,
|
|
41459
41924
|
progressStatusEnum: () => progressStatusEnum,
|
|
@@ -41559,11 +42024,14 @@ __export(schema_exports, {
|
|
|
41559
42024
|
studyModuleSessionsRelations: () => studyModuleSessionsRelations,
|
|
41560
42025
|
studyPhaseV2Values: () => studyPhaseV2Values,
|
|
41561
42026
|
studyPhaseValues: () => studyPhaseValues,
|
|
42027
|
+
subscriptionPoolStatusEnum: () => subscriptionPoolStatusEnum,
|
|
42028
|
+
subscriptionSplitStatusEnum: () => subscriptionSplitStatusEnum,
|
|
41562
42029
|
supportedCurrencies: () => supportedCurrencies,
|
|
41563
42030
|
syncLogs: () => syncLogs,
|
|
41564
42031
|
syncLogsRelations: () => syncLogsRelations2,
|
|
41565
42032
|
systemConfigs: () => systemConfigs,
|
|
41566
42033
|
systemConfigsRelations: () => systemConfigsRelations,
|
|
42034
|
+
testimonialPlacementEnum: () => testimonialPlacementEnum,
|
|
41567
42035
|
testimonialStatusEnum: () => testimonialStatusEnum,
|
|
41568
42036
|
threadStatusEnum: () => threadStatusEnum,
|
|
41569
42037
|
toneEnum: () => toneEnum,
|
|
@@ -41583,12 +42051,17 @@ __export(schema_exports, {
|
|
|
41583
42051
|
userBadgesRelations: () => userBadgesRelations2,
|
|
41584
42052
|
userChallengeScores: () => userChallengeScores,
|
|
41585
42053
|
userChallengeScoresRelations: () => userChallengeScoresRelations,
|
|
42054
|
+
userDeletionStatusEnum: () => userDeletionStatusEnum,
|
|
42055
|
+
userDeletions: () => userDeletions,
|
|
41586
42056
|
userFollows: () => userFollows2,
|
|
41587
42057
|
userFollowsRelations: () => userFollowsRelations2,
|
|
41588
42058
|
userPathEnrollments: () => userPathEnrollments,
|
|
41589
42059
|
userPathEnrollmentsRelations: () => userPathEnrollmentsRelations,
|
|
41590
42060
|
userPreferences: () => userPreferences,
|
|
42061
|
+
userPreferencesAudits: () => userPreferencesAudits,
|
|
41591
42062
|
userPreferencesRelations: () => userPreferencesRelations2,
|
|
42063
|
+
userProfileAudits: () => userProfileAudits,
|
|
42064
|
+
userProfiles: () => userProfiles,
|
|
41592
42065
|
userRegionalSettings: () => userRegionalSettings,
|
|
41593
42066
|
userRegionalSettingsRelations: () => userRegionalSettingsRelations,
|
|
41594
42067
|
userRoleEnum: () => userRoleEnum,
|
|
@@ -41596,6 +42069,7 @@ __export(schema_exports, {
|
|
|
41596
42069
|
userUsageQuotas: () => userUsageQuotas2,
|
|
41597
42070
|
users: () => users,
|
|
41598
42071
|
usersRelations: () => usersRelations2,
|
|
42072
|
+
v3CancelReasonRedisKey: () => v3CancelReasonRedisKey,
|
|
41599
42073
|
validationAttempts: () => validationAttempts2,
|
|
41600
42074
|
validationAttemptsRelations: () => validationAttemptsRelations2,
|
|
41601
42075
|
validationLessonProgress: () => validationLessonProgress,
|
|
@@ -41616,7 +42090,8 @@ __export(schema_exports, {
|
|
|
41616
42090
|
videoTemplateNameEnum: () => videoTemplateNameEnum,
|
|
41617
42091
|
videoTypeEnum: () => videoTypeEnum,
|
|
41618
42092
|
webhookEvents: () => webhookEvents2,
|
|
41619
|
-
wishlists: () => wishlists
|
|
42093
|
+
wishlists: () => wishlists,
|
|
42094
|
+
withdrawalTaxes: () => withdrawalTaxes
|
|
41620
42095
|
});
|
|
41621
42096
|
var init_schema3 = __esm({
|
|
41622
42097
|
"../../packages/database/src/schema/index.ts"() {
|
|
@@ -41632,6 +42107,7 @@ var init_schema3 = __esm({
|
|
|
41632
42107
|
init_mentorship_index();
|
|
41633
42108
|
init_reviews();
|
|
41634
42109
|
init_payouts();
|
|
42110
|
+
init_subscription_pools();
|
|
41635
42111
|
init_creator_index();
|
|
41636
42112
|
init_webhook_events();
|
|
41637
42113
|
init_transactions();
|
|
@@ -41707,8 +42183,8 @@ var init_schema3 = __esm({
|
|
|
41707
42183
|
init_tutor_content_issues();
|
|
41708
42184
|
init_magic_link_tokens();
|
|
41709
42185
|
init_mobile_refresh_tokens();
|
|
41710
|
-
init_platform_fees();
|
|
41711
42186
|
init_payout_methods();
|
|
42187
|
+
init_withdrawal_taxes();
|
|
41712
42188
|
init_media_assets();
|
|
41713
42189
|
init_push_tokens();
|
|
41714
42190
|
init_payout();
|
|
@@ -41718,6 +42194,9 @@ var init_schema3 = __esm({
|
|
|
41718
42194
|
init_course_visibility();
|
|
41719
42195
|
init_course_allowlist();
|
|
41720
42196
|
init_idempotency();
|
|
42197
|
+
init_user_deletions();
|
|
42198
|
+
init_user_profiles();
|
|
42199
|
+
init_user_resource_audits();
|
|
41721
42200
|
}
|
|
41722
42201
|
});
|
|
41723
42202
|
|
|
@@ -41725,7 +42204,7 @@ var init_schema3 = __esm({
|
|
|
41725
42204
|
var init_check_module_unlocked = __esm({
|
|
41726
42205
|
"../../packages/database/src/utils/check-module-unlocked.ts"() {
|
|
41727
42206
|
"use strict";
|
|
41728
|
-
|
|
42207
|
+
init_src3();
|
|
41729
42208
|
init_schema3();
|
|
41730
42209
|
}
|
|
41731
42210
|
});
|
|
@@ -41754,11 +42233,11 @@ var init_ids = __esm({
|
|
|
41754
42233
|
|
|
41755
42234
|
// ../../packages/database/src/index.ts
|
|
41756
42235
|
var envSchema, _db, createDb, getDb, db;
|
|
41757
|
-
var
|
|
42236
|
+
var init_src3 = __esm({
|
|
41758
42237
|
"../../packages/database/src/index.ts"() {
|
|
41759
42238
|
"use strict";
|
|
41760
42239
|
init_postgres_js();
|
|
41761
|
-
|
|
42240
|
+
init_src();
|
|
41762
42241
|
init_zod();
|
|
41763
42242
|
init_schema3();
|
|
41764
42243
|
init_schema3();
|
|
@@ -41855,7 +42334,7 @@ var init_formats = __esm({
|
|
|
41855
42334
|
var init_parser = __esm({
|
|
41856
42335
|
"../../packages/tostudy-core/src/exercises/parser.ts"() {
|
|
41857
42336
|
"use strict";
|
|
41858
|
-
|
|
42337
|
+
init_src2();
|
|
41859
42338
|
init_formats();
|
|
41860
42339
|
init_formats();
|
|
41861
42340
|
}
|
|
@@ -41879,8 +42358,8 @@ var init_lesson_exercise_data = __esm({
|
|
|
41879
42358
|
var init_sync_enrollment_progress = __esm({
|
|
41880
42359
|
"../../packages/tostudy-core/src/learning/sync-enrollment-progress.ts"() {
|
|
41881
42360
|
"use strict";
|
|
41882
|
-
|
|
41883
|
-
|
|
42361
|
+
init_src3();
|
|
42362
|
+
init_dist();
|
|
41884
42363
|
}
|
|
41885
42364
|
});
|
|
41886
42365
|
|
|
@@ -41889,21 +42368,38 @@ var DEFAULT_MAX_SESSION_TIME_SECONDS;
|
|
|
41889
42368
|
var init_study_state_sync = __esm({
|
|
41890
42369
|
"../../packages/tostudy-core/src/learning/study-state-sync.ts"() {
|
|
41891
42370
|
"use strict";
|
|
41892
|
-
|
|
42371
|
+
init_src3();
|
|
41893
42372
|
DEFAULT_MAX_SESSION_TIME_SECONDS = 2 * 60 * 60;
|
|
41894
42373
|
}
|
|
41895
42374
|
});
|
|
41896
42375
|
|
|
42376
|
+
// ../../packages/tostudy-core/src/enrollments/entitlement.ts
|
|
42377
|
+
var init_entitlement = __esm({
|
|
42378
|
+
"../../packages/tostudy-core/src/enrollments/entitlement.ts"() {
|
|
42379
|
+
"use strict";
|
|
42380
|
+
}
|
|
42381
|
+
});
|
|
42382
|
+
|
|
42383
|
+
// ../../packages/tostudy-core/src/enrollments/archived-access.ts
|
|
42384
|
+
var init_archived_access = __esm({
|
|
42385
|
+
"../../packages/tostudy-core/src/enrollments/archived-access.ts"() {
|
|
42386
|
+
"use strict";
|
|
42387
|
+
init_src3();
|
|
42388
|
+
}
|
|
42389
|
+
});
|
|
42390
|
+
|
|
41897
42391
|
// ../../packages/tostudy-core/src/learning/start-module-full.ts
|
|
41898
42392
|
var init_start_module_full = __esm({
|
|
41899
42393
|
"../../packages/tostudy-core/src/learning/start-module-full.ts"() {
|
|
41900
42394
|
"use strict";
|
|
41901
|
-
|
|
42395
|
+
init_src3();
|
|
41902
42396
|
init_parser();
|
|
41903
42397
|
init_exercise_types();
|
|
41904
42398
|
init_lesson_exercise_data();
|
|
41905
42399
|
init_sync_enrollment_progress();
|
|
41906
42400
|
init_study_state_sync();
|
|
42401
|
+
init_entitlement();
|
|
42402
|
+
init_archived_access();
|
|
41907
42403
|
}
|
|
41908
42404
|
});
|
|
41909
42405
|
|
|
@@ -41911,10 +42407,13 @@ var init_start_module_full = __esm({
|
|
|
41911
42407
|
var init_next_lesson_full = __esm({
|
|
41912
42408
|
"../../packages/tostudy-core/src/learning/next-lesson-full.ts"() {
|
|
41913
42409
|
"use strict";
|
|
41914
|
-
|
|
42410
|
+
init_src3();
|
|
42411
|
+
init_dist();
|
|
41915
42412
|
init_parser();
|
|
41916
42413
|
init_lesson_exercise_data();
|
|
41917
42414
|
init_sync_enrollment_progress();
|
|
42415
|
+
init_entitlement();
|
|
42416
|
+
init_archived_access();
|
|
41918
42417
|
init_study_state_sync();
|
|
41919
42418
|
}
|
|
41920
42419
|
});
|
|
@@ -41923,8 +42422,8 @@ var init_next_lesson_full = __esm({
|
|
|
41923
42422
|
var init_student_memory = __esm({
|
|
41924
42423
|
"../../packages/tostudy-core/src/memory/student-memory.ts"() {
|
|
41925
42424
|
"use strict";
|
|
41926
|
-
|
|
41927
|
-
|
|
42425
|
+
init_src3();
|
|
42426
|
+
init_dist();
|
|
41928
42427
|
}
|
|
41929
42428
|
});
|
|
41930
42429
|
|
|
@@ -41932,7 +42431,7 @@ var init_student_memory = __esm({
|
|
|
41932
42431
|
var init_summarize_lesson = __esm({
|
|
41933
42432
|
"../../packages/tostudy-core/src/learning/summarize-lesson.ts"() {
|
|
41934
42433
|
"use strict";
|
|
41935
|
-
|
|
42434
|
+
init_dist();
|
|
41936
42435
|
}
|
|
41937
42436
|
});
|
|
41938
42437
|
|
|
@@ -41940,14 +42439,16 @@ var init_summarize_lesson = __esm({
|
|
|
41940
42439
|
var init_validate_solution_full = __esm({
|
|
41941
42440
|
"../../packages/tostudy-core/src/learning/validate-solution-full.ts"() {
|
|
41942
42441
|
"use strict";
|
|
41943
|
-
|
|
41944
|
-
|
|
42442
|
+
init_src3();
|
|
42443
|
+
init_dist();
|
|
41945
42444
|
init_parser();
|
|
41946
42445
|
init_extractors();
|
|
41947
42446
|
init_exercise_types();
|
|
41948
42447
|
init_study_state_sync();
|
|
41949
42448
|
init_sync_enrollment_progress();
|
|
41950
42449
|
init_student_memory();
|
|
42450
|
+
init_entitlement();
|
|
42451
|
+
init_archived_access();
|
|
41951
42452
|
init_summarize_lesson();
|
|
41952
42453
|
}
|
|
41953
42454
|
});
|
|
@@ -41956,8 +42457,10 @@ var init_validate_solution_full = __esm({
|
|
|
41956
42457
|
var init_go_to_lesson = __esm({
|
|
41957
42458
|
"../../packages/tostudy-core/src/learning/go-to-lesson.ts"() {
|
|
41958
42459
|
"use strict";
|
|
41959
|
-
|
|
42460
|
+
init_src3();
|
|
41960
42461
|
init_parser();
|
|
42462
|
+
init_entitlement();
|
|
42463
|
+
init_archived_access();
|
|
41961
42464
|
}
|
|
41962
42465
|
});
|
|
41963
42466
|
|
|
@@ -41965,8 +42468,9 @@ var init_go_to_lesson = __esm({
|
|
|
41965
42468
|
var init_get_lesson_content_full = __esm({
|
|
41966
42469
|
"../../packages/tostudy-core/src/learning/get-lesson-content-full.ts"() {
|
|
41967
42470
|
"use strict";
|
|
41968
|
-
|
|
42471
|
+
init_src3();
|
|
41969
42472
|
init_parser();
|
|
42473
|
+
init_entitlement();
|
|
41970
42474
|
}
|
|
41971
42475
|
});
|
|
41972
42476
|
|
|
@@ -41982,9 +42486,11 @@ var init_formatter2 = __esm({
|
|
|
41982
42486
|
var init_get_hint_full = __esm({
|
|
41983
42487
|
"../../packages/tostudy-core/src/learning/get-hint-full.ts"() {
|
|
41984
42488
|
"use strict";
|
|
41985
|
-
|
|
42489
|
+
init_src3();
|
|
41986
42490
|
init_parser();
|
|
41987
42491
|
init_formatter2();
|
|
42492
|
+
init_entitlement();
|
|
42493
|
+
init_archived_access();
|
|
41988
42494
|
}
|
|
41989
42495
|
});
|
|
41990
42496
|
|
|
@@ -41992,8 +42498,8 @@ var init_get_hint_full = __esm({
|
|
|
41992
42498
|
var init_explain_concept = __esm({
|
|
41993
42499
|
"../../packages/tostudy-core/src/learning/explain-concept.ts"() {
|
|
41994
42500
|
"use strict";
|
|
41995
|
-
|
|
41996
|
-
|
|
42501
|
+
init_src3();
|
|
42502
|
+
init_dist();
|
|
41997
42503
|
}
|
|
41998
42504
|
});
|
|
41999
42505
|
|
|
@@ -42033,10 +42539,6 @@ async function runStart(opts, deps = defaultDeps3) {
|
|
|
42033
42539
|
const session = await deps.requireSession();
|
|
42034
42540
|
const activeCourse = await deps.requireActiveCourse();
|
|
42035
42541
|
const onboarding = await deps.getCourseOnboardingStatus(activeCourse);
|
|
42036
|
-
if (!onboarding.initReady) {
|
|
42037
|
-
deps.stderrWrite(`Dica: rode \`tostudy init\` para personalizar o tutor ao seu contexto.
|
|
42038
|
-
`);
|
|
42039
|
-
}
|
|
42040
42542
|
const driftWarning = await deps.checkCourseDrift();
|
|
42041
42543
|
if (driftWarning) deps.stderrWrite(driftWarning + "\n");
|
|
42042
42544
|
const data = deps.createHttpProvider(session.apiUrl, session.token);
|
|
@@ -42055,15 +42557,22 @@ async function runStart(opts, deps = defaultDeps3) {
|
|
|
42055
42557
|
} else {
|
|
42056
42558
|
deps.output(deps.formatModuleStart(moduleData), { json: false });
|
|
42057
42559
|
}
|
|
42560
|
+
if (!onboarding.initReady) {
|
|
42561
|
+
deps.stderrWrite(`Dica: rode \`tostudy init\` para personalizar o tutor ao seu contexto.
|
|
42562
|
+
`);
|
|
42563
|
+
}
|
|
42058
42564
|
} catch (err) {
|
|
42059
42565
|
if (err instanceof CliApiError && err.status === 403 && err.message === "CHANNEL_MISMATCH") {
|
|
42060
42566
|
process.stderr.write("Este curso n\xE3o est\xE1 dispon\xEDvel via CLI.\n");
|
|
42061
42567
|
process.stderr.write("Acesse tostudy.ai para estudar este curso pelo ChatStudy.\n");
|
|
42062
42568
|
process.exit(1);
|
|
42063
42569
|
}
|
|
42064
|
-
if (err
|
|
42065
|
-
|
|
42066
|
-
process.
|
|
42570
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42571
|
+
deps.stderrWrite(getErrors().enrollmentNotEntitled);
|
|
42572
|
+
process.exit(1);
|
|
42573
|
+
}
|
|
42574
|
+
if (isCourseArchivedError(err)) {
|
|
42575
|
+
deps.stderrWrite(getErrors().courseArchived);
|
|
42067
42576
|
process.exit(1);
|
|
42068
42577
|
}
|
|
42069
42578
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -42074,7 +42583,7 @@ var logger9, defaultDeps3, startCommand;
|
|
|
42074
42583
|
var init_start = __esm({
|
|
42075
42584
|
"src/commands/start.ts"() {
|
|
42076
42585
|
"use strict";
|
|
42077
|
-
|
|
42586
|
+
init_dist();
|
|
42078
42587
|
init_lessons2();
|
|
42079
42588
|
init_http();
|
|
42080
42589
|
init_guards();
|
|
@@ -42082,6 +42591,7 @@ var init_start = __esm({
|
|
|
42082
42591
|
init_workspace_state();
|
|
42083
42592
|
init_status();
|
|
42084
42593
|
init_formatter();
|
|
42594
|
+
init_errors();
|
|
42085
42595
|
logger9 = createLogger("cli:start");
|
|
42086
42596
|
defaultDeps3 = {
|
|
42087
42597
|
requireSession,
|
|
@@ -42110,13 +42620,14 @@ var logger10, startNextCommand;
|
|
|
42110
42620
|
var init_start_next = __esm({
|
|
42111
42621
|
"src/commands/start-next.ts"() {
|
|
42112
42622
|
"use strict";
|
|
42113
|
-
|
|
42623
|
+
init_dist();
|
|
42114
42624
|
init_lessons2();
|
|
42115
42625
|
init_http();
|
|
42116
42626
|
init_guards();
|
|
42117
42627
|
init_course_state();
|
|
42118
42628
|
init_workspace_state();
|
|
42119
42629
|
init_formatter();
|
|
42630
|
+
init_errors();
|
|
42120
42631
|
logger10 = createLogger("cli:start-next");
|
|
42121
42632
|
startNextCommand = new Command9("start-next").description("Transition to the next module after completing the current one").option("--json", "Output structured JSON").action(async (opts) => {
|
|
42122
42633
|
try {
|
|
@@ -42144,9 +42655,12 @@ var init_start_next = __esm({
|
|
|
42144
42655
|
process.stderr.write("\u2192 tostudy courses para ver outros cursos\n");
|
|
42145
42656
|
process.exit(0);
|
|
42146
42657
|
}
|
|
42147
|
-
if (err
|
|
42148
|
-
process.stderr.write(
|
|
42149
|
-
process.
|
|
42658
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42659
|
+
process.stderr.write(getErrors().enrollmentNotEntitled);
|
|
42660
|
+
process.exit(1);
|
|
42661
|
+
}
|
|
42662
|
+
if (isCourseArchivedError(err)) {
|
|
42663
|
+
process.stderr.write(getErrors().courseArchived);
|
|
42150
42664
|
process.exit(1);
|
|
42151
42665
|
}
|
|
42152
42666
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -42163,13 +42677,14 @@ var logger11, nextCommand;
|
|
|
42163
42677
|
var init_next = __esm({
|
|
42164
42678
|
"src/commands/next.ts"() {
|
|
42165
42679
|
"use strict";
|
|
42166
|
-
|
|
42680
|
+
init_dist();
|
|
42167
42681
|
init_lessons2();
|
|
42168
42682
|
init_http();
|
|
42169
42683
|
init_guards();
|
|
42170
42684
|
init_course_state();
|
|
42171
42685
|
init_workspace_state();
|
|
42172
42686
|
init_formatter();
|
|
42687
|
+
init_errors();
|
|
42173
42688
|
logger11 = createLogger("cli:next");
|
|
42174
42689
|
nextCommand = new Command10("next").description("Advance to the next lesson in the active course").option("--json", "Output structured JSON").action(async (opts) => {
|
|
42175
42690
|
try {
|
|
@@ -42195,6 +42710,18 @@ var init_next = __esm({
|
|
|
42195
42710
|
output(formatLesson(lessonData), { json: false });
|
|
42196
42711
|
}
|
|
42197
42712
|
} catch (err) {
|
|
42713
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42714
|
+
const friendly = getErrors().enrollmentNotEntitled;
|
|
42715
|
+
if (opts.json) jsonError("enrollment_not_entitled", { message: friendly });
|
|
42716
|
+
process.stderr.write(friendly);
|
|
42717
|
+
process.exit(1);
|
|
42718
|
+
}
|
|
42719
|
+
if (isCourseArchivedError(err)) {
|
|
42720
|
+
const friendly = getErrors().courseArchived;
|
|
42721
|
+
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
42722
|
+
process.stderr.write(friendly);
|
|
42723
|
+
process.exit(1);
|
|
42724
|
+
}
|
|
42198
42725
|
if (err instanceof CliApiError) {
|
|
42199
42726
|
if (err.status === 403 && err.message === "CHANNEL_MISMATCH") {
|
|
42200
42727
|
process.stderr.write("Este curso n\xE3o est\xE1 dispon\xEDvel via CLI.\n");
|
|
@@ -42227,6 +42754,7 @@ var init_next = __esm({
|
|
|
42227
42754
|
|
|
42228
42755
|
// src/commands/lesson.ts
|
|
42229
42756
|
import { Command as Command11 } from "commander";
|
|
42757
|
+
import path13 from "node:path";
|
|
42230
42758
|
function adjustTimeEstimate(type, baseMinutes) {
|
|
42231
42759
|
if (type === "exercise") return Math.max(baseMinutes, 30);
|
|
42232
42760
|
return baseMinutes;
|
|
@@ -42234,15 +42762,29 @@ function adjustTimeEstimate(type, baseMinutes) {
|
|
|
42234
42762
|
function isCheckpoint(title) {
|
|
42235
42763
|
return /^checkpoint/i.test(title.trim());
|
|
42236
42764
|
}
|
|
42237
|
-
function
|
|
42765
|
+
function replacePlaceholders(text2, workspacePath, courseTitle) {
|
|
42766
|
+
const base = path13.basename(workspacePath) === ".tostudy" ? path13.dirname(workspacePath) : workspacePath;
|
|
42767
|
+
const slug = courseSlug(courseTitle);
|
|
42768
|
+
const vaultPath = resolveVaultPath(workspacePath, slug);
|
|
42769
|
+
return text2.replaceAll("$WORKSPACE", base).replaceAll("$VAULT", vaultPath);
|
|
42770
|
+
}
|
|
42771
|
+
function formatLessonContent(data, workspacePath, courseTitle) {
|
|
42238
42772
|
const time4 = adjustTimeEstimate(data.type, data.estimatedTimeMinutes);
|
|
42239
|
-
const
|
|
42240
|
-
|
|
42241
|
-
|
|
42242
|
-
|
|
42243
|
-
|
|
42244
|
-
|
|
42245
|
-
|
|
42773
|
+
const isPractical = data.type === "exercise" || isCheckpoint(data.title);
|
|
42774
|
+
const lines = [`\u2501\u2501\u2501 Li\xE7\xE3o: ${data.title} \u2501\u2501\u2501`];
|
|
42775
|
+
if (isPractical && workspacePath) {
|
|
42776
|
+
const base = path13.basename(workspacePath) === ".tostudy" ? path13.dirname(workspacePath) : workspacePath;
|
|
42777
|
+
const slug = courseSlug(courseTitle);
|
|
42778
|
+
const vaultPath = resolveVaultPath(workspacePath, slug);
|
|
42779
|
+
lines.push(
|
|
42780
|
+
`Pasta de trabalho (workspace): ${base}`,
|
|
42781
|
+
`Cofre Obsidian (vault): ${vaultPath}`,
|
|
42782
|
+
""
|
|
42783
|
+
);
|
|
42784
|
+
} else {
|
|
42785
|
+
lines.push("");
|
|
42786
|
+
}
|
|
42787
|
+
lines.push(`Tipo: ${data.type} | Dura\xE7\xE3o estimada: ~${time4} min`, "", data.content);
|
|
42246
42788
|
if (data.acceptanceCriteria) {
|
|
42247
42789
|
lines.push("", "Crit\xE9rios de aceita\xE7\xE3o:", data.acceptanceCriteria);
|
|
42248
42790
|
}
|
|
@@ -42269,8 +42811,9 @@ var logger12, lessonCommand;
|
|
|
42269
42811
|
var init_lesson = __esm({
|
|
42270
42812
|
"src/commands/lesson.ts"() {
|
|
42271
42813
|
"use strict";
|
|
42272
|
-
|
|
42814
|
+
init_dist();
|
|
42273
42815
|
init_lessons2();
|
|
42816
|
+
init_courses();
|
|
42274
42817
|
init_http();
|
|
42275
42818
|
init_guards();
|
|
42276
42819
|
init_course_state();
|
|
@@ -42278,7 +42821,10 @@ var init_lesson = __esm({
|
|
|
42278
42821
|
init_resolve();
|
|
42279
42822
|
init_errors();
|
|
42280
42823
|
logger12 = createLogger("cli:lesson");
|
|
42281
|
-
lessonCommand = new Command11("lesson").description("Show the content of the current lesson").option("--json", "Output structured JSON").
|
|
42824
|
+
lessonCommand = new Command11("lesson").description("Show the content of the current lesson").option("--json", "Output structured JSON").option(
|
|
42825
|
+
"--read <lessonId>",
|
|
42826
|
+
"Read a specific lesson by id (works on archived / read-only courses)"
|
|
42827
|
+
).action(async (opts) => {
|
|
42282
42828
|
try {
|
|
42283
42829
|
const session = await requireSession();
|
|
42284
42830
|
const activeCourse = await requireActiveCourse();
|
|
@@ -42286,30 +42832,68 @@ var init_lesson = __esm({
|
|
|
42286
42832
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
42287
42833
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
42288
42834
|
const deps = { data, logger: logger12 };
|
|
42289
|
-
|
|
42835
|
+
let lessonId = opts.read ?? activeCourse.currentLessonId;
|
|
42290
42836
|
if (!lessonId) {
|
|
42291
|
-
|
|
42292
|
-
|
|
42837
|
+
try {
|
|
42838
|
+
const prog = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
42839
|
+
lessonId = prog.currentLesson?.id || void 0;
|
|
42840
|
+
if (prog.isArchived) {
|
|
42841
|
+
process.stderr.write("\u2139 Curso arquivado \u2014 modo leitura.\n");
|
|
42842
|
+
}
|
|
42843
|
+
} catch {
|
|
42844
|
+
}
|
|
42845
|
+
}
|
|
42846
|
+
if (!lessonId) {
|
|
42847
|
+
if (opts.json)
|
|
42848
|
+
jsonError("no_active_lesson", { message: "Nenhuma li\xE7\xE3o encontrada para leitura" });
|
|
42849
|
+
error("Nenhuma li\xE7\xE3o encontrada para leitura. Rode: tostudy start ou tostudy next");
|
|
42293
42850
|
}
|
|
42294
42851
|
const content = await getContent({ lessonId, enrollmentId: activeCourse.enrollmentId }, deps);
|
|
42852
|
+
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
42853
|
+
const ws = await resolveEffectiveWorkspace(
|
|
42854
|
+
activeCourse.courseTitle,
|
|
42855
|
+
onboardingState?.workspacePath
|
|
42856
|
+
);
|
|
42857
|
+
if (ws.found && ws.workspacePath) {
|
|
42858
|
+
if (content.content) {
|
|
42859
|
+
content.content = replacePlaceholders(
|
|
42860
|
+
content.content,
|
|
42861
|
+
ws.workspacePath,
|
|
42862
|
+
activeCourse.courseTitle
|
|
42863
|
+
);
|
|
42864
|
+
}
|
|
42865
|
+
if (content.acceptanceCriteria) {
|
|
42866
|
+
content.acceptanceCriteria = replacePlaceholders(
|
|
42867
|
+
content.acceptanceCriteria,
|
|
42868
|
+
ws.workspacePath,
|
|
42869
|
+
activeCourse.courseTitle
|
|
42870
|
+
);
|
|
42871
|
+
}
|
|
42872
|
+
}
|
|
42295
42873
|
if (opts.json) {
|
|
42296
42874
|
output(content, { json: true });
|
|
42297
42875
|
} else {
|
|
42298
|
-
output(
|
|
42876
|
+
output(
|
|
42877
|
+
formatLessonContent(
|
|
42878
|
+
content,
|
|
42879
|
+
ws.found ? ws.workspacePath : null,
|
|
42880
|
+
activeCourse.courseTitle
|
|
42881
|
+
),
|
|
42882
|
+
{ json: false }
|
|
42883
|
+
);
|
|
42299
42884
|
}
|
|
42300
|
-
if (content.type === "exercise") {
|
|
42301
|
-
|
|
42302
|
-
|
|
42303
|
-
activeCourse.courseTitle,
|
|
42304
|
-
onboardingState?.workspacePath
|
|
42885
|
+
if (content.type === "exercise" && !ws.found) {
|
|
42886
|
+
process.stderr.write(
|
|
42887
|
+
"\n\u{1F4A1} Dica: rode `tostudy select` desta pasta para us\xE1-la como workspace, ou `tostudy workspace setup` para criar em ~/study/.\n"
|
|
42305
42888
|
);
|
|
42306
|
-
if (!ws.found) {
|
|
42307
|
-
process.stderr.write(
|
|
42308
|
-
"\n\u{1F4A1} Dica: rode `tostudy select` desta pasta para us\xE1-la como workspace, ou `tostudy workspace setup` para criar em ~/study/.\n"
|
|
42309
|
-
);
|
|
42310
|
-
}
|
|
42311
42889
|
}
|
|
42312
42890
|
} catch (err) {
|
|
42891
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42892
|
+
const friendly = getErrors().enrollmentNotEntitled;
|
|
42893
|
+
if (opts.json) jsonError("enrollment_not_entitled", { message: friendly });
|
|
42894
|
+
else process.stderr.write(friendly);
|
|
42895
|
+
process.exit(1);
|
|
42896
|
+
}
|
|
42313
42897
|
if (isInsufficientCreditsError(err)) {
|
|
42314
42898
|
const friendly = getErrors().insufficientCredits;
|
|
42315
42899
|
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
@@ -42330,7 +42914,7 @@ var logger13, hintCommand;
|
|
|
42330
42914
|
var init_hint = __esm({
|
|
42331
42915
|
"src/commands/hint.ts"() {
|
|
42332
42916
|
"use strict";
|
|
42333
|
-
|
|
42917
|
+
init_dist();
|
|
42334
42918
|
init_lessons2();
|
|
42335
42919
|
init_http();
|
|
42336
42920
|
init_guards();
|
|
@@ -42356,6 +42940,18 @@ var init_hint = __esm({
|
|
|
42356
42940
|
output(formatHint(hint), { json: false });
|
|
42357
42941
|
}
|
|
42358
42942
|
} catch (err) {
|
|
42943
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42944
|
+
const friendly = getErrors().enrollmentNotEntitled;
|
|
42945
|
+
if (opts.json) jsonError("enrollment_not_entitled", { message: friendly });
|
|
42946
|
+
else process.stderr.write(friendly);
|
|
42947
|
+
process.exit(1);
|
|
42948
|
+
}
|
|
42949
|
+
if (isCourseArchivedError(err)) {
|
|
42950
|
+
const friendly = getErrors().courseArchived;
|
|
42951
|
+
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
42952
|
+
else process.stderr.write(friendly);
|
|
42953
|
+
process.exit(1);
|
|
42954
|
+
}
|
|
42359
42955
|
if (isInsufficientCreditsError(err)) {
|
|
42360
42956
|
const friendly = getErrors().insufficientCredits;
|
|
42361
42957
|
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
@@ -42390,7 +42986,7 @@ var init_validate_solution = __esm({
|
|
|
42390
42986
|
var init_level_validator = __esm({
|
|
42391
42987
|
"../../packages/tostudy-core/src/exercises/level-validator.ts"() {
|
|
42392
42988
|
"use strict";
|
|
42393
|
-
|
|
42989
|
+
init_src2();
|
|
42394
42990
|
}
|
|
42395
42991
|
});
|
|
42396
42992
|
|
|
@@ -42685,14 +43281,15 @@ var init_init_template = __esm({
|
|
|
42685
43281
|
|
|
42686
43282
|
// src/commands/validate.ts
|
|
42687
43283
|
import fs12 from "node:fs";
|
|
42688
|
-
import
|
|
43284
|
+
import path14 from "node:path";
|
|
42689
43285
|
import { Command as Command13 } from "commander";
|
|
42690
43286
|
var logger14, validateCommand;
|
|
42691
43287
|
var init_validate = __esm({
|
|
42692
43288
|
"src/commands/validate.ts"() {
|
|
42693
43289
|
"use strict";
|
|
42694
|
-
|
|
43290
|
+
init_dist();
|
|
42695
43291
|
init_exercises();
|
|
43292
|
+
init_courses();
|
|
42696
43293
|
init_http();
|
|
42697
43294
|
init_guards();
|
|
42698
43295
|
init_course_state();
|
|
@@ -42706,7 +43303,22 @@ var init_validate = __esm({
|
|
|
42706
43303
|
const activeCourse = await requireActiveCourse();
|
|
42707
43304
|
const driftWarning = await checkCourseDrift();
|
|
42708
43305
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
42709
|
-
const
|
|
43306
|
+
const data = createHttpProvider(session.apiUrl, session.token);
|
|
43307
|
+
const deps = { data, logger: logger14 };
|
|
43308
|
+
let lessonId = activeCourse.currentLessonId;
|
|
43309
|
+
if (!lessonId) {
|
|
43310
|
+
try {
|
|
43311
|
+
const prog = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
43312
|
+
if (prog.isArchived) {
|
|
43313
|
+
const friendly = getErrors().courseArchived;
|
|
43314
|
+
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
43315
|
+
else process.stderr.write(friendly);
|
|
43316
|
+
process.exit(1);
|
|
43317
|
+
}
|
|
43318
|
+
lessonId = prog.currentLesson?.id || void 0;
|
|
43319
|
+
} catch {
|
|
43320
|
+
}
|
|
43321
|
+
}
|
|
42710
43322
|
if (!lessonId) {
|
|
42711
43323
|
if (opts.json) jsonError("no_active_lesson", { message: "Nenhuma li\xE7\xE3o ativa encontrada" });
|
|
42712
43324
|
error("Nenhuma li\xE7\xE3o ativa encontrada. Rode: tostudy start ou tostudy next");
|
|
@@ -42727,7 +43339,7 @@ var init_validate = __esm({
|
|
|
42727
43339
|
error("Forne\xE7a um arquivo ou use --stdin.\n\nExemplo: tostudy validate resposta.md");
|
|
42728
43340
|
}
|
|
42729
43341
|
if (file2 && activeCourse.courseTags?.length) {
|
|
42730
|
-
const ext =
|
|
43342
|
+
const ext = path14.extname(file2).toLowerCase();
|
|
42731
43343
|
const LANG_EXTENSIONS = {
|
|
42732
43344
|
".html": ["html", "html5"],
|
|
42733
43345
|
".css": ["css"],
|
|
@@ -42762,8 +43374,6 @@ var init_validate = __esm({
|
|
|
42762
43374
|
}
|
|
42763
43375
|
}
|
|
42764
43376
|
}
|
|
42765
|
-
const data = createHttpProvider(session.apiUrl, session.token);
|
|
42766
|
-
const deps = { data, logger: logger14 };
|
|
42767
43377
|
const result = await validateSolution(
|
|
42768
43378
|
{
|
|
42769
43379
|
lessonId,
|
|
@@ -42780,6 +43390,18 @@ var init_validate = __esm({
|
|
|
42780
43390
|
}
|
|
42781
43391
|
process.exit(result.passed ? 0 : 1);
|
|
42782
43392
|
} catch (err) {
|
|
43393
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
43394
|
+
const friendly = getErrors().enrollmentNotEntitled;
|
|
43395
|
+
if (opts.json) jsonError("enrollment_not_entitled", { message: friendly });
|
|
43396
|
+
else process.stderr.write(friendly);
|
|
43397
|
+
process.exit(1);
|
|
43398
|
+
}
|
|
43399
|
+
if (isCourseArchivedError(err)) {
|
|
43400
|
+
const friendly = getErrors().courseArchived;
|
|
43401
|
+
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
43402
|
+
else process.stderr.write(friendly);
|
|
43403
|
+
process.exit(1);
|
|
43404
|
+
}
|
|
42783
43405
|
if (isInsufficientCreditsError(err)) {
|
|
42784
43406
|
const friendly = getErrors().insufficientCredits;
|
|
42785
43407
|
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
@@ -43135,7 +43757,7 @@ var logger15, defaultDeps4, initCommand;
|
|
|
43135
43757
|
var init_init = __esm({
|
|
43136
43758
|
"src/commands/init.ts"() {
|
|
43137
43759
|
"use strict";
|
|
43138
|
-
|
|
43760
|
+
init_dist();
|
|
43139
43761
|
init_courses();
|
|
43140
43762
|
init_http();
|
|
43141
43763
|
init_session_store();
|
|
@@ -43174,13 +43796,13 @@ var init_init = __esm({
|
|
|
43174
43796
|
|
|
43175
43797
|
// ../../packages/tostudy-core/src/workspace/setup-workspace.ts
|
|
43176
43798
|
import fs13 from "node:fs/promises";
|
|
43177
|
-
import
|
|
43799
|
+
import path15 from "node:path";
|
|
43178
43800
|
async function setupWorkspace(input2) {
|
|
43179
|
-
const workspacePath =
|
|
43801
|
+
const workspacePath = path15.join(input2.basePath, input2.courseSlug);
|
|
43180
43802
|
for (const dir of WORKSPACE_DIRS) {
|
|
43181
|
-
await fs13.mkdir(
|
|
43803
|
+
await fs13.mkdir(path15.join(workspacePath, dir), { recursive: true });
|
|
43182
43804
|
}
|
|
43183
|
-
const configPath =
|
|
43805
|
+
const configPath = path15.join(workspacePath, ".ana-config.json");
|
|
43184
43806
|
const config2 = {
|
|
43185
43807
|
courseId: input2.courseId,
|
|
43186
43808
|
courseSlug: input2.courseSlug,
|
|
@@ -43215,7 +43837,7 @@ async function setupWorkspace(input2) {
|
|
|
43215
43837
|
"tostudy vault sync # Sincronizar progresso",
|
|
43216
43838
|
"```"
|
|
43217
43839
|
].join("\n");
|
|
43218
|
-
await fs13.writeFile(
|
|
43840
|
+
await fs13.writeFile(path15.join(workspacePath, "README.md"), readme, "utf-8");
|
|
43219
43841
|
return { workspacePath, directories: WORKSPACE_DIRS, configPath };
|
|
43220
43842
|
}
|
|
43221
43843
|
var WORKSPACE_DIRS;
|
|
@@ -43317,7 +43939,7 @@ var init_templates = __esm({
|
|
|
43317
43939
|
|
|
43318
43940
|
// ../../packages/tostudy-core/src/workspace/extract-exercise.ts
|
|
43319
43941
|
import fs14 from "node:fs/promises";
|
|
43320
|
-
import
|
|
43942
|
+
import path16 from "node:path";
|
|
43321
43943
|
function padOrder(n) {
|
|
43322
43944
|
return String(n).padStart(2, "0");
|
|
43323
43945
|
}
|
|
@@ -43341,15 +43963,15 @@ async function extractExercise(input2) {
|
|
|
43341
43963
|
const { lessonData, exerciseTier, workspacePath } = input2;
|
|
43342
43964
|
const moduleDir = `${padOrder(lessonData.moduleOrder)}-${lessonData.moduleSlug}`;
|
|
43343
43965
|
const lessonDir = `${padOrder(lessonData.lessonOrder)}-${lessonData.lessonSlug}`;
|
|
43344
|
-
const exercisePath =
|
|
43966
|
+
const exercisePath = path16.join(workspacePath, "exercises", moduleDir, lessonDir);
|
|
43345
43967
|
await fs14.mkdir(exercisePath, { recursive: true });
|
|
43346
43968
|
const extractedFiles = [];
|
|
43347
43969
|
let hasStarterCode = false;
|
|
43348
43970
|
if (lessonData.sandpackConfig?.files) {
|
|
43349
43971
|
for (const [filePath, fileData] of Object.entries(lessonData.sandpackConfig.files)) {
|
|
43350
43972
|
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
43351
|
-
const fullPath =
|
|
43352
|
-
await fs14.mkdir(
|
|
43973
|
+
const fullPath = path16.join(exercisePath, cleanPath);
|
|
43974
|
+
await fs14.mkdir(path16.dirname(fullPath), { recursive: true });
|
|
43353
43975
|
await fs14.writeFile(fullPath, fileData.code, "utf-8");
|
|
43354
43976
|
extractedFiles.push(cleanPath);
|
|
43355
43977
|
hasStarterCode = true;
|
|
@@ -43358,13 +43980,13 @@ async function extractExercise(input2) {
|
|
|
43358
43980
|
const tierData = getTierData(lessonData.structuredData, exerciseTier);
|
|
43359
43981
|
const tierCode = tierData?.code;
|
|
43360
43982
|
if (tierCode) {
|
|
43361
|
-
await fs14.writeFile(
|
|
43983
|
+
await fs14.writeFile(path16.join(exercisePath, "exercise.js"), tierCode, "utf-8");
|
|
43362
43984
|
extractedFiles.push("exercise.js");
|
|
43363
43985
|
hasStarterCode = true;
|
|
43364
43986
|
} else {
|
|
43365
43987
|
const starter = getStarterCode(lessonData.structuredData);
|
|
43366
43988
|
if (starter) {
|
|
43367
|
-
await fs14.writeFile(
|
|
43989
|
+
await fs14.writeFile(path16.join(exercisePath, "exercise.js"), starter, "utf-8");
|
|
43368
43990
|
extractedFiles.push("exercise.js");
|
|
43369
43991
|
hasStarterCode = true;
|
|
43370
43992
|
}
|
|
@@ -43383,7 +44005,7 @@ async function extractExercise(input2) {
|
|
|
43383
44005
|
}
|
|
43384
44006
|
};
|
|
43385
44007
|
await fs14.writeFile(
|
|
43386
|
-
|
|
44008
|
+
path16.join(exercisePath, "package.json"),
|
|
43387
44009
|
JSON.stringify(pkgJson, null, 2),
|
|
43388
44010
|
"utf-8"
|
|
43389
44011
|
);
|
|
@@ -43395,19 +44017,19 @@ async function extractExercise(input2) {
|
|
|
43395
44017
|
);
|
|
43396
44018
|
for (const [configFile, configContent] of Object.entries(scaffold.configs)) {
|
|
43397
44019
|
if (!sandpackFileNames.has(configFile)) {
|
|
43398
|
-
await fs14.writeFile(
|
|
44020
|
+
await fs14.writeFile(path16.join(exercisePath, configFile), configContent, "utf-8");
|
|
43399
44021
|
extractedFiles.push(configFile);
|
|
43400
44022
|
}
|
|
43401
44023
|
}
|
|
43402
44024
|
const setupSh = `#!/bin/sh
|
|
43403
44025
|
${scaffold.setupScript}
|
|
43404
44026
|
`;
|
|
43405
|
-
await fs14.writeFile(
|
|
44027
|
+
await fs14.writeFile(path16.join(exercisePath, "setup.sh"), setupSh, "utf-8");
|
|
43406
44028
|
extractedFiles.push("setup.sh");
|
|
43407
44029
|
}
|
|
43408
44030
|
}
|
|
43409
44031
|
const readme = generateReadme(lessonData, exerciseTier);
|
|
43410
|
-
const readmePath =
|
|
44032
|
+
const readmePath = path16.join(exercisePath, "README.md");
|
|
43411
44033
|
await fs14.writeFile(readmePath, readme, "utf-8");
|
|
43412
44034
|
extractedFiles.push("README.md");
|
|
43413
44035
|
return {
|
|
@@ -43480,14 +44102,14 @@ var init_workspace = __esm({
|
|
|
43480
44102
|
|
|
43481
44103
|
// src/commands/workspace.ts
|
|
43482
44104
|
import { Command as Command16 } from "commander";
|
|
43483
|
-
import
|
|
43484
|
-
import
|
|
44105
|
+
import path17 from "node:path";
|
|
44106
|
+
import os9 from "node:os";
|
|
43485
44107
|
import fs15 from "node:fs/promises";
|
|
43486
44108
|
var logger16, workspaceCommand;
|
|
43487
44109
|
var init_workspace2 = __esm({
|
|
43488
44110
|
"src/commands/workspace.ts"() {
|
|
43489
44111
|
"use strict";
|
|
43490
|
-
|
|
44112
|
+
init_dist();
|
|
43491
44113
|
init_workspace();
|
|
43492
44114
|
init_guards();
|
|
43493
44115
|
init_course_state();
|
|
@@ -43506,13 +44128,13 @@ var init_workspace2 = __esm({
|
|
|
43506
44128
|
let directories;
|
|
43507
44129
|
if (!opts.path && cwdIsWorkspace) {
|
|
43508
44130
|
const resolvedCwd = await resolveCwdWorkspacePath(process.cwd());
|
|
43509
|
-
workspacePath = resolvedCwd ??
|
|
44131
|
+
workspacePath = resolvedCwd ?? path17.join(process.cwd(), ".tostudy");
|
|
43510
44132
|
await fs15.mkdir(workspacePath, { recursive: true });
|
|
43511
44133
|
directories = ["exercises", "generated", "notes", "diagrams"];
|
|
43512
44134
|
for (const dir of directories) {
|
|
43513
|
-
await fs15.mkdir(
|
|
44135
|
+
await fs15.mkdir(path17.join(workspacePath, dir), { recursive: true });
|
|
43514
44136
|
}
|
|
43515
|
-
const configPath =
|
|
44137
|
+
const configPath = path17.join(workspacePath, ".ana-config.json");
|
|
43516
44138
|
await fs15.writeFile(
|
|
43517
44139
|
configPath,
|
|
43518
44140
|
JSON.stringify(
|
|
@@ -43531,7 +44153,7 @@ var init_workspace2 = __esm({
|
|
|
43531
44153
|
"utf-8"
|
|
43532
44154
|
);
|
|
43533
44155
|
} else {
|
|
43534
|
-
const basePath = opts.path ??
|
|
44156
|
+
const basePath = opts.path ?? path17.join(os9.homedir(), "study");
|
|
43535
44157
|
const result2 = await setupWorkspace({
|
|
43536
44158
|
courseId: activeCourse.courseId,
|
|
43537
44159
|
courseSlug: courseSlug(activeCourse.courseTitle),
|
|
@@ -43565,7 +44187,7 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43565
44187
|
process.exit(1);
|
|
43566
44188
|
}
|
|
43567
44189
|
});
|
|
43568
|
-
workspaceCommand.command("status").description("Mostrar status do workspace do curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
44190
|
+
workspaceCommand.command("status").description("Mostrar status do workspace do curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace", path17.join(os9.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
43569
44191
|
try {
|
|
43570
44192
|
const activeCourse = await requireActiveCourse();
|
|
43571
44193
|
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
@@ -43582,22 +44204,22 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43582
44204
|
const workspacePath = ws.workspacePath;
|
|
43583
44205
|
let configData = null;
|
|
43584
44206
|
try {
|
|
43585
|
-
const raw = await fs15.readFile(
|
|
44207
|
+
const raw = await fs15.readFile(path17.join(workspacePath, ".ana-config.json"), "utf-8");
|
|
43586
44208
|
configData = JSON.parse(raw);
|
|
43587
44209
|
} catch {
|
|
43588
44210
|
configData = null;
|
|
43589
44211
|
}
|
|
43590
|
-
const exercisesDir =
|
|
44212
|
+
const exercisesDir = path17.join(workspacePath, "exercises");
|
|
43591
44213
|
let exerciseCount = 0;
|
|
43592
44214
|
try {
|
|
43593
44215
|
const moduleDirs = await fs15.readdir(exercisesDir);
|
|
43594
44216
|
for (const modDir of moduleDirs) {
|
|
43595
|
-
const modPath =
|
|
44217
|
+
const modPath = path17.join(exercisesDir, modDir);
|
|
43596
44218
|
const stat = await fs15.stat(modPath);
|
|
43597
44219
|
if (stat.isDirectory()) {
|
|
43598
44220
|
const lessonDirs = await fs15.readdir(modPath);
|
|
43599
44221
|
for (const lessonDir of lessonDirs) {
|
|
43600
|
-
const lessonPath =
|
|
44222
|
+
const lessonPath = path17.join(modPath, lessonDir);
|
|
43601
44223
|
const lstat = await fs15.stat(lessonPath);
|
|
43602
44224
|
if (lstat.isDirectory()) exerciseCount++;
|
|
43603
44225
|
}
|
|
@@ -43605,14 +44227,14 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43605
44227
|
}
|
|
43606
44228
|
} catch {
|
|
43607
44229
|
}
|
|
43608
|
-
const generatedDir =
|
|
44230
|
+
const generatedDir = path17.join(workspacePath, "generated");
|
|
43609
44231
|
let artifactCount = 0;
|
|
43610
44232
|
try {
|
|
43611
44233
|
const files = await fs15.readdir(generatedDir);
|
|
43612
44234
|
artifactCount = files.length;
|
|
43613
44235
|
} catch {
|
|
43614
44236
|
}
|
|
43615
|
-
const diagramsDir =
|
|
44237
|
+
const diagramsDir = path17.join(workspacePath, "diagrams");
|
|
43616
44238
|
let diagramCount = 0;
|
|
43617
44239
|
try {
|
|
43618
44240
|
const files = await fs15.readdir(diagramsDir);
|
|
@@ -43664,14 +44286,14 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43664
44286
|
|
|
43665
44287
|
// src/commands/export.ts
|
|
43666
44288
|
import { Command as Command17 } from "commander";
|
|
43667
|
-
import
|
|
43668
|
-
import
|
|
44289
|
+
import path18 from "node:path";
|
|
44290
|
+
import os10 from "node:os";
|
|
43669
44291
|
import fs16 from "node:fs/promises";
|
|
43670
44292
|
var logger17, exportCommand;
|
|
43671
44293
|
var init_export = __esm({
|
|
43672
44294
|
"src/commands/export.ts"() {
|
|
43673
44295
|
"use strict";
|
|
43674
|
-
|
|
44296
|
+
init_dist();
|
|
43675
44297
|
init_workspace();
|
|
43676
44298
|
init_http();
|
|
43677
44299
|
init_guards();
|
|
@@ -43679,7 +44301,7 @@ var init_export = __esm({
|
|
|
43679
44301
|
init_resolve();
|
|
43680
44302
|
init_errors();
|
|
43681
44303
|
logger17 = createLogger("cli:export");
|
|
43682
|
-
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",
|
|
44304
|
+
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", path18.join(os10.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
43683
44305
|
try {
|
|
43684
44306
|
const session = await requireSession();
|
|
43685
44307
|
const activeCourse = await requireActiveCourse();
|
|
@@ -43697,7 +44319,7 @@ var init_export = __esm({
|
|
|
43697
44319
|
opts.path
|
|
43698
44320
|
);
|
|
43699
44321
|
if (ws.found && ws.source === "cwd" && ws.workspacePath) {
|
|
43700
|
-
const configPath =
|
|
44322
|
+
const configPath = path18.join(ws.workspacePath, ".ana-config.json");
|
|
43701
44323
|
let hasConfig = false;
|
|
43702
44324
|
try {
|
|
43703
44325
|
await fs16.access(configPath);
|
|
@@ -43709,7 +44331,7 @@ var init_export = __esm({
|
|
|
43709
44331
|
logger17.info("Auto-initializing workspace", { workspacePath: ws.workspacePath });
|
|
43710
44332
|
await fs16.mkdir(ws.workspacePath, { recursive: true });
|
|
43711
44333
|
for (const dir of ["exercises", "generated", "notes", "diagrams"]) {
|
|
43712
|
-
await fs16.mkdir(
|
|
44334
|
+
await fs16.mkdir(path18.join(ws.workspacePath, dir), { recursive: true });
|
|
43713
44335
|
}
|
|
43714
44336
|
await fs16.writeFile(
|
|
43715
44337
|
configPath,
|
|
@@ -43729,7 +44351,7 @@ var init_export = __esm({
|
|
|
43729
44351
|
"utf-8"
|
|
43730
44352
|
);
|
|
43731
44353
|
await setCourseWorkspacePath(activeCourse.courseId, ws.workspacePath);
|
|
43732
|
-
const isNamespaced = ws.workspacePath ===
|
|
44354
|
+
const isNamespaced = ws.workspacePath === path18.join(process.cwd(), ".tostudy");
|
|
43733
44355
|
process.stderr.write(
|
|
43734
44356
|
isNamespaced ? `\u2728 Workspace inicializado em .tostudy/ (isolado do projeto).
|
|
43735
44357
|
` : `\u2728 Workspace inicializado nesta pasta.
|
|
@@ -43780,19 +44402,19 @@ ${result.files.map((f) => ` \u{1F4C4} ${f}`).join("\n")}
|
|
|
43780
44402
|
// src/commands/open.ts
|
|
43781
44403
|
import { Command as Command18 } from "commander";
|
|
43782
44404
|
import { execFile as execFile3 } from "node:child_process";
|
|
43783
|
-
import
|
|
43784
|
-
import
|
|
44405
|
+
import path19 from "node:path";
|
|
44406
|
+
import os11 from "node:os";
|
|
43785
44407
|
var logger18, openCommand;
|
|
43786
44408
|
var init_open = __esm({
|
|
43787
44409
|
"src/commands/open.ts"() {
|
|
43788
44410
|
"use strict";
|
|
43789
|
-
|
|
44411
|
+
init_dist();
|
|
43790
44412
|
init_guards();
|
|
43791
44413
|
init_course_state();
|
|
43792
44414
|
init_resolve();
|
|
43793
44415
|
init_errors();
|
|
43794
44416
|
logger18 = createLogger("cli:open");
|
|
43795
|
-
openCommand = new Command18("open").description("Abrir workspace do curso na IDE").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
44417
|
+
openCommand = new Command18("open").description("Abrir workspace do curso na IDE").option("--path <dir>", "Diret\xF3rio base do workspace", path19.join(os11.homedir(), "study")).action(async (opts) => {
|
|
43796
44418
|
try {
|
|
43797
44419
|
const activeCourse = await requireActiveCourse();
|
|
43798
44420
|
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
@@ -43846,14 +44468,14 @@ var init_types2 = __esm({
|
|
|
43846
44468
|
|
|
43847
44469
|
// ../../packages/tostudy-core/src/vault/write-vault.ts
|
|
43848
44470
|
import fs17 from "node:fs/promises";
|
|
43849
|
-
import
|
|
44471
|
+
import path20 from "node:path";
|
|
43850
44472
|
async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
|
|
43851
44473
|
for (const file2 of files) {
|
|
43852
|
-
const fullPath =
|
|
43853
|
-
await fs17.mkdir(
|
|
44474
|
+
const fullPath = path20.join(outputPath, file2.relativePath);
|
|
44475
|
+
await fs17.mkdir(path20.dirname(fullPath), { recursive: true });
|
|
43854
44476
|
await fs17.writeFile(fullPath, file2.content, "utf-8");
|
|
43855
44477
|
}
|
|
43856
|
-
const vaultPath =
|
|
44478
|
+
const vaultPath = path20.join(outputPath, courseSlug2);
|
|
43857
44479
|
const marker = {
|
|
43858
44480
|
courseId,
|
|
43859
44481
|
courseSlug: courseSlug2,
|
|
@@ -43862,7 +44484,7 @@ async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
|
|
|
43862
44484
|
};
|
|
43863
44485
|
await fs17.mkdir(vaultPath, { recursive: true });
|
|
43864
44486
|
await fs17.writeFile(
|
|
43865
|
-
|
|
44487
|
+
path20.join(vaultPath, VAULT_MARKER_FILENAME),
|
|
43866
44488
|
JSON.stringify(marker, null, 2),
|
|
43867
44489
|
"utf-8"
|
|
43868
44490
|
);
|
|
@@ -43887,14 +44509,14 @@ var init_vault = __esm({
|
|
|
43887
44509
|
|
|
43888
44510
|
// src/commands/vault.ts
|
|
43889
44511
|
import { Command as Command19 } from "commander";
|
|
43890
|
-
import
|
|
43891
|
-
import
|
|
44512
|
+
import path21 from "node:path";
|
|
44513
|
+
import os12 from "node:os";
|
|
43892
44514
|
import fs18 from "node:fs/promises";
|
|
43893
44515
|
var logger19, vaultCommand;
|
|
43894
44516
|
var init_vault2 = __esm({
|
|
43895
44517
|
"src/commands/vault.ts"() {
|
|
43896
44518
|
"use strict";
|
|
43897
|
-
|
|
44519
|
+
init_dist();
|
|
43898
44520
|
init_vault();
|
|
43899
44521
|
init_courses();
|
|
43900
44522
|
init_http();
|
|
@@ -43904,7 +44526,7 @@ var init_vault2 = __esm({
|
|
|
43904
44526
|
init_errors();
|
|
43905
44527
|
logger19 = createLogger("cli:vault");
|
|
43906
44528
|
vaultCommand = new Command19("vault").description("Gerenciar vault Obsidian do curso");
|
|
43907
|
-
vaultCommand.command("init").description("Gerar vault Obsidian para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
44529
|
+
vaultCommand.command("init").description("Gerar vault Obsidian para o curso ativo").option("--path <dir>", "Diret\xF3rio base do workspace", path21.join(os12.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
43908
44530
|
try {
|
|
43909
44531
|
const session = await requireSession();
|
|
43910
44532
|
const activeCourse = await requireActiveCourse();
|
|
@@ -43986,7 +44608,7 @@ Para visualizar:
|
|
|
43986
44608
|
process.exit(1);
|
|
43987
44609
|
}
|
|
43988
44610
|
});
|
|
43989
|
-
vaultCommand.command("sync").description("Sincronizar progresso do curso com o vault local").option("--path <dir>", "Diret\xF3rio base do workspace",
|
|
44611
|
+
vaultCommand.command("sync").description("Sincronizar progresso do curso com o vault local").option("--path <dir>", "Diret\xF3rio base do workspace", path21.join(os12.homedir(), "study")).option("--json", "Output structured JSON").action(async (opts) => {
|
|
43990
44612
|
try {
|
|
43991
44613
|
const session = await requireSession();
|
|
43992
44614
|
const activeCourse = await requireActiveCourse();
|
|
@@ -44012,7 +44634,7 @@ Para visualizar:
|
|
|
44012
44634
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
44013
44635
|
const deps = { data, logger: logger19 };
|
|
44014
44636
|
const progress3 = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
44015
|
-
const markerPath =
|
|
44637
|
+
const markerPath = path21.join(vaultPath, ".ana-vault.json");
|
|
44016
44638
|
const markerRaw = await fs18.readFile(markerPath, "utf-8");
|
|
44017
44639
|
const marker = JSON.parse(markerRaw);
|
|
44018
44640
|
marker.lastSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -44022,7 +44644,7 @@ Para visualizar:
|
|
|
44022
44644
|
currentLesson: progress3.currentLesson.title
|
|
44023
44645
|
};
|
|
44024
44646
|
await fs18.writeFile(markerPath, JSON.stringify(marker, null, 2), "utf-8");
|
|
44025
|
-
const courseIndexPath =
|
|
44647
|
+
const courseIndexPath = path21.join(vaultPath, slug, "index.md");
|
|
44026
44648
|
try {
|
|
44027
44649
|
let indexContent = await fs18.readFile(courseIndexPath, "utf-8");
|
|
44028
44650
|
indexContent = indexContent.replace(/\n---\n\n> 📊 Progresso:.*\n/g, "");
|
|
@@ -44148,7 +44770,7 @@ var logger20, syncCommand;
|
|
|
44148
44770
|
var init_sync = __esm({
|
|
44149
44771
|
"src/commands/sync.ts"() {
|
|
44150
44772
|
"use strict";
|
|
44151
|
-
|
|
44773
|
+
init_dist();
|
|
44152
44774
|
init_guards();
|
|
44153
44775
|
init_formatter();
|
|
44154
44776
|
init_instruction_pipeline();
|
|
@@ -44205,7 +44827,7 @@ var logger21, briefCommand;
|
|
|
44205
44827
|
var init_brief = __esm({
|
|
44206
44828
|
"src/commands/brief.ts"() {
|
|
44207
44829
|
"use strict";
|
|
44208
|
-
|
|
44830
|
+
init_dist();
|
|
44209
44831
|
init_guards();
|
|
44210
44832
|
init_cache();
|
|
44211
44833
|
init_api();
|
|
@@ -44257,7 +44879,7 @@ var logger22, briefCreateCommand;
|
|
|
44257
44879
|
var init_brief_create = __esm({
|
|
44258
44880
|
"src/commands/brief-create.ts"() {
|
|
44259
44881
|
"use strict";
|
|
44260
|
-
|
|
44882
|
+
init_dist();
|
|
44261
44883
|
init_guards();
|
|
44262
44884
|
init_bootstrap();
|
|
44263
44885
|
init_api();
|
|
@@ -44335,15 +44957,15 @@ var init_brief_open = __esm({
|
|
|
44335
44957
|
|
|
44336
44958
|
// src/sessions/storage.ts
|
|
44337
44959
|
import fs19 from "node:fs";
|
|
44338
|
-
import
|
|
44960
|
+
import path22 from "node:path";
|
|
44339
44961
|
function sessionsDir(workspacePath) {
|
|
44340
|
-
return
|
|
44962
|
+
return path22.join(workspacePath, ".tostudy", "sessions");
|
|
44341
44963
|
}
|
|
44342
44964
|
async function saveModuleSummary(workspacePath, input2) {
|
|
44343
44965
|
const dir = sessionsDir(workspacePath);
|
|
44344
44966
|
fs19.mkdirSync(dir, { recursive: true });
|
|
44345
44967
|
const filename = `module-${input2.moduleId}-summary.md`;
|
|
44346
|
-
const filePath =
|
|
44968
|
+
const filePath = path22.join(dir, filename);
|
|
44347
44969
|
const header = [
|
|
44348
44970
|
"---",
|
|
44349
44971
|
`moduleId: ${input2.moduleId}`,
|
|
@@ -44362,7 +44984,7 @@ async function loadSessionContext(workspacePath) {
|
|
|
44362
44984
|
const files = fs19.readdirSync(dir).filter((f) => f.startsWith("module-") && f.endsWith("-summary.md")).sort();
|
|
44363
44985
|
const summaries = [];
|
|
44364
44986
|
for (const file2 of files) {
|
|
44365
|
-
const content = fs19.readFileSync(
|
|
44987
|
+
const content = fs19.readFileSync(path22.join(dir, file2), "utf-8");
|
|
44366
44988
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
44367
44989
|
if (!frontmatterMatch) continue;
|
|
44368
44990
|
const meta3 = frontmatterMatch[1];
|
|
@@ -44378,7 +45000,7 @@ var logger23;
|
|
|
44378
45000
|
var init_storage = __esm({
|
|
44379
45001
|
"src/sessions/storage.ts"() {
|
|
44380
45002
|
"use strict";
|
|
44381
|
-
|
|
45003
|
+
init_dist();
|
|
44382
45004
|
logger23 = createLogger("cli:sessions");
|
|
44383
45005
|
}
|
|
44384
45006
|
});
|
|
@@ -44390,7 +45012,7 @@ var logger24, compactCommand;
|
|
|
44390
45012
|
var init_compact = __esm({
|
|
44391
45013
|
"src/commands/compact.ts"() {
|
|
44392
45014
|
"use strict";
|
|
44393
|
-
|
|
45015
|
+
init_dist();
|
|
44394
45016
|
init_guards();
|
|
44395
45017
|
init_workspace_state();
|
|
44396
45018
|
init_storage();
|
|
@@ -44439,7 +45061,7 @@ var logger25, contextCommand;
|
|
|
44439
45061
|
var init_context = __esm({
|
|
44440
45062
|
"src/commands/context.ts"() {
|
|
44441
45063
|
"use strict";
|
|
44442
|
-
|
|
45064
|
+
init_dist();
|
|
44443
45065
|
init_workspace_state();
|
|
44444
45066
|
init_storage();
|
|
44445
45067
|
init_formatter();
|
|
@@ -44493,21 +45115,125 @@ var init_context = __esm({
|
|
|
44493
45115
|
}
|
|
44494
45116
|
});
|
|
44495
45117
|
|
|
44496
|
-
// src/commands/
|
|
45118
|
+
// src/commands/memory.ts
|
|
44497
45119
|
import { Command as Command27 } from "commander";
|
|
45120
|
+
var logger26, memoryCommand;
|
|
45121
|
+
var init_memory = __esm({
|
|
45122
|
+
"src/commands/memory.ts"() {
|
|
45123
|
+
"use strict";
|
|
45124
|
+
init_dist();
|
|
45125
|
+
init_http();
|
|
45126
|
+
init_workspace_state();
|
|
45127
|
+
init_guards();
|
|
45128
|
+
init_formatter();
|
|
45129
|
+
logger26 = createLogger("cli:memory");
|
|
45130
|
+
memoryCommand = new Command27("memory").description("Load accumulated student memory (learning profile + recent lessons) for the tutor").option("--json", "Output structured JSON").action(async (opts) => {
|
|
45131
|
+
try {
|
|
45132
|
+
const ws = await findWorkspaceState();
|
|
45133
|
+
if (!ws) {
|
|
45134
|
+
if (opts.json) return jsonError("no_workspace");
|
|
45135
|
+
return error("Nenhum workspace encontrado. Rode: tostudy setup");
|
|
45136
|
+
}
|
|
45137
|
+
const { courseId, enrollmentId } = ws.state;
|
|
45138
|
+
if (!courseId || !enrollmentId) {
|
|
45139
|
+
if (opts.json) return jsonError("no_active_course");
|
|
45140
|
+
return error("Nenhum curso ativo. Rode: tostudy select");
|
|
45141
|
+
}
|
|
45142
|
+
const session = await requireSession();
|
|
45143
|
+
const data = createHttpProvider(session.apiUrl, session.token);
|
|
45144
|
+
const { context } = await data.memory.getContext(courseId, enrollmentId);
|
|
45145
|
+
if (opts.json) {
|
|
45146
|
+
output({ context }, { json: true });
|
|
45147
|
+
} else {
|
|
45148
|
+
output(context, { json: false });
|
|
45149
|
+
}
|
|
45150
|
+
} catch (err) {
|
|
45151
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
45152
|
+
if (msg.includes("process.exit")) return;
|
|
45153
|
+
logger26.warn("memory failed", { error: msg });
|
|
45154
|
+
if (opts.json) jsonError(msg);
|
|
45155
|
+
else error(msg);
|
|
45156
|
+
}
|
|
45157
|
+
});
|
|
45158
|
+
}
|
|
45159
|
+
});
|
|
45160
|
+
|
|
45161
|
+
// src/commands/insight.ts
|
|
45162
|
+
import { Command as Command28 } from "commander";
|
|
45163
|
+
var logger27, VALID_TYPES, insightCommand;
|
|
45164
|
+
var init_insight = __esm({
|
|
45165
|
+
"src/commands/insight.ts"() {
|
|
45166
|
+
"use strict";
|
|
45167
|
+
init_dist();
|
|
45168
|
+
init_http();
|
|
45169
|
+
init_workspace_state();
|
|
45170
|
+
init_guards();
|
|
45171
|
+
init_formatter();
|
|
45172
|
+
logger27 = createLogger("cli:insight");
|
|
45173
|
+
VALID_TYPES = ["difficulty", "breakthrough", "question"];
|
|
45174
|
+
insightCommand = new Command28("insight").description(
|
|
45175
|
+
"Persist a student cognitive insight (difficulty | breakthrough | question) into course memory"
|
|
45176
|
+
).argument("<type>", "difficulty | breakthrough | question").argument("<content>", 'Short description, e.g. "confunde async/await com promises"').option("--module-id <id>", "Module the insight relates to").option("--json", "Output structured JSON").action(async (type, content, opts) => {
|
|
45177
|
+
try {
|
|
45178
|
+
if (!VALID_TYPES.includes(type)) {
|
|
45179
|
+
if (opts.json) return jsonError("invalid_type");
|
|
45180
|
+
return error(`Tipo inv\xE1lido. Use: ${VALID_TYPES.join(" | ")}`);
|
|
45181
|
+
}
|
|
45182
|
+
const trimmed = content.trim();
|
|
45183
|
+
if (!trimmed) {
|
|
45184
|
+
if (opts.json) return jsonError("empty_content");
|
|
45185
|
+
return error("Conte\xFAdo vazio.");
|
|
45186
|
+
}
|
|
45187
|
+
const ws = await findWorkspaceState();
|
|
45188
|
+
if (!ws) {
|
|
45189
|
+
if (opts.json) return jsonError("no_workspace");
|
|
45190
|
+
return error("Nenhum workspace encontrado. Rode: tostudy setup");
|
|
45191
|
+
}
|
|
45192
|
+
const { courseId, enrollmentId } = ws.state;
|
|
45193
|
+
if (!courseId || !enrollmentId) {
|
|
45194
|
+
if (opts.json) return jsonError("no_active_course");
|
|
45195
|
+
return error("Nenhum curso ativo. Rode: tostudy select");
|
|
45196
|
+
}
|
|
45197
|
+
const session = await requireSession();
|
|
45198
|
+
const data = createHttpProvider(session.apiUrl, session.token);
|
|
45199
|
+
const res = await data.memory.recordInsight({
|
|
45200
|
+
courseId,
|
|
45201
|
+
enrollmentId,
|
|
45202
|
+
type,
|
|
45203
|
+
content: trimmed,
|
|
45204
|
+
...opts.moduleId ? { moduleId: opts.moduleId } : {}
|
|
45205
|
+
});
|
|
45206
|
+
if (opts.json) {
|
|
45207
|
+
output(res, { json: true });
|
|
45208
|
+
} else {
|
|
45209
|
+
output(res.message, { json: false });
|
|
45210
|
+
}
|
|
45211
|
+
} catch (err) {
|
|
45212
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
45213
|
+
if (msg.includes("process.exit")) return;
|
|
45214
|
+
logger27.warn("insight failed", { error: msg });
|
|
45215
|
+
if (opts.json) jsonError(msg);
|
|
45216
|
+
else error(msg);
|
|
45217
|
+
}
|
|
45218
|
+
});
|
|
45219
|
+
}
|
|
45220
|
+
});
|
|
45221
|
+
|
|
45222
|
+
// src/commands/level.ts
|
|
45223
|
+
import { Command as Command29 } from "commander";
|
|
44498
45224
|
function isExerciseLevel2(value) {
|
|
44499
45225
|
return ALL_LEVELS.includes(value);
|
|
44500
45226
|
}
|
|
44501
|
-
var
|
|
45227
|
+
var logger28, ALL_LEVELS, LEVEL_LABELS2, levelCommand;
|
|
44502
45228
|
var init_level = __esm({
|
|
44503
45229
|
"src/commands/level.ts"() {
|
|
44504
45230
|
"use strict";
|
|
44505
|
-
|
|
45231
|
+
init_dist();
|
|
44506
45232
|
init_http();
|
|
44507
45233
|
init_exercises();
|
|
44508
45234
|
init_guards();
|
|
44509
45235
|
init_formatter();
|
|
44510
|
-
|
|
45236
|
+
logger28 = createLogger("cli:level");
|
|
44511
45237
|
ALL_LEVELS = ["L0", "L1", "L2", "L3", "L4"];
|
|
44512
45238
|
LEVEL_LABELS2 = {
|
|
44513
45239
|
L0: "Pr\xE9-check (perguntas conceituais)",
|
|
@@ -44516,12 +45242,12 @@ var init_level = __esm({
|
|
|
44516
45242
|
L3: "Guiado (passo a passo + checkpoints)",
|
|
44517
45243
|
L4: "Desafio livre (folha em branco)"
|
|
44518
45244
|
};
|
|
44519
|
-
levelCommand = new
|
|
45245
|
+
levelCommand = new Command29("level").description("Show or set the exercise scaffolding level for the active course").argument("[level]", "Target level: L0, L1, L2, L3, or L4").option("--json", "Output structured JSON").action(async (rawLevel, opts) => {
|
|
44520
45246
|
try {
|
|
44521
45247
|
const session = await requireSession();
|
|
44522
45248
|
const activeCourse = await requireActiveCourse();
|
|
44523
45249
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
44524
|
-
const deps = { data, logger:
|
|
45250
|
+
const deps = { data, logger: logger28 };
|
|
44525
45251
|
if (!rawLevel) {
|
|
44526
45252
|
const levels = await getEnrollmentLevels({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
44527
45253
|
if (opts.json) {
|
|
@@ -44579,18 +45305,18 @@ var init_level = __esm({
|
|
|
44579
45305
|
});
|
|
44580
45306
|
|
|
44581
45307
|
// src/commands/theory.ts
|
|
44582
|
-
import { Command as
|
|
44583
|
-
var
|
|
45308
|
+
import { Command as Command30 } from "commander";
|
|
45309
|
+
var logger29, EXERCISE_LEVELS2, theoryCommand;
|
|
44584
45310
|
var init_theory = __esm({
|
|
44585
45311
|
"src/commands/theory.ts"() {
|
|
44586
45312
|
"use strict";
|
|
44587
|
-
|
|
45313
|
+
init_dist();
|
|
44588
45314
|
init_guards();
|
|
44589
45315
|
init_formatter();
|
|
44590
45316
|
init_errors();
|
|
44591
|
-
|
|
45317
|
+
logger29 = createLogger("cli:theory");
|
|
44592
45318
|
EXERCISE_LEVELS2 = ["L0", "L1", "L2", "L3", "L4"];
|
|
44593
|
-
theoryCommand = new
|
|
45319
|
+
theoryCommand = new Command30("theory").description("Request more theory on the current lesson (escape hatch)").option("--focus <text>", "Optional focus area in PT-BR (max 500 chars)").option("--level <L0|L1|L2|L3|L4>", "Override current exercise level (otherwise auto-detect)").option("--lesson <uuid>", "Override lesson ID (defaults to current workspace lesson)").option("--json", "Output structured JSON").action(async (opts) => {
|
|
44594
45320
|
try {
|
|
44595
45321
|
const session = await requireSession();
|
|
44596
45322
|
const active = await requireActiveCourse();
|
|
@@ -44627,7 +45353,7 @@ var init_theory = __esm({
|
|
|
44627
45353
|
currentLevel = levels.currentLevel;
|
|
44628
45354
|
}
|
|
44629
45355
|
const requestUrl = `${session.apiUrl}/api/cli/exercises/more-theory`;
|
|
44630
|
-
|
|
45356
|
+
logger29.debug("Requesting more theory", { lessonId, currentLevel });
|
|
44631
45357
|
const res = await fetch(requestUrl, {
|
|
44632
45358
|
method: "POST",
|
|
44633
45359
|
headers: {
|
|
@@ -44945,7 +45671,7 @@ var init_resolve_enrollment = __esm({
|
|
|
44945
45671
|
});
|
|
44946
45672
|
|
|
44947
45673
|
// src/commands/export-grades.ts
|
|
44948
|
-
import { Command as
|
|
45674
|
+
import { Command as Command31 } from "commander";
|
|
44949
45675
|
function isFormat(value) {
|
|
44950
45676
|
return SUPPORTED_FORMATS.includes(value);
|
|
44951
45677
|
}
|
|
@@ -45032,15 +45758,15 @@ async function runExportGrades(opts, deps = defaultDeps5) {
|
|
|
45032
45758
|
if (!rendered.endsWith("\n")) rendered += "\n";
|
|
45033
45759
|
deps.stdoutWrite(rendered);
|
|
45034
45760
|
}
|
|
45035
|
-
var
|
|
45761
|
+
var logger30, SUPPORTED_FORMATS, defaultDeps5, exportGradesCommand;
|
|
45036
45762
|
var init_export_grades = __esm({
|
|
45037
45763
|
"src/commands/export-grades.ts"() {
|
|
45038
45764
|
"use strict";
|
|
45039
|
-
|
|
45765
|
+
init_dist();
|
|
45040
45766
|
init_guards();
|
|
45041
45767
|
init_grades();
|
|
45042
45768
|
init_resolve_enrollment();
|
|
45043
|
-
|
|
45769
|
+
logger30 = createLogger("cli:export-grades");
|
|
45044
45770
|
SUPPORTED_FORMATS = ["json", "csv", "md"];
|
|
45045
45771
|
defaultDeps5 = {
|
|
45046
45772
|
requireSession,
|
|
@@ -45050,10 +45776,10 @@ var init_export_grades = __esm({
|
|
|
45050
45776
|
stderrWrite: (message) => process.stderr.write(message),
|
|
45051
45777
|
// process.exit is typed as `never` — wrap so the cast is local to one line.
|
|
45052
45778
|
exit: (code) => process.exit(code),
|
|
45053
|
-
logger:
|
|
45779
|
+
logger: logger30,
|
|
45054
45780
|
resolveBySlug: resolveEnrollmentBySlug
|
|
45055
45781
|
};
|
|
45056
|
-
exportGradesCommand = new
|
|
45782
|
+
exportGradesCommand = new Command31("export-grades").description("Exporta o hist\xF3rico de valida\xE7\xF5es (notas) do curso ativo").option(
|
|
45057
45783
|
"--course <slug>",
|
|
45058
45784
|
"Slug do curso (gerado a partir do t\xEDtulo). Sem a flag, exporta o curso ativo."
|
|
45059
45785
|
).option("--format <json|csv|md>", "Formato de sa\xEDda (default: json)", "json").addHelpText(
|
|
@@ -45078,7 +45804,7 @@ C\xF3digos de sa\xEDda:
|
|
|
45078
45804
|
});
|
|
45079
45805
|
|
|
45080
45806
|
// src/commands/grades.ts
|
|
45081
|
-
import { Command as
|
|
45807
|
+
import { Command as Command32 } from "commander";
|
|
45082
45808
|
async function fetchAttempts(session, enrollmentId, deps) {
|
|
45083
45809
|
const url2 = `${session.apiUrl}/api/cli/validations/by-enrollment?enrollmentId=${encodeURIComponent(
|
|
45084
45810
|
enrollmentId
|
|
@@ -45219,29 +45945,29 @@ async function runGrades(opts, deps = defaultDeps6) {
|
|
|
45219
45945
|
);
|
|
45220
45946
|
deps.stdoutWrite(formatGradesAllEnrollmentsTable(summaries) + "\n");
|
|
45221
45947
|
}
|
|
45222
|
-
var
|
|
45948
|
+
var logger31, defaultDeps6, gradesCommand;
|
|
45223
45949
|
var init_grades2 = __esm({
|
|
45224
45950
|
"src/commands/grades.ts"() {
|
|
45225
45951
|
"use strict";
|
|
45226
|
-
|
|
45952
|
+
init_dist();
|
|
45227
45953
|
init_http();
|
|
45228
45954
|
init_courses();
|
|
45229
45955
|
init_guards();
|
|
45230
45956
|
init_grades();
|
|
45231
45957
|
init_resolve_enrollment();
|
|
45232
|
-
|
|
45958
|
+
logger31 = createLogger("cli:grades");
|
|
45233
45959
|
defaultDeps6 = {
|
|
45234
45960
|
requireSession,
|
|
45235
45961
|
fetch: globalThis.fetch.bind(globalThis),
|
|
45236
45962
|
stdoutWrite: (message) => process.stdout.write(message),
|
|
45237
45963
|
stderrWrite: (message) => process.stderr.write(message),
|
|
45238
45964
|
exit: (code) => process.exit(code),
|
|
45239
|
-
logger:
|
|
45965
|
+
logger: logger31,
|
|
45240
45966
|
resolveBySlug: resolveEnrollmentBySlug,
|
|
45241
45967
|
buildDataProvider: createHttpProvider,
|
|
45242
45968
|
listCoursesFn: listCourses
|
|
45243
45969
|
};
|
|
45244
|
-
gradesCommand = new
|
|
45970
|
+
gradesCommand = new Command32("grades").description("Mostra um resumo das notas (todas as matr\xEDculas ou um curso espec\xEDfico)").option(
|
|
45245
45971
|
"--course <slug>",
|
|
45246
45972
|
"Slug do curso (gerado a partir do t\xEDtulo). Sem a flag, lista todos os cursos."
|
|
45247
45973
|
).addHelpText(
|
|
@@ -45265,7 +45991,7 @@ C\xF3digos de sa\xEDda:
|
|
|
45265
45991
|
});
|
|
45266
45992
|
|
|
45267
45993
|
// src/commands/review.ts
|
|
45268
|
-
import { Command as
|
|
45994
|
+
import { Command as Command33 } from "commander";
|
|
45269
45995
|
import { createInterface } from "node:readline/promises";
|
|
45270
45996
|
import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
|
|
45271
45997
|
async function defaultPromptLessonChoice(lessonIds) {
|
|
@@ -45401,26 +46127,26 @@ async function runReview(slug, opts, deps = defaultDeps7) {
|
|
|
45401
46127
|
}) + "\n"
|
|
45402
46128
|
);
|
|
45403
46129
|
}
|
|
45404
|
-
var
|
|
46130
|
+
var logger32, defaultDeps7, reviewCommand;
|
|
45405
46131
|
var init_review2 = __esm({
|
|
45406
46132
|
"src/commands/review.ts"() {
|
|
45407
46133
|
"use strict";
|
|
45408
|
-
|
|
46134
|
+
init_dist();
|
|
45409
46135
|
init_guards();
|
|
45410
46136
|
init_grades();
|
|
45411
46137
|
init_resolve_enrollment();
|
|
45412
|
-
|
|
46138
|
+
logger32 = createLogger("cli:review");
|
|
45413
46139
|
defaultDeps7 = {
|
|
45414
46140
|
requireSession,
|
|
45415
46141
|
fetch: globalThis.fetch.bind(globalThis),
|
|
45416
46142
|
stdoutWrite: (message) => process.stdout.write(message),
|
|
45417
46143
|
stderrWrite: (message) => process.stderr.write(message),
|
|
45418
46144
|
exit: (code) => process.exit(code),
|
|
45419
|
-
logger:
|
|
46145
|
+
logger: logger32,
|
|
45420
46146
|
resolveBySlug: resolveEnrollmentBySlug,
|
|
45421
46147
|
promptLessonChoice: defaultPromptLessonChoice
|
|
45422
46148
|
};
|
|
45423
|
-
reviewCommand = new
|
|
46149
|
+
reviewCommand = new Command33("review").description("Revisa a \xFAltima tentativa de valida\xE7\xE3o de uma li\xE7\xE3o").argument("<slug>", "Slug do curso (gerado a partir do t\xEDtulo)").option("--json", "Sa\xEDda em JSON (sem prompt interativo)").addHelpText(
|
|
45424
46150
|
"after",
|
|
45425
46151
|
`
|
|
45426
46152
|
Exemplos:
|
|
@@ -45449,9 +46175,9 @@ __export(cli_exports, {
|
|
|
45449
46175
|
CLI_VERSION: () => CLI_VERSION,
|
|
45450
46176
|
createProgram: () => createProgram
|
|
45451
46177
|
});
|
|
45452
|
-
import { Command as
|
|
46178
|
+
import { Command as Command34 } from "commander";
|
|
45453
46179
|
function createProgram() {
|
|
45454
|
-
const program2 = new
|
|
46180
|
+
const program2 = new Command34();
|
|
45455
46181
|
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").option("--locale <code>", "Output locale (pt-BR | en-US); defaults to LANG env then pt-BR");
|
|
45456
46182
|
program2.addCommand(setupCommand);
|
|
45457
46183
|
program2.addCommand(doctorCommand);
|
|
@@ -45484,6 +46210,8 @@ function createProgram() {
|
|
|
45484
46210
|
program2.addCommand(vaultCommand);
|
|
45485
46211
|
program2.addCommand(compactCommand);
|
|
45486
46212
|
program2.addCommand(contextCommand);
|
|
46213
|
+
program2.addCommand(memoryCommand);
|
|
46214
|
+
program2.addCommand(insightCommand);
|
|
45487
46215
|
return program2;
|
|
45488
46216
|
}
|
|
45489
46217
|
var init_cli = __esm({
|
|
@@ -45515,6 +46243,8 @@ var init_cli = __esm({
|
|
|
45515
46243
|
init_brief_open();
|
|
45516
46244
|
init_compact();
|
|
45517
46245
|
init_context();
|
|
46246
|
+
init_memory();
|
|
46247
|
+
init_insight();
|
|
45518
46248
|
init_level();
|
|
45519
46249
|
init_theory();
|
|
45520
46250
|
init_export_grades();
|