@tostudy-ai/cli 0.11.2 → 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 +1060 -382
- 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
|
});
|
|
@@ -1607,8 +1641,9 @@ Rode \`tostudy context --json\` em sil\xEAncio para descobrir o estado do aluno.
|
|
|
1607
1641
|
### Se tudo pronto (workspace + curso + contexto):
|
|
1608
1642
|
|
|
1609
1643
|
1. Leia os \`moduleSummaries\` do resultado para saber o que o aluno j\xE1 estudou.
|
|
1610
|
-
2.
|
|
1611
|
-
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.`);
|
|
1612
1647
|
sections.push(renderHowToConduct());
|
|
1613
1648
|
sections.push(renderSilentTools());
|
|
1614
1649
|
sections.push(`## Compacta\xE7\xE3o de Contexto (Autom\xE1tico)
|
|
@@ -1808,6 +1843,10 @@ Estes comandos s\xE3o suas ferramentas. Rode em sil\xEAncio (sem anunciar), use
|
|
|
1808
1843
|
- \`tostudy hint --json\` \u2014 dica progressiva (3 n\xEDveis).
|
|
1809
1844
|
- \`tostudy validate <arquivo>\` \u2014 valida exerc\xEDcio (exit 0 = passou, 1 = falhou).
|
|
1810
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
|
+
|
|
1811
1850
|
Voc\xEA nunca menciona estes comandos ao aluno. Ele fala com VOC\xCA, n\xE3o com o CLI.`;
|
|
1812
1851
|
}
|
|
1813
1852
|
function renderHandlingSituations() {
|
|
@@ -1828,6 +1867,7 @@ function renderTechnicalReference() {
|
|
|
1828
1867
|
- Use \`--json\` em qualquer comando para sa\xEDda estruturada.
|
|
1829
1868
|
- \`tostudy validate\` retorna exit code 0 (aprovado) ou 1 (reprovado).
|
|
1830
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).
|
|
1831
1871
|
- \`tostudy lesson --json\` retorna \`{ type, title, content, hints, acceptanceCriteria }\`.
|
|
1832
1872
|
- \`tostudy progress --json\` retorna \`{ coursePercent, currentModule, currentLesson }\`.`;
|
|
1833
1873
|
}
|
|
@@ -1939,7 +1979,7 @@ var logger2;
|
|
|
1939
1979
|
var init_instruction_files = __esm({
|
|
1940
1980
|
"src/workspace/instruction-files.ts"() {
|
|
1941
1981
|
"use strict";
|
|
1942
|
-
|
|
1982
|
+
init_dist();
|
|
1943
1983
|
init_instruction_template_v3();
|
|
1944
1984
|
logger2 = createLogger("cli:instruction-files");
|
|
1945
1985
|
}
|
|
@@ -1948,6 +1988,72 @@ var init_instruction_files = __esm({
|
|
|
1948
1988
|
// src/commands/login.ts
|
|
1949
1989
|
import { Command } from "commander";
|
|
1950
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
|
+
}
|
|
1951
2057
|
function ideToPlatform(ideName) {
|
|
1952
2058
|
const lower = ideName.toLowerCase();
|
|
1953
2059
|
if (lower.includes("claude")) return "claude";
|
|
@@ -1961,7 +2067,7 @@ var logger3, DEFAULT_API_URL, PORT, loginCommand;
|
|
|
1961
2067
|
var init_login = __esm({
|
|
1962
2068
|
"src/commands/login.ts"() {
|
|
1963
2069
|
"use strict";
|
|
1964
|
-
|
|
2070
|
+
init_dist();
|
|
1965
2071
|
init_courses();
|
|
1966
2072
|
init_http();
|
|
1967
2073
|
init_oauth_server();
|
|
@@ -1970,8 +2076,30 @@ var init_login = __esm({
|
|
|
1970
2076
|
logger3 = createLogger("cli:login");
|
|
1971
2077
|
DEFAULT_API_URL = "https://tostudy.ai";
|
|
1972
2078
|
PORT = 9876;
|
|
1973
|
-
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) => {
|
|
1974
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
|
+
}
|
|
1975
2103
|
if (opts.manual) {
|
|
1976
2104
|
console.log(`
|
|
1977
2105
|
Acesse este endere\xE7o no seu browser:`);
|
|
@@ -2333,7 +2461,8 @@ var init_errors_pt_br = __esm({
|
|
|
2333
2461
|
workspaceCommandDescription: "Gerenciar workspace de estudo local",
|
|
2334
2462
|
workspaceSetupDescription: "Criar estrutura do workspace para o curso ativo",
|
|
2335
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",
|
|
2336
|
-
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"
|
|
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"
|
|
2337
2466
|
};
|
|
2338
2467
|
}
|
|
2339
2468
|
});
|
|
@@ -2352,7 +2481,8 @@ var init_errors_en_us = __esm({
|
|
|
2352
2481
|
workspaceCommandDescription: "Manage local study workspace",
|
|
2353
2482
|
workspaceSetupDescription: "Create the workspace structure for the active course",
|
|
2354
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",
|
|
2355
|
-
courseArchived: "This course has been archived and is available for reading only.\nUse `tostudy lesson` to review the content you've already studied.\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"
|
|
2356
2486
|
};
|
|
2357
2487
|
}
|
|
2358
2488
|
});
|
|
@@ -2388,6 +2518,10 @@ function isCourseArchivedError(err) {
|
|
|
2388
2518
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2389
2519
|
return msg.includes("COURSE_ARCHIVED");
|
|
2390
2520
|
}
|
|
2521
|
+
function isEnrollmentNotEntitledError(err) {
|
|
2522
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2523
|
+
return msg.includes("ENROLLMENT_NOT_ENTITLED");
|
|
2524
|
+
}
|
|
2391
2525
|
var BUNDLES, _cachedLocale;
|
|
2392
2526
|
var init_errors = __esm({
|
|
2393
2527
|
"src/errors/index.ts"() {
|
|
@@ -2584,7 +2718,7 @@ var CLI_VERSION;
|
|
|
2584
2718
|
var init_version = __esm({
|
|
2585
2719
|
"src/version.ts"() {
|
|
2586
2720
|
"use strict";
|
|
2587
|
-
CLI_VERSION = true ? "0.
|
|
2721
|
+
CLI_VERSION = true ? "0.12.0" : "0.7.1";
|
|
2588
2722
|
}
|
|
2589
2723
|
});
|
|
2590
2724
|
|
|
@@ -2598,16 +2732,9 @@ __export(update_checker_exports, {
|
|
|
2598
2732
|
});
|
|
2599
2733
|
import fs7 from "node:fs";
|
|
2600
2734
|
import path9 from "node:path";
|
|
2601
|
-
import os6 from "node:os";
|
|
2602
|
-
function getConfigDir2() {
|
|
2603
|
-
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2604
|
-
return path9.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2605
|
-
}
|
|
2606
|
-
return path9.join(os6.homedir(), ".tostudy");
|
|
2607
|
-
}
|
|
2608
2735
|
function readCache() {
|
|
2609
2736
|
try {
|
|
2610
|
-
const p = path9.join(
|
|
2737
|
+
const p = path9.join(getConfigDir(), CACHE_FILE);
|
|
2611
2738
|
if (!fs7.existsSync(p)) return null;
|
|
2612
2739
|
return JSON.parse(fs7.readFileSync(p, "utf-8"));
|
|
2613
2740
|
} catch {
|
|
@@ -2616,7 +2743,7 @@ function readCache() {
|
|
|
2616
2743
|
}
|
|
2617
2744
|
function writeCache(cache) {
|
|
2618
2745
|
try {
|
|
2619
|
-
const dir =
|
|
2746
|
+
const dir = getConfigDir();
|
|
2620
2747
|
fs7.mkdirSync(dir, { recursive: true });
|
|
2621
2748
|
fs7.writeFileSync(path9.join(dir, CACHE_FILE), JSON.stringify(cache));
|
|
2622
2749
|
} catch {
|
|
@@ -2679,6 +2806,7 @@ var PACKAGE_NAME, CACHE_FILE, CHECK_INTERVAL_MS, REGISTRY_TIMEOUT_MS;
|
|
|
2679
2806
|
var init_update_checker = __esm({
|
|
2680
2807
|
"src/update-checker.ts"() {
|
|
2681
2808
|
"use strict";
|
|
2809
|
+
init_config_dir();
|
|
2682
2810
|
PACKAGE_NAME = "@tostudy-ai/cli";
|
|
2683
2811
|
CACHE_FILE = "update-check.json";
|
|
2684
2812
|
CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2688,19 +2816,12 @@ var init_update_checker = __esm({
|
|
|
2688
2816
|
|
|
2689
2817
|
// src/learner-brief/cache.ts
|
|
2690
2818
|
import fs8 from "node:fs";
|
|
2691
|
-
import os7 from "node:os";
|
|
2692
2819
|
import path10 from "node:path";
|
|
2693
|
-
function getDefaultConfigDir() {
|
|
2694
|
-
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2695
|
-
return path10.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2696
|
-
}
|
|
2697
|
-
return path10.join(os7.homedir(), ".tostudy");
|
|
2698
|
-
}
|
|
2699
2820
|
function resolveCachePath(configDir) {
|
|
2700
2821
|
return path10.join(configDir, "student-brief.json");
|
|
2701
2822
|
}
|
|
2702
2823
|
async function readBriefCache(configDir) {
|
|
2703
|
-
const dir = configDir ??
|
|
2824
|
+
const dir = configDir ?? getConfigDir();
|
|
2704
2825
|
const p = resolveCachePath(dir);
|
|
2705
2826
|
if (!fs8.existsSync(p)) return null;
|
|
2706
2827
|
try {
|
|
@@ -2711,26 +2832,20 @@ async function readBriefCache(configDir) {
|
|
|
2711
2832
|
}
|
|
2712
2833
|
}
|
|
2713
2834
|
async function writeBriefCache(configDir, cache) {
|
|
2714
|
-
const dir = configDir ??
|
|
2835
|
+
const dir = configDir ?? getConfigDir();
|
|
2715
2836
|
fs8.mkdirSync(dir, { recursive: true });
|
|
2716
2837
|
fs8.writeFileSync(resolveCachePath(dir), JSON.stringify(cache, null, 2), { mode: 384 });
|
|
2717
2838
|
}
|
|
2718
2839
|
var init_cache = __esm({
|
|
2719
2840
|
"src/learner-brief/cache.ts"() {
|
|
2720
2841
|
"use strict";
|
|
2842
|
+
init_config_dir();
|
|
2721
2843
|
}
|
|
2722
2844
|
});
|
|
2723
2845
|
|
|
2724
2846
|
// src/tutor-persona/cache.ts
|
|
2725
2847
|
import fs9 from "node:fs";
|
|
2726
|
-
import os8 from "node:os";
|
|
2727
2848
|
import path11 from "node:path";
|
|
2728
|
-
function getDefaultConfigDir2() {
|
|
2729
|
-
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
2730
|
-
return path11.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
2731
|
-
}
|
|
2732
|
-
return path11.join(os8.homedir(), ".tostudy");
|
|
2733
|
-
}
|
|
2734
2849
|
function resolveCachePath2(configDir) {
|
|
2735
2850
|
return path11.join(configDir, "tutor-personalities.json");
|
|
2736
2851
|
}
|
|
@@ -2748,12 +2863,12 @@ function writeAll(configDir, cache) {
|
|
|
2748
2863
|
fs9.writeFileSync(resolveCachePath2(configDir), JSON.stringify(cache, null, 2), { mode: 384 });
|
|
2749
2864
|
}
|
|
2750
2865
|
async function readPersonaCacheForCourse(configDir, courseId) {
|
|
2751
|
-
const dir = configDir ??
|
|
2866
|
+
const dir = configDir ?? getConfigDir();
|
|
2752
2867
|
const all = readAll(dir);
|
|
2753
2868
|
return all[courseId] ?? null;
|
|
2754
2869
|
}
|
|
2755
2870
|
async function writePersonaCacheForCourse(configDir, courseId, entry) {
|
|
2756
|
-
const dir = configDir ??
|
|
2871
|
+
const dir = configDir ?? getConfigDir();
|
|
2757
2872
|
const all = readAll(dir);
|
|
2758
2873
|
all[courseId] = entry;
|
|
2759
2874
|
writeAll(dir, all);
|
|
@@ -2761,6 +2876,7 @@ async function writePersonaCacheForCourse(configDir, courseId, entry) {
|
|
|
2761
2876
|
var init_cache2 = __esm({
|
|
2762
2877
|
"src/tutor-persona/cache.ts"() {
|
|
2763
2878
|
"use strict";
|
|
2879
|
+
init_config_dir();
|
|
2764
2880
|
}
|
|
2765
2881
|
});
|
|
2766
2882
|
|
|
@@ -2981,7 +3097,7 @@ var logger4, coursesCommand;
|
|
|
2981
3097
|
var init_courses2 = __esm({
|
|
2982
3098
|
"src/commands/courses.ts"() {
|
|
2983
3099
|
"use strict";
|
|
2984
|
-
|
|
3100
|
+
init_dist();
|
|
2985
3101
|
init_courses();
|
|
2986
3102
|
init_http();
|
|
2987
3103
|
init_guards();
|
|
@@ -3017,7 +3133,7 @@ var init_courses2 = __esm({
|
|
|
3017
3133
|
// src/workspace/resolve.ts
|
|
3018
3134
|
import fs10 from "node:fs/promises";
|
|
3019
3135
|
import path12 from "node:path";
|
|
3020
|
-
import
|
|
3136
|
+
import os6 from "node:os";
|
|
3021
3137
|
function courseSlug(title) {
|
|
3022
3138
|
return title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
3023
3139
|
}
|
|
@@ -3048,7 +3164,7 @@ async function resolveCwdWorkspacePath(cwd = process.cwd()) {
|
|
|
3048
3164
|
return null;
|
|
3049
3165
|
}
|
|
3050
3166
|
}
|
|
3051
|
-
async function findCwdWorkspaceUpwards(startCwd = process.cwd(), homeDir =
|
|
3167
|
+
async function findCwdWorkspaceUpwards(startCwd = process.cwd(), homeDir = os6.homedir()) {
|
|
3052
3168
|
const home = path12.resolve(homeDir);
|
|
3053
3169
|
let current = path12.resolve(startCwd);
|
|
3054
3170
|
while (true) {
|
|
@@ -3079,7 +3195,7 @@ async function findExistingVault(workspacePath, slug) {
|
|
|
3079
3195
|
return null;
|
|
3080
3196
|
}
|
|
3081
3197
|
}
|
|
3082
|
-
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()) {
|
|
3083
3199
|
const cwdWorkspace = await findCwdWorkspaceUpwards(cwd, homeDir);
|
|
3084
3200
|
if (cwdWorkspace) {
|
|
3085
3201
|
return { found: true, workspacePath: cwdWorkspace, source: "cwd" };
|
|
@@ -3101,7 +3217,7 @@ var DEFAULT_BASE;
|
|
|
3101
3217
|
var init_resolve = __esm({
|
|
3102
3218
|
"src/workspace/resolve.ts"() {
|
|
3103
3219
|
"use strict";
|
|
3104
|
-
DEFAULT_BASE = path12.join(
|
|
3220
|
+
DEFAULT_BASE = path12.join(os6.homedir(), "study");
|
|
3105
3221
|
}
|
|
3106
3222
|
});
|
|
3107
3223
|
|
|
@@ -3130,31 +3246,15 @@ var init_status = __esm({
|
|
|
3130
3246
|
});
|
|
3131
3247
|
|
|
3132
3248
|
// src/learner-brief/api.ts
|
|
3133
|
-
async function apiFetch2(url2, token2, init) {
|
|
3134
|
-
const response = await fetch(url2, {
|
|
3135
|
-
method: init?.method ?? "GET",
|
|
3136
|
-
body: init?.body,
|
|
3137
|
-
headers: {
|
|
3138
|
-
"Content-Type": "application/json",
|
|
3139
|
-
Authorization: `Bearer ${token2}`,
|
|
3140
|
-
...init?.headers ?? {}
|
|
3141
|
-
}
|
|
3142
|
-
});
|
|
3143
|
-
const body = await response.json();
|
|
3144
|
-
if (!response.ok) {
|
|
3145
|
-
throw new CliApiError(body.error ?? `API error ${response.status}`, response.status);
|
|
3146
|
-
}
|
|
3147
|
-
return body;
|
|
3148
|
-
}
|
|
3149
3249
|
async function fetchLearnerBrief(input2) {
|
|
3150
|
-
const response = await
|
|
3250
|
+
const response = await cliApiFetch(
|
|
3151
3251
|
`${input2.apiUrl}/api/cli/student/learner-brief`,
|
|
3152
3252
|
input2.token
|
|
3153
3253
|
);
|
|
3154
3254
|
return response.brief;
|
|
3155
3255
|
}
|
|
3156
3256
|
async function upsertLearnerBrief(input2) {
|
|
3157
|
-
const response = await
|
|
3257
|
+
const response = await cliApiFetch(
|
|
3158
3258
|
`${input2.apiUrl}/api/cli/student/learner-brief`,
|
|
3159
3259
|
input2.token,
|
|
3160
3260
|
{
|
|
@@ -3265,32 +3365,17 @@ var init_api2 = __esm({
|
|
|
3265
3365
|
});
|
|
3266
3366
|
|
|
3267
3367
|
// src/onboarding/api.ts
|
|
3268
|
-
async function apiFetch3(url2, token2, init) {
|
|
3269
|
-
const response = await fetch(url2, {
|
|
3270
|
-
...init,
|
|
3271
|
-
headers: {
|
|
3272
|
-
"Content-Type": "application/json",
|
|
3273
|
-
Authorization: `Bearer ${token2}`,
|
|
3274
|
-
...init?.headers
|
|
3275
|
-
}
|
|
3276
|
-
});
|
|
3277
|
-
const body = await response.json();
|
|
3278
|
-
if (!response.ok) {
|
|
3279
|
-
throw new CliApiError(body.error ?? `API error ${response.status}`, response.status);
|
|
3280
|
-
}
|
|
3281
|
-
return body;
|
|
3282
|
-
}
|
|
3283
3368
|
async function getRemoteEnrollmentOnboarding(input2) {
|
|
3284
3369
|
const url2 = new URL(`${input2.apiUrl}/api/cli/onboarding`);
|
|
3285
3370
|
url2.searchParams.set("enrollmentId", input2.enrollmentId);
|
|
3286
|
-
const response = await
|
|
3371
|
+
const response = await cliApiFetch(
|
|
3287
3372
|
url2.toString(),
|
|
3288
3373
|
input2.token
|
|
3289
3374
|
);
|
|
3290
3375
|
return response.onboarding;
|
|
3291
3376
|
}
|
|
3292
3377
|
async function saveRemoteEnrollmentOnboarding(input2) {
|
|
3293
|
-
const response = await
|
|
3378
|
+
const response = await cliApiFetch(
|
|
3294
3379
|
`${input2.apiUrl}/api/cli/onboarding`,
|
|
3295
3380
|
input2.token,
|
|
3296
3381
|
{
|
|
@@ -3465,7 +3550,7 @@ var logger5, defaultDeps2;
|
|
|
3465
3550
|
var init_instruction_pipeline = __esm({
|
|
3466
3551
|
"src/instruction-pipeline.ts"() {
|
|
3467
3552
|
"use strict";
|
|
3468
|
-
|
|
3553
|
+
init_dist();
|
|
3469
3554
|
init_workspace_marker();
|
|
3470
3555
|
init_workspace_state();
|
|
3471
3556
|
init_api();
|
|
@@ -3569,7 +3654,7 @@ var logger6;
|
|
|
3569
3654
|
var init_pipeline_deps = __esm({
|
|
3570
3655
|
"src/commands/_shared/pipeline-deps.ts"() {
|
|
3571
3656
|
"use strict";
|
|
3572
|
-
|
|
3657
|
+
init_dist();
|
|
3573
3658
|
init_courses();
|
|
3574
3659
|
init_http();
|
|
3575
3660
|
init_instruction_pipeline();
|
|
@@ -3580,18 +3665,19 @@ var init_pipeline_deps = __esm({
|
|
|
3580
3665
|
|
|
3581
3666
|
// src/commands/select.ts
|
|
3582
3667
|
import { Command as Command6 } from "commander";
|
|
3583
|
-
import
|
|
3668
|
+
import os7 from "node:os";
|
|
3584
3669
|
var logger7, selectCommand;
|
|
3585
3670
|
var init_select = __esm({
|
|
3586
3671
|
"src/commands/select.ts"() {
|
|
3587
3672
|
"use strict";
|
|
3588
|
-
|
|
3673
|
+
init_dist();
|
|
3589
3674
|
init_courses();
|
|
3590
3675
|
init_http();
|
|
3591
3676
|
init_guards();
|
|
3592
3677
|
init_workspace_marker();
|
|
3593
3678
|
init_resolve();
|
|
3594
3679
|
init_formatter();
|
|
3680
|
+
init_errors();
|
|
3595
3681
|
init_status();
|
|
3596
3682
|
init_instruction_pipeline();
|
|
3597
3683
|
init_pipeline_deps();
|
|
@@ -3664,7 +3750,7 @@ var init_select = __esm({
|
|
|
3664
3750
|
);
|
|
3665
3751
|
} else {
|
|
3666
3752
|
const slashCmd = courseSlug2 ? `/tostudy-${courseSlug2}` : "/tostudy";
|
|
3667
|
-
const home =
|
|
3753
|
+
const home = os7.homedir();
|
|
3668
3754
|
const cwd = process.cwd();
|
|
3669
3755
|
const namespacedPath = `${cwd}/.tostudy`;
|
|
3670
3756
|
let wsLine;
|
|
@@ -3699,6 +3785,10 @@ var init_select = __esm({
|
|
|
3699
3785
|
output(lines.join("\n"), { json: false });
|
|
3700
3786
|
}
|
|
3701
3787
|
} catch (err) {
|
|
3788
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
3789
|
+
process.stderr.write(getErrors().enrollmentNotEntitled);
|
|
3790
|
+
process.exit(1);
|
|
3791
|
+
}
|
|
3702
3792
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3703
3793
|
error(msg);
|
|
3704
3794
|
}
|
|
@@ -3712,12 +3802,13 @@ var logger8, progressCommand;
|
|
|
3712
3802
|
var init_progress = __esm({
|
|
3713
3803
|
"src/commands/progress.ts"() {
|
|
3714
3804
|
"use strict";
|
|
3715
|
-
|
|
3805
|
+
init_dist();
|
|
3716
3806
|
init_courses();
|
|
3717
3807
|
init_http();
|
|
3718
3808
|
init_guards();
|
|
3719
3809
|
init_course_state();
|
|
3720
3810
|
init_formatter();
|
|
3811
|
+
init_errors();
|
|
3721
3812
|
logger8 = createLogger("cli:progress");
|
|
3722
3813
|
progressCommand = new Command7("progress").description("Show your progress in the active course").option("--json", "Output structured JSON").action(async (opts) => {
|
|
3723
3814
|
try {
|
|
@@ -3734,6 +3825,10 @@ var init_progress = __esm({
|
|
|
3734
3825
|
output(formatProgress(progress3), { json: false });
|
|
3735
3826
|
}
|
|
3736
3827
|
} catch (err) {
|
|
3828
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
3829
|
+
process.stderr.write(getErrors().enrollmentNotEntitled);
|
|
3830
|
+
process.exit(1);
|
|
3831
|
+
}
|
|
3737
3832
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3738
3833
|
error(msg);
|
|
3739
3834
|
}
|
|
@@ -5287,7 +5382,7 @@ var init_query_promise = __esm({
|
|
|
5287
5382
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
5288
5383
|
const nullifyMap = {};
|
|
5289
5384
|
const result = columns.reduce(
|
|
5290
|
-
(result2, { path:
|
|
5385
|
+
(result2, { path: path23, field }, columnIndex) => {
|
|
5291
5386
|
let decoder;
|
|
5292
5387
|
if (is(field, Column)) {
|
|
5293
5388
|
decoder = field;
|
|
@@ -5299,8 +5394,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
5299
5394
|
decoder = field.sql.decoder;
|
|
5300
5395
|
}
|
|
5301
5396
|
let node = result2;
|
|
5302
|
-
for (const [pathChunkIndex, pathChunk] of
|
|
5303
|
-
if (pathChunkIndex <
|
|
5397
|
+
for (const [pathChunkIndex, pathChunk] of path23.entries()) {
|
|
5398
|
+
if (pathChunkIndex < path23.length - 1) {
|
|
5304
5399
|
if (!(pathChunk in node)) {
|
|
5305
5400
|
node[pathChunk] = {};
|
|
5306
5401
|
}
|
|
@@ -5308,8 +5403,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
5308
5403
|
} else {
|
|
5309
5404
|
const rawValue = row[columnIndex];
|
|
5310
5405
|
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
5311
|
-
if (joinsNotNullableMap && is(field, Column) &&
|
|
5312
|
-
const objectName =
|
|
5406
|
+
if (joinsNotNullableMap && is(field, Column) && path23.length === 2) {
|
|
5407
|
+
const objectName = path23[0];
|
|
5313
5408
|
if (!(objectName in nullifyMap)) {
|
|
5314
5409
|
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
5315
5410
|
} else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
@@ -9256,13 +9351,13 @@ function Subscribe(postgres2, options) {
|
|
|
9256
9351
|
}
|
|
9257
9352
|
}
|
|
9258
9353
|
function handle(a, b2) {
|
|
9259
|
-
const
|
|
9354
|
+
const path23 = b2.relation.schema + "." + b2.relation.table;
|
|
9260
9355
|
call("*", a, b2);
|
|
9261
|
-
call("*:" +
|
|
9262
|
-
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);
|
|
9263
9358
|
call(b2.command, a, b2);
|
|
9264
|
-
call(b2.command + ":" +
|
|
9265
|
-
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);
|
|
9266
9361
|
}
|
|
9267
9362
|
function pong() {
|
|
9268
9363
|
const x2 = Buffer.alloc(34);
|
|
@@ -9375,8 +9470,8 @@ function parseEvent(x) {
|
|
|
9375
9470
|
const xs = x.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i) || [];
|
|
9376
9471
|
if (!xs)
|
|
9377
9472
|
throw new Error("Malformed subscribe pattern: " + x);
|
|
9378
|
-
const [, command,
|
|
9379
|
-
return (command || "*") + (
|
|
9473
|
+
const [, command, path23, key] = xs;
|
|
9474
|
+
return (command || "*") + (path23 ? ":" + (path23.indexOf(".") === -1 ? "public." + path23 : path23) : "") + (key ? "=" + key : "");
|
|
9380
9475
|
}
|
|
9381
9476
|
var noop2;
|
|
9382
9477
|
var init_subscribe = __esm({
|
|
@@ -9457,7 +9552,7 @@ var init_large = __esm({
|
|
|
9457
9552
|
});
|
|
9458
9553
|
|
|
9459
9554
|
// ../../node_modules/postgres/src/index.js
|
|
9460
|
-
import
|
|
9555
|
+
import os8 from "os";
|
|
9461
9556
|
import fs11 from "fs";
|
|
9462
9557
|
function Postgres(a, b2) {
|
|
9463
9558
|
const options = parseOptions(a, b2), subscribe = options.no_subscribe || Subscribe(Postgres, { ...options });
|
|
@@ -9514,10 +9609,10 @@ function Postgres(a, b2) {
|
|
|
9514
9609
|
});
|
|
9515
9610
|
return query;
|
|
9516
9611
|
}
|
|
9517
|
-
function file2(
|
|
9612
|
+
function file2(path23, args = [], options2 = {}) {
|
|
9518
9613
|
arguments.length === 2 && !Array.isArray(args) && (options2 = args, args = []);
|
|
9519
9614
|
const query = new Query([], args, (query2) => {
|
|
9520
|
-
fs11.readFile(
|
|
9615
|
+
fs11.readFile(path23, "utf8", (err, string4) => {
|
|
9521
9616
|
if (err)
|
|
9522
9617
|
return query2.reject(err);
|
|
9523
9618
|
query2.strings = [string4];
|
|
@@ -9835,13 +9930,13 @@ function parseUrl(url2) {
|
|
|
9835
9930
|
}
|
|
9836
9931
|
function osUsername() {
|
|
9837
9932
|
try {
|
|
9838
|
-
return
|
|
9933
|
+
return os8.userInfo().username;
|
|
9839
9934
|
} catch (_) {
|
|
9840
9935
|
return process.env.USERNAME || process.env.USER || process.env.LOGNAME;
|
|
9841
9936
|
}
|
|
9842
9937
|
}
|
|
9843
9938
|
var src_default;
|
|
9844
|
-
var
|
|
9939
|
+
var init_src = __esm({
|
|
9845
9940
|
"../../node_modules/postgres/src/index.js"() {
|
|
9846
9941
|
init_types();
|
|
9847
9942
|
init_connection();
|
|
@@ -14096,12 +14191,12 @@ var init_session2 = __esm({
|
|
|
14096
14191
|
init_tracing();
|
|
14097
14192
|
init_utils();
|
|
14098
14193
|
PostgresJsPreparedQuery = class extends PgPreparedQuery {
|
|
14099
|
-
constructor(client, queryString, params,
|
|
14194
|
+
constructor(client, queryString, params, logger33, cache, queryMetadata, cacheConfig, fields, _isResponseInArrayMode, customResultMapper) {
|
|
14100
14195
|
super({ sql: queryString, params }, cache, queryMetadata, cacheConfig);
|
|
14101
14196
|
this.client = client;
|
|
14102
14197
|
this.queryString = queryString;
|
|
14103
14198
|
this.params = params;
|
|
14104
|
-
this.logger =
|
|
14199
|
+
this.logger = logger33;
|
|
14105
14200
|
this.fields = fields;
|
|
14106
14201
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
14107
14202
|
this.customResultMapper = customResultMapper;
|
|
@@ -14242,11 +14337,11 @@ function construct(client, config2 = {}) {
|
|
|
14242
14337
|
client.options.serializers["114"] = transparentParser;
|
|
14243
14338
|
client.options.serializers["3802"] = transparentParser;
|
|
14244
14339
|
const dialect = new PgDialect({ casing: config2.casing });
|
|
14245
|
-
let
|
|
14340
|
+
let logger33;
|
|
14246
14341
|
if (config2.logger === true) {
|
|
14247
|
-
|
|
14342
|
+
logger33 = new DefaultLogger();
|
|
14248
14343
|
} else if (config2.logger !== false) {
|
|
14249
|
-
|
|
14344
|
+
logger33 = config2.logger;
|
|
14250
14345
|
}
|
|
14251
14346
|
let schema;
|
|
14252
14347
|
if (config2.schema) {
|
|
@@ -14260,7 +14355,7 @@ function construct(client, config2 = {}) {
|
|
|
14260
14355
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
14261
14356
|
};
|
|
14262
14357
|
}
|
|
14263
|
-
const session = new PostgresJsSession(client, dialect, schema, { logger:
|
|
14358
|
+
const session = new PostgresJsSession(client, dialect, schema, { logger: logger33, cache: config2.cache });
|
|
14264
14359
|
const db2 = new PostgresJsDatabase(dialect, session, schema);
|
|
14265
14360
|
db2.$client = client;
|
|
14266
14361
|
db2.$cache = config2.cache;
|
|
@@ -14290,7 +14385,7 @@ function drizzle(...params) {
|
|
|
14290
14385
|
var PostgresJsDatabase;
|
|
14291
14386
|
var init_driver = __esm({
|
|
14292
14387
|
"../../node_modules/drizzle-orm/postgres-js/driver.js"() {
|
|
14293
|
-
|
|
14388
|
+
init_src();
|
|
14294
14389
|
init_entity();
|
|
14295
14390
|
init_logger();
|
|
14296
14391
|
init_db();
|
|
@@ -14575,10 +14670,10 @@ function mergeDefs(...defs) {
|
|
|
14575
14670
|
function cloneDef(schema) {
|
|
14576
14671
|
return mergeDefs(schema._zod.def);
|
|
14577
14672
|
}
|
|
14578
|
-
function getElementAtPath(obj,
|
|
14579
|
-
if (!
|
|
14673
|
+
function getElementAtPath(obj, path23) {
|
|
14674
|
+
if (!path23)
|
|
14580
14675
|
return obj;
|
|
14581
|
-
return
|
|
14676
|
+
return path23.reduce((acc, key) => acc?.[key], obj);
|
|
14582
14677
|
}
|
|
14583
14678
|
function promiseAllObject(promisesObj) {
|
|
14584
14679
|
const keys = Object.keys(promisesObj);
|
|
@@ -14890,11 +14985,11 @@ function aborted(x, startIndex = 0) {
|
|
|
14890
14985
|
}
|
|
14891
14986
|
return false;
|
|
14892
14987
|
}
|
|
14893
|
-
function prefixIssues(
|
|
14988
|
+
function prefixIssues(path23, issues) {
|
|
14894
14989
|
return issues.map((iss) => {
|
|
14895
14990
|
var _a2;
|
|
14896
14991
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
14897
|
-
iss.path.unshift(
|
|
14992
|
+
iss.path.unshift(path23);
|
|
14898
14993
|
return iss;
|
|
14899
14994
|
});
|
|
14900
14995
|
}
|
|
@@ -15136,7 +15231,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
|
|
|
15136
15231
|
}
|
|
15137
15232
|
function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
15138
15233
|
const result = { errors: [] };
|
|
15139
|
-
const processError = (error50,
|
|
15234
|
+
const processError = (error50, path23 = []) => {
|
|
15140
15235
|
var _a2, _b;
|
|
15141
15236
|
for (const issue2 of error50.issues) {
|
|
15142
15237
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -15146,7 +15241,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
15146
15241
|
} else if (issue2.code === "invalid_element") {
|
|
15147
15242
|
processError({ issues: issue2.issues }, issue2.path);
|
|
15148
15243
|
} else {
|
|
15149
|
-
const fullpath = [...
|
|
15244
|
+
const fullpath = [...path23, ...issue2.path];
|
|
15150
15245
|
if (fullpath.length === 0) {
|
|
15151
15246
|
result.errors.push(mapper(issue2));
|
|
15152
15247
|
continue;
|
|
@@ -15178,8 +15273,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
15178
15273
|
}
|
|
15179
15274
|
function toDotPath(_path) {
|
|
15180
15275
|
const segs = [];
|
|
15181
|
-
const
|
|
15182
|
-
for (const seg of
|
|
15276
|
+
const path23 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
15277
|
+
for (const seg of path23) {
|
|
15183
15278
|
if (typeof seg === "number")
|
|
15184
15279
|
segs.push(`[${seg}]`);
|
|
15185
15280
|
else if (typeof seg === "symbol")
|
|
@@ -27873,13 +27968,13 @@ function resolveRef(ref, ctx) {
|
|
|
27873
27968
|
if (!ref.startsWith("#")) {
|
|
27874
27969
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
27875
27970
|
}
|
|
27876
|
-
const
|
|
27877
|
-
if (
|
|
27971
|
+
const path23 = ref.slice(1).split("/").filter(Boolean);
|
|
27972
|
+
if (path23.length === 0) {
|
|
27878
27973
|
return ctx.rootSchema;
|
|
27879
27974
|
}
|
|
27880
27975
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
27881
|
-
if (
|
|
27882
|
-
const key =
|
|
27976
|
+
if (path23[0] === defsKey) {
|
|
27977
|
+
const key = path23[1];
|
|
27883
27978
|
if (!key || !ctx.defs[key]) {
|
|
27884
27979
|
throw new Error(`Reference not found: ${ref}`);
|
|
27885
27980
|
}
|
|
@@ -28644,6 +28739,7 @@ var init_users = __esm({
|
|
|
28644
28739
|
"../../packages/database/src/schema/users.ts"() {
|
|
28645
28740
|
"use strict";
|
|
28646
28741
|
init_pg_core();
|
|
28742
|
+
init_drizzle_orm();
|
|
28647
28743
|
userRoleEnum = pgEnum("user_role", [
|
|
28648
28744
|
"student",
|
|
28649
28745
|
"creator_provisional",
|
|
@@ -28691,7 +28787,7 @@ var init_users = __esm({
|
|
|
28691
28787
|
photoUrl: text("photo_url"),
|
|
28692
28788
|
// Cloudflare R2 URL for custom uploaded photo
|
|
28693
28789
|
studentRole: studentRoleEnum("student_role"),
|
|
28694
|
-
//
|
|
28790
|
+
// learner self-id, any role may set it (GH #657 — calibrates exercise difficulty): PM, Developer, Designer, Manager, Outros
|
|
28695
28791
|
referralSource: varchar("referral_source", { length: 50 }),
|
|
28696
28792
|
// How the user heard about tostudy (optional, for attribution)
|
|
28697
28793
|
expertise: varchar("expertise", { length: 200 }),
|
|
@@ -28806,7 +28902,12 @@ var init_users = __esm({
|
|
|
28806
28902
|
externalIdIdx: index("idx_users_external_id").on(
|
|
28807
28903
|
table.provisioningSource,
|
|
28808
28904
|
table.externalUserId
|
|
28809
|
-
)
|
|
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`)
|
|
28810
28911
|
})
|
|
28811
28912
|
);
|
|
28812
28913
|
}
|
|
@@ -28947,6 +29048,14 @@ var init_user_preferences = __esm({
|
|
|
28947
29048
|
emailNewReplies: boolean("email_new_replies").default(true).notNull(),
|
|
28948
29049
|
/** Whether user wants push notifications for mentorship (via MCP) */
|
|
28949
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(),
|
|
28950
29059
|
// i18n nickname pilot column (dogfooding)
|
|
28951
29060
|
nicknameI18n: jsonb("nickname_i18n").$type(),
|
|
28952
29061
|
// Timestamps
|
|
@@ -29209,7 +29318,6 @@ var init_courses3 = __esm({
|
|
|
29209
29318
|
tags: jsonb("tags").$type().default([]).notNull(),
|
|
29210
29319
|
// Search tags: ['agent', 'mcp', 'automation', 'claude-code']
|
|
29211
29320
|
categoryId: uuid("category_id").references(() => courseCategories.id, { onDelete: "set null" }),
|
|
29212
|
-
enrollmentCount: integer("enrollment_count").default(0).notNull(),
|
|
29213
29321
|
thumbnailUrl: varchar("thumbnail_url", { length: 500 }),
|
|
29214
29322
|
videoIntroUrl: varchar("video_intro_url", { length: 500 }),
|
|
29215
29323
|
// Story 10.8: Video upload integration
|
|
@@ -29314,8 +29422,6 @@ var init_courses3 = __esm({
|
|
|
29314
29422
|
// B-tree index for essential course filter
|
|
29315
29423
|
createdAtIdx: index("courses_created_at_idx").on(table.createdAt),
|
|
29316
29424
|
// B-tree index for newest sort
|
|
29317
|
-
enrollmentCountIdx: index("courses_enrollment_count_idx").on(table.enrollmentCount),
|
|
29318
|
-
// B-tree for best-sellers sort
|
|
29319
29425
|
// Story 11.1: Curadoria queue sorting and filtering indexes
|
|
29320
29426
|
statusIdx: index("courses_status_idx").on(table.status),
|
|
29321
29427
|
// B-tree for status filtering
|
|
@@ -29659,6 +29765,18 @@ var init_credit_wallets = __esm({
|
|
|
29659
29765
|
walletCreatedAtIdx: index("cwt_wallet_created_at_idx").on(table.walletId, table.createdAt),
|
|
29660
29766
|
walletTypeIdx: index("cwt_wallet_type_idx").on(table.walletId, table.type),
|
|
29661
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'`),
|
|
29662
29780
|
referenceTypeCheck: check(
|
|
29663
29781
|
"cwt_reference_type_check",
|
|
29664
29782
|
sql`${table.referenceType} IS NULL OR ${table.referenceType} IN (
|
|
@@ -30202,7 +30320,7 @@ var init_errors6 = __esm({
|
|
|
30202
30320
|
});
|
|
30203
30321
|
|
|
30204
30322
|
// ../../packages/types/src/index.ts
|
|
30205
|
-
var
|
|
30323
|
+
var init_src2 = __esm({
|
|
30206
30324
|
"../../packages/types/src/index.ts"() {
|
|
30207
30325
|
"use strict";
|
|
30208
30326
|
init_user();
|
|
@@ -30224,7 +30342,7 @@ var init_course_reviews = __esm({
|
|
|
30224
30342
|
init_pg_core();
|
|
30225
30343
|
init_users();
|
|
30226
30344
|
init_courses3();
|
|
30227
|
-
|
|
30345
|
+
init_src2();
|
|
30228
30346
|
courseReviewStatusEnum = pgEnum("course_review_status", [
|
|
30229
30347
|
"pending",
|
|
30230
30348
|
"approved",
|
|
@@ -30332,6 +30450,7 @@ var init_enrollments = __esm({
|
|
|
30332
30450
|
"../../packages/database/src/schema/enrollments.ts"() {
|
|
30333
30451
|
"use strict";
|
|
30334
30452
|
init_pg_core();
|
|
30453
|
+
init_drizzle_orm();
|
|
30335
30454
|
init_users();
|
|
30336
30455
|
init_courses3();
|
|
30337
30456
|
init_cohorts();
|
|
@@ -30412,7 +30531,14 @@ var init_enrollments = __esm({
|
|
|
30412
30531
|
table.currentLevel
|
|
30413
30532
|
),
|
|
30414
30533
|
// Paris Group integration: partial index for cohort lookups.
|
|
30415
|
-
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'`)
|
|
30416
30542
|
})
|
|
30417
30543
|
);
|
|
30418
30544
|
}
|
|
@@ -33915,6 +34041,34 @@ var init_mentor_availability = __esm({
|
|
|
33915
34041
|
}
|
|
33916
34042
|
});
|
|
33917
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
|
+
|
|
33918
34072
|
// ../../packages/database/src/schema/mentorship-sessions.ts
|
|
33919
34073
|
var mentorshipSessions2, sessionParticipants2, sessionWaitlist2;
|
|
33920
34074
|
var init_mentorship_sessions = __esm({
|
|
@@ -34178,14 +34332,16 @@ var init_mentorship_packages = __esm({
|
|
|
34178
34332
|
function isCreditUsable(credit) {
|
|
34179
34333
|
return credit.status === "active" && credit.creditsRemaining > 0 && new Date(credit.expiresAt) > /* @__PURE__ */ new Date();
|
|
34180
34334
|
}
|
|
34181
|
-
var creditStatusEnum, mentorshipCredits2, insertMentorshipCreditSchema;
|
|
34335
|
+
var creditStatusEnum, creditOriginEnum, mentorshipCredits2, insertMentorshipCreditSchema;
|
|
34182
34336
|
var init_mentorship_credits = __esm({
|
|
34183
34337
|
"../../packages/database/src/schema/mentorship-credits.ts"() {
|
|
34184
34338
|
"use strict";
|
|
34185
34339
|
init_pg_core();
|
|
34340
|
+
init_drizzle_orm();
|
|
34186
34341
|
init_users();
|
|
34187
34342
|
init_mentorship_packages();
|
|
34188
34343
|
init_mentorship_services();
|
|
34344
|
+
init_enrollments();
|
|
34189
34345
|
init_zod();
|
|
34190
34346
|
creditStatusEnum = pgEnum("mentorship_credit_status", [
|
|
34191
34347
|
"active",
|
|
@@ -34195,12 +34351,17 @@ var init_mentorship_credits = __esm({
|
|
|
34195
34351
|
"expired"
|
|
34196
34352
|
// Credits expired (not used before expiration date)
|
|
34197
34353
|
]);
|
|
34354
|
+
creditOriginEnum = pgEnum("mentorship_credit_origin", ["package", "course_purchase"]);
|
|
34198
34355
|
mentorshipCredits2 = pgTable(
|
|
34199
34356
|
"mentorship_credits",
|
|
34200
34357
|
{
|
|
34201
34358
|
id: uuid("id").defaultRandom().primaryKey(),
|
|
34202
34359
|
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
34203
|
-
|
|
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
|
+
}),
|
|
34204
34365
|
mentorId: uuid("mentor_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
34205
34366
|
serviceId: uuid("service_id").references(() => mentorshipServices2.id, { onDelete: "cascade" }).notNull(),
|
|
34206
34367
|
// Credit balance
|
|
@@ -34210,6 +34371,12 @@ var init_mentorship_credits = __esm({
|
|
|
34210
34371
|
// Current available credits
|
|
34211
34372
|
// Status tracking
|
|
34212
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
|
+
}),
|
|
34213
34380
|
// Payment reference
|
|
34214
34381
|
stripePaymentIntentId: varchar("stripe_payment_intent_id", { length: 100 }),
|
|
34215
34382
|
// Dates
|
|
@@ -34255,21 +34422,47 @@ var init_mentorship_credits = __esm({
|
|
|
34255
34422
|
table.stripePaymentIntentId
|
|
34256
34423
|
),
|
|
34257
34424
|
// ORDER BY purchasedAt DESC (credit transaction history)
|
|
34258
|
-
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
|
+
)
|
|
34259
34434
|
})
|
|
34260
34435
|
);
|
|
34261
34436
|
insertMentorshipCreditSchema = external_exports.object({
|
|
34262
34437
|
userId: external_exports.string().uuid(),
|
|
34263
|
-
|
|
34438
|
+
// FEAT-1288: optional — required iff origin === "package" (refinement below)
|
|
34439
|
+
packageId: external_exports.string().uuid().optional().nullable(),
|
|
34264
34440
|
mentorId: external_exports.string().uuid(),
|
|
34265
34441
|
serviceId: external_exports.string().uuid(),
|
|
34266
34442
|
totalCredits: external_exports.number().int().positive(),
|
|
34267
34443
|
creditsRemaining: external_exports.number().int().min(0),
|
|
34268
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(),
|
|
34269
34447
|
stripePaymentIntentId: external_exports.string().max(100).optional().nullable(),
|
|
34270
34448
|
expiresAt: external_exports.date(),
|
|
34271
34449
|
reminderSent30d: external_exports.boolean().optional().default(false),
|
|
34272
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
|
+
}
|
|
34273
34466
|
});
|
|
34274
34467
|
}
|
|
34275
34468
|
});
|
|
@@ -34468,6 +34661,55 @@ var init_mentorship_transactions = __esm({
|
|
|
34468
34661
|
}
|
|
34469
34662
|
});
|
|
34470
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
|
+
|
|
34471
34713
|
// ../../packages/database/src/schema/session-reviews.ts
|
|
34472
34714
|
var REVIEW_TAGS, sessionReviews2, sessionReviewVotes2;
|
|
34473
34715
|
var init_session_reviews = __esm({
|
|
@@ -34552,11 +34794,13 @@ var init_mentorship_index = __esm({
|
|
|
34552
34794
|
init_mentorship_templates();
|
|
34553
34795
|
init_mentorship_services();
|
|
34554
34796
|
init_mentor_availability();
|
|
34797
|
+
init_mentor_specializations();
|
|
34555
34798
|
init_mentorship_sessions();
|
|
34556
34799
|
init_session_resources();
|
|
34557
34800
|
init_mentorship_transactions();
|
|
34558
34801
|
init_mentorship_packages();
|
|
34559
34802
|
init_mentorship_credits();
|
|
34803
|
+
init_course_mentoria_offers();
|
|
34560
34804
|
init_session_reviews();
|
|
34561
34805
|
}
|
|
34562
34806
|
});
|
|
@@ -34632,6 +34876,7 @@ var init_transactions = __esm({
|
|
|
34632
34876
|
init_pg_core();
|
|
34633
34877
|
init_courses3();
|
|
34634
34878
|
init_users();
|
|
34879
|
+
init_enrollments();
|
|
34635
34880
|
transactions2 = pgTable(
|
|
34636
34881
|
"transactions",
|
|
34637
34882
|
{
|
|
@@ -34644,6 +34889,15 @@ var init_transactions = __esm({
|
|
|
34644
34889
|
courseId: uuid("course_id").notNull().references(() => courses.id, { onDelete: "restrict" }),
|
|
34645
34890
|
creatorId: uuid("creator_id").notNull().references(() => users.id, { onDelete: "restrict" }),
|
|
34646
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
|
+
}),
|
|
34647
34901
|
// Financial details (all amounts in cents)
|
|
34648
34902
|
amount: integer("amount").notNull(),
|
|
34649
34903
|
// Total amount charged
|
|
@@ -34663,11 +34917,24 @@ var init_transactions = __esm({
|
|
|
34663
34917
|
paymentMethod: varchar("payment_method", { length: 50 }),
|
|
34664
34918
|
// 'card' or 'pix'
|
|
34665
34919
|
status: varchar("status", { length: 20 }).notNull().default("pending"),
|
|
34666
|
-
// 'pending', 'succeeded', 'failed', 'refunded'
|
|
34920
|
+
// 'pending', 'succeeded', 'failed', 'refunded', 'disputed' (GH #718 chargeback)
|
|
34667
34921
|
// Timestamps
|
|
34668
34922
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
34669
34923
|
processedAt: timestamp("processed_at"),
|
|
34670
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)
|
|
34671
34938
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
34672
34939
|
},
|
|
34673
34940
|
(table) => ({
|
|
@@ -34754,6 +35021,56 @@ var init_payouts = __esm({
|
|
|
34754
35021
|
}
|
|
34755
35022
|
});
|
|
34756
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
|
+
|
|
34757
35074
|
// ../../packages/database/src/schema/creator-applications.ts
|
|
34758
35075
|
var creatorApplications2;
|
|
34759
35076
|
var init_creator_applications = __esm({
|
|
@@ -35016,7 +35333,10 @@ var init_course_project_enums = __esm({
|
|
|
35016
35333
|
});
|
|
35017
35334
|
|
|
35018
35335
|
// ../../packages/database/src/schema/course-project-types.ts
|
|
35019
|
-
|
|
35336
|
+
function v3CancelReasonRedisKey(courseId) {
|
|
35337
|
+
return `v3:cancel-reason:${courseId}`;
|
|
35338
|
+
}
|
|
35339
|
+
var CANCEL_REASONS, V3_CANCEL_REASON_TTL_SECONDS;
|
|
35020
35340
|
var init_course_project_types = __esm({
|
|
35021
35341
|
"../../packages/database/src/schema/course-project-types.ts"() {
|
|
35022
35342
|
"use strict";
|
|
@@ -35027,6 +35347,7 @@ var init_course_project_types = __esm({
|
|
|
35027
35347
|
"incomplete_stream",
|
|
35028
35348
|
"unknown"
|
|
35029
35349
|
];
|
|
35350
|
+
V3_CANCEL_REASON_TTL_SECONDS = 86400;
|
|
35030
35351
|
}
|
|
35031
35352
|
});
|
|
35032
35353
|
|
|
@@ -35066,6 +35387,7 @@ var init_course_projects = __esm({
|
|
|
35066
35387
|
"../../packages/database/src/schema/course-projects.ts"() {
|
|
35067
35388
|
"use strict";
|
|
35068
35389
|
init_pg_core();
|
|
35390
|
+
init_drizzle_orm();
|
|
35069
35391
|
init_users();
|
|
35070
35392
|
init_brainstormings();
|
|
35071
35393
|
init_courses3();
|
|
@@ -35184,7 +35506,9 @@ var init_course_projects = __esm({
|
|
|
35184
35506
|
statusIdx: index("course_projects_status_idx").on(table.status),
|
|
35185
35507
|
currentPhaseIdx: index("course_projects_current_phase_idx").on(table.currentPhase),
|
|
35186
35508
|
sourceTypeIdx: index("course_projects_source_type_idx").on(table.sourceType),
|
|
35187
|
-
|
|
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`),
|
|
35188
35512
|
categoryIdIdx: index("course_projects_category_id_idx").on(table.categoryId),
|
|
35189
35513
|
// ORDER BY createdAt/updatedAt DESC (project listing + creator initial state)
|
|
35190
35514
|
createdAtIdx: index("course_projects_created_at_idx").on(table.createdAt),
|
|
@@ -37003,6 +37327,12 @@ var init_security_audit_log = __esm({
|
|
|
37003
37327
|
"account.role_change",
|
|
37004
37328
|
"account.profile_update",
|
|
37005
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",
|
|
37006
37336
|
// Admin events
|
|
37007
37337
|
"admin.user_suspend",
|
|
37008
37338
|
"admin.user_unsuspend",
|
|
@@ -38045,12 +38375,14 @@ var init_system_config = __esm({
|
|
|
38045
38375
|
"ai.context.compression_threshold": "ai.context.compression_threshold",
|
|
38046
38376
|
// Business - Pricing
|
|
38047
38377
|
"business.pricing.min_course_price_brl": "business.pricing.min_course_price_brl",
|
|
38048
|
-
"business.pricing.mentorship_platform_fee_percent": "business.pricing.mentorship_platform_fee_percent",
|
|
38049
38378
|
"business.pricing.course_mentoria_creator_share": "business.pricing.course_mentoria_creator_share",
|
|
38050
38379
|
"business.pricing.course_mentoria_platform_share": "business.pricing.course_mentoria_platform_share",
|
|
38051
|
-
"business.pricing.course_selfpaced_creator_share": "business.pricing.course_selfpaced_creator_share",
|
|
38052
|
-
"business.pricing.course_selfpaced_platform_share": "business.pricing.course_selfpaced_platform_share",
|
|
38053
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",
|
|
38054
38386
|
// Business - Monitoring Thresholds
|
|
38055
38387
|
"business.monitoring.cache_success_threshold": "business.monitoring.cache_success_threshold",
|
|
38056
38388
|
"business.monitoring.cache_warning_threshold": "business.monitoring.cache_warning_threshold",
|
|
@@ -38639,7 +38971,7 @@ var init_course_transfer_logs = __esm({
|
|
|
38639
38971
|
"use strict";
|
|
38640
38972
|
init_pg_core();
|
|
38641
38973
|
init_users();
|
|
38642
|
-
transferTypeEnum = pgEnum("transfer_type", ["export", "import"]);
|
|
38974
|
+
transferTypeEnum = pgEnum("transfer_type", ["export", "import", "reassign"]);
|
|
38643
38975
|
transferStatusEnum = pgEnum("transfer_status", [
|
|
38644
38976
|
"pending",
|
|
38645
38977
|
"processing",
|
|
@@ -38654,6 +38986,8 @@ var init_course_transfer_logs = __esm({
|
|
|
38654
38986
|
adminId: uuid("admin_id").references(() => users.id, { onDelete: "restrict" }).notNull(),
|
|
38655
38987
|
type: transferTypeEnum("type").notNull(),
|
|
38656
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" }),
|
|
38657
38991
|
courseName: text("course_name").notNull(),
|
|
38658
38992
|
sourceEnvironment: text("source_environment"),
|
|
38659
38993
|
status: transferStatusEnum("status").default("pending").notNull(),
|
|
@@ -38668,9 +39002,7 @@ var init_course_transfer_logs = __esm({
|
|
|
38668
39002
|
adminIdIdx: index("course_transfer_logs_admin_id_idx").on(table.adminId),
|
|
38669
39003
|
typeIdx: index("course_transfer_logs_type_idx").on(table.type),
|
|
38670
39004
|
statusIdx: index("course_transfer_logs_status_idx").on(table.status),
|
|
38671
|
-
createdAtIdx: index("course_transfer_logs_created_at_idx").on(
|
|
38672
|
-
table.createdAt
|
|
38673
|
-
)
|
|
39005
|
+
createdAtIdx: index("course_transfer_logs_created_at_idx").on(table.createdAt)
|
|
38674
39006
|
})
|
|
38675
39007
|
);
|
|
38676
39008
|
}
|
|
@@ -40709,34 +41041,6 @@ var init_magic_link_tokens = __esm({
|
|
|
40709
41041
|
}
|
|
40710
41042
|
});
|
|
40711
41043
|
|
|
40712
|
-
// ../../packages/database/src/schema/platform-fees.ts
|
|
40713
|
-
var platformFeeTypeEnum, platformFees;
|
|
40714
|
-
var init_platform_fees = __esm({
|
|
40715
|
-
"../../packages/database/src/schema/platform-fees.ts"() {
|
|
40716
|
-
"use strict";
|
|
40717
|
-
init_pg_core();
|
|
40718
|
-
platformFeeTypeEnum = pgEnum("platform_fee_type", ["course", "mentorship"]);
|
|
40719
|
-
platformFees = pgTable(
|
|
40720
|
-
"platform_fees",
|
|
40721
|
-
{
|
|
40722
|
-
id: uuid("id").defaultRandom().primaryKey(),
|
|
40723
|
-
countryCode: varchar("country_code", { length: 2 }).notNull(),
|
|
40724
|
-
feeType: platformFeeTypeEnum("fee_type").notNull(),
|
|
40725
|
-
feePercent: numeric("fee_percent", { precision: 5, scale: 2 }).notNull(),
|
|
40726
|
-
isActive: boolean("is_active").default(true),
|
|
40727
|
-
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
40728
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
40729
|
-
},
|
|
40730
|
-
(table) => ({
|
|
40731
|
-
countryFeeTypeUniq: unique("platform_fees_country_fee_type_uniq").on(
|
|
40732
|
-
table.countryCode,
|
|
40733
|
-
table.feeType
|
|
40734
|
-
)
|
|
40735
|
-
})
|
|
40736
|
-
);
|
|
40737
|
-
}
|
|
40738
|
-
});
|
|
40739
|
-
|
|
40740
41044
|
// ../../packages/database/src/schema/payout-methods.ts
|
|
40741
41045
|
var payoutMethods, payoutAccounts;
|
|
40742
41046
|
var init_payout_methods = __esm({
|
|
@@ -40776,6 +41080,34 @@ var init_payout_methods = __esm({
|
|
|
40776
41080
|
}
|
|
40777
41081
|
});
|
|
40778
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
|
+
|
|
40779
41111
|
// ../../packages/database/src/schema/media-assets.ts
|
|
40780
41112
|
var mediaAssetStatusEnum, mediaAssetTypeEnum, mediaAssetDomainEnum, mediaAssets;
|
|
40781
41113
|
var init_media_assets = __esm({
|
|
@@ -40857,7 +41189,7 @@ var init_push_tokens = __esm({
|
|
|
40857
41189
|
});
|
|
40858
41190
|
|
|
40859
41191
|
// ../../packages/database/src/schema/payout.ts
|
|
40860
|
-
var
|
|
41192
|
+
var payoutWithdrawals, payoutBankAccounts, payoutWithdrawalTransitions;
|
|
40861
41193
|
var init_payout = __esm({
|
|
40862
41194
|
"../../packages/database/src/schema/payout.ts"() {
|
|
40863
41195
|
"use strict";
|
|
@@ -40867,22 +41199,6 @@ var init_payout = __esm({
|
|
|
40867
41199
|
init_credit_wallets();
|
|
40868
41200
|
init_credit_wallets();
|
|
40869
41201
|
init_payout_methods();
|
|
40870
|
-
payoutFeeConfig = pgTable(
|
|
40871
|
-
"payout_fee_config",
|
|
40872
|
-
{
|
|
40873
|
-
id: uuid("id").defaultRandom().primaryKey(),
|
|
40874
|
-
mentorId: uuid("mentor_id").references(() => users.id, {
|
|
40875
|
-
onDelete: "cascade"
|
|
40876
|
-
}).unique(),
|
|
40877
|
-
// null = global default
|
|
40878
|
-
feePercent: decimal("fee_percent", { precision: 5, scale: 2 }).notNull(),
|
|
40879
|
-
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
40880
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
40881
|
-
},
|
|
40882
|
-
(table) => ({
|
|
40883
|
-
feeRange: check("pfc_fee_range", sql`${table.feePercent} >= 0 AND ${table.feePercent} <= 100`)
|
|
40884
|
-
})
|
|
40885
|
-
);
|
|
40886
41202
|
payoutWithdrawals = pgTable(
|
|
40887
41203
|
"payout_withdrawals",
|
|
40888
41204
|
{
|
|
@@ -40899,10 +41215,17 @@ var init_payout = __esm({
|
|
|
40899
41215
|
precision: 10,
|
|
40900
41216
|
scale: 4
|
|
40901
41217
|
}).notNull(),
|
|
40902
|
-
|
|
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(),
|
|
40903
41222
|
grossUsd: decimal("gross_usd", { precision: 10, scale: 4 }).notNull(),
|
|
40904
|
-
|
|
41223
|
+
taxUsd: decimal("tax_usd", { precision: 10, scale: 4 }).notNull(),
|
|
40905
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 }),
|
|
40906
41229
|
exchangeRateBrl: decimal("exchange_rate_brl", {
|
|
40907
41230
|
precision: 10,
|
|
40908
41231
|
scale: 4
|
|
@@ -41101,6 +41424,7 @@ var init_course_allowlist = __esm({
|
|
|
41101
41424
|
"../../packages/database/src/schema/course-allowlist.ts"() {
|
|
41102
41425
|
"use strict";
|
|
41103
41426
|
init_pg_core();
|
|
41427
|
+
init_drizzle_orm();
|
|
41104
41428
|
init_courses3();
|
|
41105
41429
|
init_users();
|
|
41106
41430
|
courseAllowlist = pgTable(
|
|
@@ -41114,14 +41438,20 @@ var init_course_allowlist = __esm({
|
|
|
41114
41438
|
onDelete: "set null"
|
|
41115
41439
|
}),
|
|
41116
41440
|
invitedAt: timestamp("invited_at", { withTimezone: true }).defaultNow().notNull(),
|
|
41117
|
-
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 })
|
|
41118
41446
|
},
|
|
41119
41447
|
(table) => ({
|
|
41120
41448
|
courseEmailUnique: uniqueIndex("course_allowlist_course_email_unique").on(
|
|
41121
41449
|
table.courseId,
|
|
41122
41450
|
table.email
|
|
41123
41451
|
),
|
|
41124
|
-
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`)
|
|
41125
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
|
|
41126
41456
|
})
|
|
41127
41457
|
);
|
|
@@ -41164,6 +41494,119 @@ var init_idempotency = __esm({
|
|
|
41164
41494
|
}
|
|
41165
41495
|
});
|
|
41166
41496
|
|
|
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
|
+
);
|
|
41535
|
+
}
|
|
41536
|
+
});
|
|
41537
|
+
|
|
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"() {
|
|
41542
|
+
"use strict";
|
|
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
|
+
);
|
|
41607
|
+
}
|
|
41608
|
+
});
|
|
41609
|
+
|
|
41167
41610
|
// ../../packages/database/src/schema/index.ts
|
|
41168
41611
|
var schema_exports = {};
|
|
41169
41612
|
__export(schema_exports, {
|
|
@@ -41178,6 +41621,7 @@ __export(schema_exports, {
|
|
|
41178
41621
|
PACKAGE_VALIDITY_OPTIONS: () => PACKAGE_VALIDITY_OPTIONS,
|
|
41179
41622
|
REVIEW_TAGS: () => REVIEW_TAGS,
|
|
41180
41623
|
SUGGESTED_DISCOUNTS: () => SUGGESTED_DISCOUNTS,
|
|
41624
|
+
V3_CANCEL_REASON_TTL_SECONDS: () => V3_CANCEL_REASON_TTL_SECONDS,
|
|
41181
41625
|
accounts: () => accounts,
|
|
41182
41626
|
accountsRelations: () => accountsRelations2,
|
|
41183
41627
|
actionTypeEnum: () => actionTypeEnum,
|
|
@@ -41206,6 +41650,8 @@ __export(schema_exports, {
|
|
|
41206
41650
|
browserSessions: () => browserSessions,
|
|
41207
41651
|
browserSessionsRelations: () => browserSessionsRelations,
|
|
41208
41652
|
cancellationReasonEnum: () => cancellationReasonEnum,
|
|
41653
|
+
catalogSubscriptionCreatorSplits: () => catalogSubscriptionCreatorSplits,
|
|
41654
|
+
catalogSubscriptionRevenuePools: () => catalogSubscriptionRevenuePools,
|
|
41209
41655
|
certificates: () => certificates,
|
|
41210
41656
|
certificatesRelations: () => certificatesRelations2,
|
|
41211
41657
|
challengeType: () => challengeType,
|
|
@@ -41251,6 +41697,7 @@ __export(schema_exports, {
|
|
|
41251
41697
|
courseKnowledgeBases: () => courseKnowledgeBases,
|
|
41252
41698
|
courseKnowledgeBasesRelations: () => courseKnowledgeBasesRelations,
|
|
41253
41699
|
courseLevelEnum: () => courseLevelEnum,
|
|
41700
|
+
courseMentoriaOffers: () => courseMentoriaOffers,
|
|
41254
41701
|
courseProjects: () => courseProjects,
|
|
41255
41702
|
courseProjectsRelations: () => courseProjectsRelations,
|
|
41256
41703
|
courseProposals: () => courseProposals2,
|
|
@@ -41291,6 +41738,7 @@ __export(schema_exports, {
|
|
|
41291
41738
|
creatorVariationAxesRelations: () => creatorVariationAxesRelations,
|
|
41292
41739
|
creditMovementAuditLog: () => creditMovementAuditLog,
|
|
41293
41740
|
creditMovementAuditLogRelations: () => creditMovementAuditLogRelations,
|
|
41741
|
+
creditOriginEnum: () => creditOriginEnum,
|
|
41294
41742
|
creditPackages: () => creditPackages,
|
|
41295
41743
|
creditStatusEnum: () => creditStatusEnum,
|
|
41296
41744
|
creditSubscriptionPlans: () => creditSubscriptionPlans,
|
|
@@ -41340,6 +41788,7 @@ __export(schema_exports, {
|
|
|
41340
41788
|
helpArticleRatings: () => helpArticleRatings,
|
|
41341
41789
|
ideas: () => ideas,
|
|
41342
41790
|
ideasRelations: () => ideasRelations,
|
|
41791
|
+
insertCourseMentoriaOfferSchema: () => insertCourseMentoriaOfferSchema,
|
|
41343
41792
|
insertMentorshipCreditSchema: () => insertMentorshipCreditSchema,
|
|
41344
41793
|
insertMentorshipPackageSchema: () => insertMentorshipPackageSchema,
|
|
41345
41794
|
insertPlatformSettingSchema: () => insertPlatformSettingSchema,
|
|
@@ -41389,6 +41838,7 @@ __export(schema_exports, {
|
|
|
41389
41838
|
mentorAvailabilityExceptions: () => mentorAvailabilityExceptions2,
|
|
41390
41839
|
mentorAvailabilityExceptionsRelations: () => mentorAvailabilityExceptionsRelations2,
|
|
41391
41840
|
mentorAvailabilityRelations: () => mentorAvailabilityRelations2,
|
|
41841
|
+
mentorSpecializations: () => mentorSpecializations,
|
|
41392
41842
|
mentorshipCredits: () => mentorshipCredits2,
|
|
41393
41843
|
mentorshipCreditsRelations: () => mentorshipCreditsRelations2,
|
|
41394
41844
|
mentorshipMessages: () => mentorshipMessages2,
|
|
@@ -41439,7 +41889,6 @@ __export(schema_exports, {
|
|
|
41439
41889
|
pathStatusEnum: () => pathStatusEnum,
|
|
41440
41890
|
payoutAccounts: () => payoutAccounts,
|
|
41441
41891
|
payoutBankAccounts: () => payoutBankAccounts,
|
|
41442
|
-
payoutFeeConfig: () => payoutFeeConfig,
|
|
41443
41892
|
payoutMethods: () => payoutMethods,
|
|
41444
41893
|
payoutStatusEnum: () => payoutStatusEnum,
|
|
41445
41894
|
payoutTransactions: () => payoutTransactions2,
|
|
@@ -41452,8 +41901,6 @@ __export(schema_exports, {
|
|
|
41452
41901
|
pgBackendIdempotencyKeys: () => pgBackendIdempotencyKeys,
|
|
41453
41902
|
pixKeyTypeEnum: () => pixKeyTypeEnum,
|
|
41454
41903
|
platformConfig: () => platformConfig,
|
|
41455
|
-
platformFeeTypeEnum: () => platformFeeTypeEnum,
|
|
41456
|
-
platformFees: () => platformFees,
|
|
41457
41904
|
platformSettings: () => platformSettings2,
|
|
41458
41905
|
playgroundEvalScores: () => playgroundEvalScores,
|
|
41459
41906
|
playgroundEvalScoresRelations: () => playgroundEvalScoresRelations,
|
|
@@ -41471,6 +41918,7 @@ __export(schema_exports, {
|
|
|
41471
41918
|
portfolioViews: () => portfolioViews,
|
|
41472
41919
|
portfolioViewsRelations: () => portfolioViewsRelations,
|
|
41473
41920
|
pricingTiers: () => pricingTiers,
|
|
41921
|
+
profileVisibilityEnum: () => profileVisibilityEnum,
|
|
41474
41922
|
progress: () => progress,
|
|
41475
41923
|
progressRelations: () => progressRelations2,
|
|
41476
41924
|
progressStatusEnum: () => progressStatusEnum,
|
|
@@ -41576,6 +42024,8 @@ __export(schema_exports, {
|
|
|
41576
42024
|
studyModuleSessionsRelations: () => studyModuleSessionsRelations,
|
|
41577
42025
|
studyPhaseV2Values: () => studyPhaseV2Values,
|
|
41578
42026
|
studyPhaseValues: () => studyPhaseValues,
|
|
42027
|
+
subscriptionPoolStatusEnum: () => subscriptionPoolStatusEnum,
|
|
42028
|
+
subscriptionSplitStatusEnum: () => subscriptionSplitStatusEnum,
|
|
41579
42029
|
supportedCurrencies: () => supportedCurrencies,
|
|
41580
42030
|
syncLogs: () => syncLogs,
|
|
41581
42031
|
syncLogsRelations: () => syncLogsRelations2,
|
|
@@ -41601,12 +42051,17 @@ __export(schema_exports, {
|
|
|
41601
42051
|
userBadgesRelations: () => userBadgesRelations2,
|
|
41602
42052
|
userChallengeScores: () => userChallengeScores,
|
|
41603
42053
|
userChallengeScoresRelations: () => userChallengeScoresRelations,
|
|
42054
|
+
userDeletionStatusEnum: () => userDeletionStatusEnum,
|
|
42055
|
+
userDeletions: () => userDeletions,
|
|
41604
42056
|
userFollows: () => userFollows2,
|
|
41605
42057
|
userFollowsRelations: () => userFollowsRelations2,
|
|
41606
42058
|
userPathEnrollments: () => userPathEnrollments,
|
|
41607
42059
|
userPathEnrollmentsRelations: () => userPathEnrollmentsRelations,
|
|
41608
42060
|
userPreferences: () => userPreferences,
|
|
42061
|
+
userPreferencesAudits: () => userPreferencesAudits,
|
|
41609
42062
|
userPreferencesRelations: () => userPreferencesRelations2,
|
|
42063
|
+
userProfileAudits: () => userProfileAudits,
|
|
42064
|
+
userProfiles: () => userProfiles,
|
|
41610
42065
|
userRegionalSettings: () => userRegionalSettings,
|
|
41611
42066
|
userRegionalSettingsRelations: () => userRegionalSettingsRelations,
|
|
41612
42067
|
userRoleEnum: () => userRoleEnum,
|
|
@@ -41614,6 +42069,7 @@ __export(schema_exports, {
|
|
|
41614
42069
|
userUsageQuotas: () => userUsageQuotas2,
|
|
41615
42070
|
users: () => users,
|
|
41616
42071
|
usersRelations: () => usersRelations2,
|
|
42072
|
+
v3CancelReasonRedisKey: () => v3CancelReasonRedisKey,
|
|
41617
42073
|
validationAttempts: () => validationAttempts2,
|
|
41618
42074
|
validationAttemptsRelations: () => validationAttemptsRelations2,
|
|
41619
42075
|
validationLessonProgress: () => validationLessonProgress,
|
|
@@ -41634,7 +42090,8 @@ __export(schema_exports, {
|
|
|
41634
42090
|
videoTemplateNameEnum: () => videoTemplateNameEnum,
|
|
41635
42091
|
videoTypeEnum: () => videoTypeEnum,
|
|
41636
42092
|
webhookEvents: () => webhookEvents2,
|
|
41637
|
-
wishlists: () => wishlists
|
|
42093
|
+
wishlists: () => wishlists,
|
|
42094
|
+
withdrawalTaxes: () => withdrawalTaxes
|
|
41638
42095
|
});
|
|
41639
42096
|
var init_schema3 = __esm({
|
|
41640
42097
|
"../../packages/database/src/schema/index.ts"() {
|
|
@@ -41650,6 +42107,7 @@ var init_schema3 = __esm({
|
|
|
41650
42107
|
init_mentorship_index();
|
|
41651
42108
|
init_reviews();
|
|
41652
42109
|
init_payouts();
|
|
42110
|
+
init_subscription_pools();
|
|
41653
42111
|
init_creator_index();
|
|
41654
42112
|
init_webhook_events();
|
|
41655
42113
|
init_transactions();
|
|
@@ -41725,8 +42183,8 @@ var init_schema3 = __esm({
|
|
|
41725
42183
|
init_tutor_content_issues();
|
|
41726
42184
|
init_magic_link_tokens();
|
|
41727
42185
|
init_mobile_refresh_tokens();
|
|
41728
|
-
init_platform_fees();
|
|
41729
42186
|
init_payout_methods();
|
|
42187
|
+
init_withdrawal_taxes();
|
|
41730
42188
|
init_media_assets();
|
|
41731
42189
|
init_push_tokens();
|
|
41732
42190
|
init_payout();
|
|
@@ -41736,6 +42194,9 @@ var init_schema3 = __esm({
|
|
|
41736
42194
|
init_course_visibility();
|
|
41737
42195
|
init_course_allowlist();
|
|
41738
42196
|
init_idempotency();
|
|
42197
|
+
init_user_deletions();
|
|
42198
|
+
init_user_profiles();
|
|
42199
|
+
init_user_resource_audits();
|
|
41739
42200
|
}
|
|
41740
42201
|
});
|
|
41741
42202
|
|
|
@@ -41743,7 +42204,7 @@ var init_schema3 = __esm({
|
|
|
41743
42204
|
var init_check_module_unlocked = __esm({
|
|
41744
42205
|
"../../packages/database/src/utils/check-module-unlocked.ts"() {
|
|
41745
42206
|
"use strict";
|
|
41746
|
-
|
|
42207
|
+
init_src3();
|
|
41747
42208
|
init_schema3();
|
|
41748
42209
|
}
|
|
41749
42210
|
});
|
|
@@ -41772,11 +42233,11 @@ var init_ids = __esm({
|
|
|
41772
42233
|
|
|
41773
42234
|
// ../../packages/database/src/index.ts
|
|
41774
42235
|
var envSchema, _db, createDb, getDb, db;
|
|
41775
|
-
var
|
|
42236
|
+
var init_src3 = __esm({
|
|
41776
42237
|
"../../packages/database/src/index.ts"() {
|
|
41777
42238
|
"use strict";
|
|
41778
42239
|
init_postgres_js();
|
|
41779
|
-
|
|
42240
|
+
init_src();
|
|
41780
42241
|
init_zod();
|
|
41781
42242
|
init_schema3();
|
|
41782
42243
|
init_schema3();
|
|
@@ -41873,7 +42334,7 @@ var init_formats = __esm({
|
|
|
41873
42334
|
var init_parser = __esm({
|
|
41874
42335
|
"../../packages/tostudy-core/src/exercises/parser.ts"() {
|
|
41875
42336
|
"use strict";
|
|
41876
|
-
|
|
42337
|
+
init_src2();
|
|
41877
42338
|
init_formats();
|
|
41878
42339
|
init_formats();
|
|
41879
42340
|
}
|
|
@@ -41897,8 +42358,8 @@ var init_lesson_exercise_data = __esm({
|
|
|
41897
42358
|
var init_sync_enrollment_progress = __esm({
|
|
41898
42359
|
"../../packages/tostudy-core/src/learning/sync-enrollment-progress.ts"() {
|
|
41899
42360
|
"use strict";
|
|
41900
|
-
|
|
41901
|
-
|
|
42361
|
+
init_src3();
|
|
42362
|
+
init_dist();
|
|
41902
42363
|
}
|
|
41903
42364
|
});
|
|
41904
42365
|
|
|
@@ -41907,21 +42368,38 @@ var DEFAULT_MAX_SESSION_TIME_SECONDS;
|
|
|
41907
42368
|
var init_study_state_sync = __esm({
|
|
41908
42369
|
"../../packages/tostudy-core/src/learning/study-state-sync.ts"() {
|
|
41909
42370
|
"use strict";
|
|
41910
|
-
|
|
42371
|
+
init_src3();
|
|
41911
42372
|
DEFAULT_MAX_SESSION_TIME_SECONDS = 2 * 60 * 60;
|
|
41912
42373
|
}
|
|
41913
42374
|
});
|
|
41914
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
|
+
|
|
41915
42391
|
// ../../packages/tostudy-core/src/learning/start-module-full.ts
|
|
41916
42392
|
var init_start_module_full = __esm({
|
|
41917
42393
|
"../../packages/tostudy-core/src/learning/start-module-full.ts"() {
|
|
41918
42394
|
"use strict";
|
|
41919
|
-
|
|
42395
|
+
init_src3();
|
|
41920
42396
|
init_parser();
|
|
41921
42397
|
init_exercise_types();
|
|
41922
42398
|
init_lesson_exercise_data();
|
|
41923
42399
|
init_sync_enrollment_progress();
|
|
41924
42400
|
init_study_state_sync();
|
|
42401
|
+
init_entitlement();
|
|
42402
|
+
init_archived_access();
|
|
41925
42403
|
}
|
|
41926
42404
|
});
|
|
41927
42405
|
|
|
@@ -41929,10 +42407,13 @@ var init_start_module_full = __esm({
|
|
|
41929
42407
|
var init_next_lesson_full = __esm({
|
|
41930
42408
|
"../../packages/tostudy-core/src/learning/next-lesson-full.ts"() {
|
|
41931
42409
|
"use strict";
|
|
41932
|
-
|
|
42410
|
+
init_src3();
|
|
42411
|
+
init_dist();
|
|
41933
42412
|
init_parser();
|
|
41934
42413
|
init_lesson_exercise_data();
|
|
41935
42414
|
init_sync_enrollment_progress();
|
|
42415
|
+
init_entitlement();
|
|
42416
|
+
init_archived_access();
|
|
41936
42417
|
init_study_state_sync();
|
|
41937
42418
|
}
|
|
41938
42419
|
});
|
|
@@ -41941,8 +42422,8 @@ var init_next_lesson_full = __esm({
|
|
|
41941
42422
|
var init_student_memory = __esm({
|
|
41942
42423
|
"../../packages/tostudy-core/src/memory/student-memory.ts"() {
|
|
41943
42424
|
"use strict";
|
|
41944
|
-
|
|
41945
|
-
|
|
42425
|
+
init_src3();
|
|
42426
|
+
init_dist();
|
|
41946
42427
|
}
|
|
41947
42428
|
});
|
|
41948
42429
|
|
|
@@ -41950,7 +42431,7 @@ var init_student_memory = __esm({
|
|
|
41950
42431
|
var init_summarize_lesson = __esm({
|
|
41951
42432
|
"../../packages/tostudy-core/src/learning/summarize-lesson.ts"() {
|
|
41952
42433
|
"use strict";
|
|
41953
|
-
|
|
42434
|
+
init_dist();
|
|
41954
42435
|
}
|
|
41955
42436
|
});
|
|
41956
42437
|
|
|
@@ -41958,14 +42439,16 @@ var init_summarize_lesson = __esm({
|
|
|
41958
42439
|
var init_validate_solution_full = __esm({
|
|
41959
42440
|
"../../packages/tostudy-core/src/learning/validate-solution-full.ts"() {
|
|
41960
42441
|
"use strict";
|
|
41961
|
-
|
|
41962
|
-
|
|
42442
|
+
init_src3();
|
|
42443
|
+
init_dist();
|
|
41963
42444
|
init_parser();
|
|
41964
42445
|
init_extractors();
|
|
41965
42446
|
init_exercise_types();
|
|
41966
42447
|
init_study_state_sync();
|
|
41967
42448
|
init_sync_enrollment_progress();
|
|
41968
42449
|
init_student_memory();
|
|
42450
|
+
init_entitlement();
|
|
42451
|
+
init_archived_access();
|
|
41969
42452
|
init_summarize_lesson();
|
|
41970
42453
|
}
|
|
41971
42454
|
});
|
|
@@ -41974,8 +42457,10 @@ var init_validate_solution_full = __esm({
|
|
|
41974
42457
|
var init_go_to_lesson = __esm({
|
|
41975
42458
|
"../../packages/tostudy-core/src/learning/go-to-lesson.ts"() {
|
|
41976
42459
|
"use strict";
|
|
41977
|
-
|
|
42460
|
+
init_src3();
|
|
41978
42461
|
init_parser();
|
|
42462
|
+
init_entitlement();
|
|
42463
|
+
init_archived_access();
|
|
41979
42464
|
}
|
|
41980
42465
|
});
|
|
41981
42466
|
|
|
@@ -41983,8 +42468,9 @@ var init_go_to_lesson = __esm({
|
|
|
41983
42468
|
var init_get_lesson_content_full = __esm({
|
|
41984
42469
|
"../../packages/tostudy-core/src/learning/get-lesson-content-full.ts"() {
|
|
41985
42470
|
"use strict";
|
|
41986
|
-
|
|
42471
|
+
init_src3();
|
|
41987
42472
|
init_parser();
|
|
42473
|
+
init_entitlement();
|
|
41988
42474
|
}
|
|
41989
42475
|
});
|
|
41990
42476
|
|
|
@@ -42000,9 +42486,11 @@ var init_formatter2 = __esm({
|
|
|
42000
42486
|
var init_get_hint_full = __esm({
|
|
42001
42487
|
"../../packages/tostudy-core/src/learning/get-hint-full.ts"() {
|
|
42002
42488
|
"use strict";
|
|
42003
|
-
|
|
42489
|
+
init_src3();
|
|
42004
42490
|
init_parser();
|
|
42005
42491
|
init_formatter2();
|
|
42492
|
+
init_entitlement();
|
|
42493
|
+
init_archived_access();
|
|
42006
42494
|
}
|
|
42007
42495
|
});
|
|
42008
42496
|
|
|
@@ -42010,8 +42498,8 @@ var init_get_hint_full = __esm({
|
|
|
42010
42498
|
var init_explain_concept = __esm({
|
|
42011
42499
|
"../../packages/tostudy-core/src/learning/explain-concept.ts"() {
|
|
42012
42500
|
"use strict";
|
|
42013
|
-
|
|
42014
|
-
|
|
42501
|
+
init_src3();
|
|
42502
|
+
init_dist();
|
|
42015
42503
|
}
|
|
42016
42504
|
});
|
|
42017
42505
|
|
|
@@ -42051,10 +42539,6 @@ async function runStart(opts, deps = defaultDeps3) {
|
|
|
42051
42539
|
const session = await deps.requireSession();
|
|
42052
42540
|
const activeCourse = await deps.requireActiveCourse();
|
|
42053
42541
|
const onboarding = await deps.getCourseOnboardingStatus(activeCourse);
|
|
42054
|
-
if (!onboarding.initReady) {
|
|
42055
|
-
deps.stderrWrite(`Dica: rode \`tostudy init\` para personalizar o tutor ao seu contexto.
|
|
42056
|
-
`);
|
|
42057
|
-
}
|
|
42058
42542
|
const driftWarning = await deps.checkCourseDrift();
|
|
42059
42543
|
if (driftWarning) deps.stderrWrite(driftWarning + "\n");
|
|
42060
42544
|
const data = deps.createHttpProvider(session.apiUrl, session.token);
|
|
@@ -42073,12 +42557,20 @@ async function runStart(opts, deps = defaultDeps3) {
|
|
|
42073
42557
|
} else {
|
|
42074
42558
|
deps.output(deps.formatModuleStart(moduleData), { json: false });
|
|
42075
42559
|
}
|
|
42560
|
+
if (!onboarding.initReady) {
|
|
42561
|
+
deps.stderrWrite(`Dica: rode \`tostudy init\` para personalizar o tutor ao seu contexto.
|
|
42562
|
+
`);
|
|
42563
|
+
}
|
|
42076
42564
|
} catch (err) {
|
|
42077
42565
|
if (err instanceof CliApiError && err.status === 403 && err.message === "CHANNEL_MISMATCH") {
|
|
42078
42566
|
process.stderr.write("Este curso n\xE3o est\xE1 dispon\xEDvel via CLI.\n");
|
|
42079
42567
|
process.stderr.write("Acesse tostudy.ai para estudar este curso pelo ChatStudy.\n");
|
|
42080
42568
|
process.exit(1);
|
|
42081
42569
|
}
|
|
42570
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42571
|
+
deps.stderrWrite(getErrors().enrollmentNotEntitled);
|
|
42572
|
+
process.exit(1);
|
|
42573
|
+
}
|
|
42082
42574
|
if (isCourseArchivedError(err)) {
|
|
42083
42575
|
deps.stderrWrite(getErrors().courseArchived);
|
|
42084
42576
|
process.exit(1);
|
|
@@ -42091,7 +42583,7 @@ var logger9, defaultDeps3, startCommand;
|
|
|
42091
42583
|
var init_start = __esm({
|
|
42092
42584
|
"src/commands/start.ts"() {
|
|
42093
42585
|
"use strict";
|
|
42094
|
-
|
|
42586
|
+
init_dist();
|
|
42095
42587
|
init_lessons2();
|
|
42096
42588
|
init_http();
|
|
42097
42589
|
init_guards();
|
|
@@ -42128,7 +42620,7 @@ var logger10, startNextCommand;
|
|
|
42128
42620
|
var init_start_next = __esm({
|
|
42129
42621
|
"src/commands/start-next.ts"() {
|
|
42130
42622
|
"use strict";
|
|
42131
|
-
|
|
42623
|
+
init_dist();
|
|
42132
42624
|
init_lessons2();
|
|
42133
42625
|
init_http();
|
|
42134
42626
|
init_guards();
|
|
@@ -42163,6 +42655,10 @@ var init_start_next = __esm({
|
|
|
42163
42655
|
process.stderr.write("\u2192 tostudy courses para ver outros cursos\n");
|
|
42164
42656
|
process.exit(0);
|
|
42165
42657
|
}
|
|
42658
|
+
if (isEnrollmentNotEntitledError(err)) {
|
|
42659
|
+
process.stderr.write(getErrors().enrollmentNotEntitled);
|
|
42660
|
+
process.exit(1);
|
|
42661
|
+
}
|
|
42166
42662
|
if (isCourseArchivedError(err)) {
|
|
42167
42663
|
process.stderr.write(getErrors().courseArchived);
|
|
42168
42664
|
process.exit(1);
|
|
@@ -42181,7 +42677,7 @@ var logger11, nextCommand;
|
|
|
42181
42677
|
var init_next = __esm({
|
|
42182
42678
|
"src/commands/next.ts"() {
|
|
42183
42679
|
"use strict";
|
|
42184
|
-
|
|
42680
|
+
init_dist();
|
|
42185
42681
|
init_lessons2();
|
|
42186
42682
|
init_http();
|
|
42187
42683
|
init_guards();
|
|
@@ -42214,6 +42710,12 @@ var init_next = __esm({
|
|
|
42214
42710
|
output(formatLesson(lessonData), { json: false });
|
|
42215
42711
|
}
|
|
42216
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
|
+
}
|
|
42217
42719
|
if (isCourseArchivedError(err)) {
|
|
42218
42720
|
const friendly = getErrors().courseArchived;
|
|
42219
42721
|
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
@@ -42252,6 +42754,7 @@ var init_next = __esm({
|
|
|
42252
42754
|
|
|
42253
42755
|
// src/commands/lesson.ts
|
|
42254
42756
|
import { Command as Command11 } from "commander";
|
|
42757
|
+
import path13 from "node:path";
|
|
42255
42758
|
function adjustTimeEstimate(type, baseMinutes) {
|
|
42256
42759
|
if (type === "exercise") return Math.max(baseMinutes, 30);
|
|
42257
42760
|
return baseMinutes;
|
|
@@ -42259,15 +42762,29 @@ function adjustTimeEstimate(type, baseMinutes) {
|
|
|
42259
42762
|
function isCheckpoint(title) {
|
|
42260
42763
|
return /^checkpoint/i.test(title.trim());
|
|
42261
42764
|
}
|
|
42262
|
-
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) {
|
|
42263
42772
|
const time4 = adjustTimeEstimate(data.type, data.estimatedTimeMinutes);
|
|
42264
|
-
const
|
|
42265
|
-
|
|
42266
|
-
|
|
42267
|
-
|
|
42268
|
-
|
|
42269
|
-
|
|
42270
|
-
|
|
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);
|
|
42271
42788
|
if (data.acceptanceCriteria) {
|
|
42272
42789
|
lines.push("", "Crit\xE9rios de aceita\xE7\xE3o:", data.acceptanceCriteria);
|
|
42273
42790
|
}
|
|
@@ -42294,7 +42811,7 @@ var logger12, lessonCommand;
|
|
|
42294
42811
|
var init_lesson = __esm({
|
|
42295
42812
|
"src/commands/lesson.ts"() {
|
|
42296
42813
|
"use strict";
|
|
42297
|
-
|
|
42814
|
+
init_dist();
|
|
42298
42815
|
init_lessons2();
|
|
42299
42816
|
init_courses();
|
|
42300
42817
|
init_http();
|
|
@@ -42332,24 +42849,51 @@ var init_lesson = __esm({
|
|
|
42332
42849
|
error("Nenhuma li\xE7\xE3o encontrada para leitura. Rode: tostudy start ou tostudy next");
|
|
42333
42850
|
}
|
|
42334
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
|
+
}
|
|
42335
42873
|
if (opts.json) {
|
|
42336
42874
|
output(content, { json: true });
|
|
42337
42875
|
} else {
|
|
42338
|
-
output(
|
|
42876
|
+
output(
|
|
42877
|
+
formatLessonContent(
|
|
42878
|
+
content,
|
|
42879
|
+
ws.found ? ws.workspacePath : null,
|
|
42880
|
+
activeCourse.courseTitle
|
|
42881
|
+
),
|
|
42882
|
+
{ json: false }
|
|
42883
|
+
);
|
|
42339
42884
|
}
|
|
42340
|
-
if (content.type === "exercise") {
|
|
42341
|
-
|
|
42342
|
-
|
|
42343
|
-
activeCourse.courseTitle,
|
|
42344
|
-
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"
|
|
42345
42888
|
);
|
|
42346
|
-
if (!ws.found) {
|
|
42347
|
-
process.stderr.write(
|
|
42348
|
-
"\n\u{1F4A1} Dica: rode `tostudy select` desta pasta para us\xE1-la como workspace, ou `tostudy workspace setup` para criar em ~/study/.\n"
|
|
42349
|
-
);
|
|
42350
|
-
}
|
|
42351
42889
|
}
|
|
42352
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
|
+
}
|
|
42353
42897
|
if (isInsufficientCreditsError(err)) {
|
|
42354
42898
|
const friendly = getErrors().insufficientCredits;
|
|
42355
42899
|
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
@@ -42370,7 +42914,7 @@ var logger13, hintCommand;
|
|
|
42370
42914
|
var init_hint = __esm({
|
|
42371
42915
|
"src/commands/hint.ts"() {
|
|
42372
42916
|
"use strict";
|
|
42373
|
-
|
|
42917
|
+
init_dist();
|
|
42374
42918
|
init_lessons2();
|
|
42375
42919
|
init_http();
|
|
42376
42920
|
init_guards();
|
|
@@ -42396,11 +42940,17 @@ var init_hint = __esm({
|
|
|
42396
42940
|
output(formatHint(hint), { json: false });
|
|
42397
42941
|
}
|
|
42398
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
|
+
}
|
|
42399
42949
|
if (isCourseArchivedError(err)) {
|
|
42400
42950
|
const friendly = getErrors().courseArchived;
|
|
42401
42951
|
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
42402
|
-
|
|
42403
|
-
|
|
42952
|
+
else process.stderr.write(friendly);
|
|
42953
|
+
process.exit(1);
|
|
42404
42954
|
}
|
|
42405
42955
|
if (isInsufficientCreditsError(err)) {
|
|
42406
42956
|
const friendly = getErrors().insufficientCredits;
|
|
@@ -42436,7 +42986,7 @@ var init_validate_solution = __esm({
|
|
|
42436
42986
|
var init_level_validator = __esm({
|
|
42437
42987
|
"../../packages/tostudy-core/src/exercises/level-validator.ts"() {
|
|
42438
42988
|
"use strict";
|
|
42439
|
-
|
|
42989
|
+
init_src2();
|
|
42440
42990
|
}
|
|
42441
42991
|
});
|
|
42442
42992
|
|
|
@@ -42731,14 +43281,15 @@ var init_init_template = __esm({
|
|
|
42731
43281
|
|
|
42732
43282
|
// src/commands/validate.ts
|
|
42733
43283
|
import fs12 from "node:fs";
|
|
42734
|
-
import
|
|
43284
|
+
import path14 from "node:path";
|
|
42735
43285
|
import { Command as Command13 } from "commander";
|
|
42736
43286
|
var logger14, validateCommand;
|
|
42737
43287
|
var init_validate = __esm({
|
|
42738
43288
|
"src/commands/validate.ts"() {
|
|
42739
43289
|
"use strict";
|
|
42740
|
-
|
|
43290
|
+
init_dist();
|
|
42741
43291
|
init_exercises();
|
|
43292
|
+
init_courses();
|
|
42742
43293
|
init_http();
|
|
42743
43294
|
init_guards();
|
|
42744
43295
|
init_course_state();
|
|
@@ -42752,7 +43303,22 @@ var init_validate = __esm({
|
|
|
42752
43303
|
const activeCourse = await requireActiveCourse();
|
|
42753
43304
|
const driftWarning = await checkCourseDrift();
|
|
42754
43305
|
if (driftWarning) process.stderr.write(driftWarning + "\n");
|
|
42755
|
-
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
|
+
}
|
|
42756
43322
|
if (!lessonId) {
|
|
42757
43323
|
if (opts.json) jsonError("no_active_lesson", { message: "Nenhuma li\xE7\xE3o ativa encontrada" });
|
|
42758
43324
|
error("Nenhuma li\xE7\xE3o ativa encontrada. Rode: tostudy start ou tostudy next");
|
|
@@ -42773,7 +43339,7 @@ var init_validate = __esm({
|
|
|
42773
43339
|
error("Forne\xE7a um arquivo ou use --stdin.\n\nExemplo: tostudy validate resposta.md");
|
|
42774
43340
|
}
|
|
42775
43341
|
if (file2 && activeCourse.courseTags?.length) {
|
|
42776
|
-
const ext =
|
|
43342
|
+
const ext = path14.extname(file2).toLowerCase();
|
|
42777
43343
|
const LANG_EXTENSIONS = {
|
|
42778
43344
|
".html": ["html", "html5"],
|
|
42779
43345
|
".css": ["css"],
|
|
@@ -42808,8 +43374,6 @@ var init_validate = __esm({
|
|
|
42808
43374
|
}
|
|
42809
43375
|
}
|
|
42810
43376
|
}
|
|
42811
|
-
const data = createHttpProvider(session.apiUrl, session.token);
|
|
42812
|
-
const deps = { data, logger: logger14 };
|
|
42813
43377
|
const result = await validateSolution(
|
|
42814
43378
|
{
|
|
42815
43379
|
lessonId,
|
|
@@ -42826,11 +43390,17 @@ var init_validate = __esm({
|
|
|
42826
43390
|
}
|
|
42827
43391
|
process.exit(result.passed ? 0 : 1);
|
|
42828
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
|
+
}
|
|
42829
43399
|
if (isCourseArchivedError(err)) {
|
|
42830
43400
|
const friendly = getErrors().courseArchived;
|
|
42831
43401
|
if (opts.json) jsonError("course_archived", { message: friendly });
|
|
42832
|
-
|
|
42833
|
-
|
|
43402
|
+
else process.stderr.write(friendly);
|
|
43403
|
+
process.exit(1);
|
|
42834
43404
|
}
|
|
42835
43405
|
if (isInsufficientCreditsError(err)) {
|
|
42836
43406
|
const friendly = getErrors().insufficientCredits;
|
|
@@ -43187,7 +43757,7 @@ var logger15, defaultDeps4, initCommand;
|
|
|
43187
43757
|
var init_init = __esm({
|
|
43188
43758
|
"src/commands/init.ts"() {
|
|
43189
43759
|
"use strict";
|
|
43190
|
-
|
|
43760
|
+
init_dist();
|
|
43191
43761
|
init_courses();
|
|
43192
43762
|
init_http();
|
|
43193
43763
|
init_session_store();
|
|
@@ -43226,13 +43796,13 @@ var init_init = __esm({
|
|
|
43226
43796
|
|
|
43227
43797
|
// ../../packages/tostudy-core/src/workspace/setup-workspace.ts
|
|
43228
43798
|
import fs13 from "node:fs/promises";
|
|
43229
|
-
import
|
|
43799
|
+
import path15 from "node:path";
|
|
43230
43800
|
async function setupWorkspace(input2) {
|
|
43231
|
-
const workspacePath =
|
|
43801
|
+
const workspacePath = path15.join(input2.basePath, input2.courseSlug);
|
|
43232
43802
|
for (const dir of WORKSPACE_DIRS) {
|
|
43233
|
-
await fs13.mkdir(
|
|
43803
|
+
await fs13.mkdir(path15.join(workspacePath, dir), { recursive: true });
|
|
43234
43804
|
}
|
|
43235
|
-
const configPath =
|
|
43805
|
+
const configPath = path15.join(workspacePath, ".ana-config.json");
|
|
43236
43806
|
const config2 = {
|
|
43237
43807
|
courseId: input2.courseId,
|
|
43238
43808
|
courseSlug: input2.courseSlug,
|
|
@@ -43267,7 +43837,7 @@ async function setupWorkspace(input2) {
|
|
|
43267
43837
|
"tostudy vault sync # Sincronizar progresso",
|
|
43268
43838
|
"```"
|
|
43269
43839
|
].join("\n");
|
|
43270
|
-
await fs13.writeFile(
|
|
43840
|
+
await fs13.writeFile(path15.join(workspacePath, "README.md"), readme, "utf-8");
|
|
43271
43841
|
return { workspacePath, directories: WORKSPACE_DIRS, configPath };
|
|
43272
43842
|
}
|
|
43273
43843
|
var WORKSPACE_DIRS;
|
|
@@ -43369,7 +43939,7 @@ var init_templates = __esm({
|
|
|
43369
43939
|
|
|
43370
43940
|
// ../../packages/tostudy-core/src/workspace/extract-exercise.ts
|
|
43371
43941
|
import fs14 from "node:fs/promises";
|
|
43372
|
-
import
|
|
43942
|
+
import path16 from "node:path";
|
|
43373
43943
|
function padOrder(n) {
|
|
43374
43944
|
return String(n).padStart(2, "0");
|
|
43375
43945
|
}
|
|
@@ -43393,15 +43963,15 @@ async function extractExercise(input2) {
|
|
|
43393
43963
|
const { lessonData, exerciseTier, workspacePath } = input2;
|
|
43394
43964
|
const moduleDir = `${padOrder(lessonData.moduleOrder)}-${lessonData.moduleSlug}`;
|
|
43395
43965
|
const lessonDir = `${padOrder(lessonData.lessonOrder)}-${lessonData.lessonSlug}`;
|
|
43396
|
-
const exercisePath =
|
|
43966
|
+
const exercisePath = path16.join(workspacePath, "exercises", moduleDir, lessonDir);
|
|
43397
43967
|
await fs14.mkdir(exercisePath, { recursive: true });
|
|
43398
43968
|
const extractedFiles = [];
|
|
43399
43969
|
let hasStarterCode = false;
|
|
43400
43970
|
if (lessonData.sandpackConfig?.files) {
|
|
43401
43971
|
for (const [filePath, fileData] of Object.entries(lessonData.sandpackConfig.files)) {
|
|
43402
43972
|
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
43403
|
-
const fullPath =
|
|
43404
|
-
await fs14.mkdir(
|
|
43973
|
+
const fullPath = path16.join(exercisePath, cleanPath);
|
|
43974
|
+
await fs14.mkdir(path16.dirname(fullPath), { recursive: true });
|
|
43405
43975
|
await fs14.writeFile(fullPath, fileData.code, "utf-8");
|
|
43406
43976
|
extractedFiles.push(cleanPath);
|
|
43407
43977
|
hasStarterCode = true;
|
|
@@ -43410,13 +43980,13 @@ async function extractExercise(input2) {
|
|
|
43410
43980
|
const tierData = getTierData(lessonData.structuredData, exerciseTier);
|
|
43411
43981
|
const tierCode = tierData?.code;
|
|
43412
43982
|
if (tierCode) {
|
|
43413
|
-
await fs14.writeFile(
|
|
43983
|
+
await fs14.writeFile(path16.join(exercisePath, "exercise.js"), tierCode, "utf-8");
|
|
43414
43984
|
extractedFiles.push("exercise.js");
|
|
43415
43985
|
hasStarterCode = true;
|
|
43416
43986
|
} else {
|
|
43417
43987
|
const starter = getStarterCode(lessonData.structuredData);
|
|
43418
43988
|
if (starter) {
|
|
43419
|
-
await fs14.writeFile(
|
|
43989
|
+
await fs14.writeFile(path16.join(exercisePath, "exercise.js"), starter, "utf-8");
|
|
43420
43990
|
extractedFiles.push("exercise.js");
|
|
43421
43991
|
hasStarterCode = true;
|
|
43422
43992
|
}
|
|
@@ -43435,7 +44005,7 @@ async function extractExercise(input2) {
|
|
|
43435
44005
|
}
|
|
43436
44006
|
};
|
|
43437
44007
|
await fs14.writeFile(
|
|
43438
|
-
|
|
44008
|
+
path16.join(exercisePath, "package.json"),
|
|
43439
44009
|
JSON.stringify(pkgJson, null, 2),
|
|
43440
44010
|
"utf-8"
|
|
43441
44011
|
);
|
|
@@ -43447,19 +44017,19 @@ async function extractExercise(input2) {
|
|
|
43447
44017
|
);
|
|
43448
44018
|
for (const [configFile, configContent] of Object.entries(scaffold.configs)) {
|
|
43449
44019
|
if (!sandpackFileNames.has(configFile)) {
|
|
43450
|
-
await fs14.writeFile(
|
|
44020
|
+
await fs14.writeFile(path16.join(exercisePath, configFile), configContent, "utf-8");
|
|
43451
44021
|
extractedFiles.push(configFile);
|
|
43452
44022
|
}
|
|
43453
44023
|
}
|
|
43454
44024
|
const setupSh = `#!/bin/sh
|
|
43455
44025
|
${scaffold.setupScript}
|
|
43456
44026
|
`;
|
|
43457
|
-
await fs14.writeFile(
|
|
44027
|
+
await fs14.writeFile(path16.join(exercisePath, "setup.sh"), setupSh, "utf-8");
|
|
43458
44028
|
extractedFiles.push("setup.sh");
|
|
43459
44029
|
}
|
|
43460
44030
|
}
|
|
43461
44031
|
const readme = generateReadme(lessonData, exerciseTier);
|
|
43462
|
-
const readmePath =
|
|
44032
|
+
const readmePath = path16.join(exercisePath, "README.md");
|
|
43463
44033
|
await fs14.writeFile(readmePath, readme, "utf-8");
|
|
43464
44034
|
extractedFiles.push("README.md");
|
|
43465
44035
|
return {
|
|
@@ -43532,14 +44102,14 @@ var init_workspace = __esm({
|
|
|
43532
44102
|
|
|
43533
44103
|
// src/commands/workspace.ts
|
|
43534
44104
|
import { Command as Command16 } from "commander";
|
|
43535
|
-
import
|
|
43536
|
-
import
|
|
44105
|
+
import path17 from "node:path";
|
|
44106
|
+
import os9 from "node:os";
|
|
43537
44107
|
import fs15 from "node:fs/promises";
|
|
43538
44108
|
var logger16, workspaceCommand;
|
|
43539
44109
|
var init_workspace2 = __esm({
|
|
43540
44110
|
"src/commands/workspace.ts"() {
|
|
43541
44111
|
"use strict";
|
|
43542
|
-
|
|
44112
|
+
init_dist();
|
|
43543
44113
|
init_workspace();
|
|
43544
44114
|
init_guards();
|
|
43545
44115
|
init_course_state();
|
|
@@ -43558,13 +44128,13 @@ var init_workspace2 = __esm({
|
|
|
43558
44128
|
let directories;
|
|
43559
44129
|
if (!opts.path && cwdIsWorkspace) {
|
|
43560
44130
|
const resolvedCwd = await resolveCwdWorkspacePath(process.cwd());
|
|
43561
|
-
workspacePath = resolvedCwd ??
|
|
44131
|
+
workspacePath = resolvedCwd ?? path17.join(process.cwd(), ".tostudy");
|
|
43562
44132
|
await fs15.mkdir(workspacePath, { recursive: true });
|
|
43563
44133
|
directories = ["exercises", "generated", "notes", "diagrams"];
|
|
43564
44134
|
for (const dir of directories) {
|
|
43565
|
-
await fs15.mkdir(
|
|
44135
|
+
await fs15.mkdir(path17.join(workspacePath, dir), { recursive: true });
|
|
43566
44136
|
}
|
|
43567
|
-
const configPath =
|
|
44137
|
+
const configPath = path17.join(workspacePath, ".ana-config.json");
|
|
43568
44138
|
await fs15.writeFile(
|
|
43569
44139
|
configPath,
|
|
43570
44140
|
JSON.stringify(
|
|
@@ -43583,7 +44153,7 @@ var init_workspace2 = __esm({
|
|
|
43583
44153
|
"utf-8"
|
|
43584
44154
|
);
|
|
43585
44155
|
} else {
|
|
43586
|
-
const basePath = opts.path ??
|
|
44156
|
+
const basePath = opts.path ?? path17.join(os9.homedir(), "study");
|
|
43587
44157
|
const result2 = await setupWorkspace({
|
|
43588
44158
|
courseId: activeCourse.courseId,
|
|
43589
44159
|
courseSlug: courseSlug(activeCourse.courseTitle),
|
|
@@ -43617,7 +44187,7 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43617
44187
|
process.exit(1);
|
|
43618
44188
|
}
|
|
43619
44189
|
});
|
|
43620
|
-
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) => {
|
|
43621
44191
|
try {
|
|
43622
44192
|
const activeCourse = await requireActiveCourse();
|
|
43623
44193
|
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
@@ -43634,22 +44204,22 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43634
44204
|
const workspacePath = ws.workspacePath;
|
|
43635
44205
|
let configData = null;
|
|
43636
44206
|
try {
|
|
43637
|
-
const raw = await fs15.readFile(
|
|
44207
|
+
const raw = await fs15.readFile(path17.join(workspacePath, ".ana-config.json"), "utf-8");
|
|
43638
44208
|
configData = JSON.parse(raw);
|
|
43639
44209
|
} catch {
|
|
43640
44210
|
configData = null;
|
|
43641
44211
|
}
|
|
43642
|
-
const exercisesDir =
|
|
44212
|
+
const exercisesDir = path17.join(workspacePath, "exercises");
|
|
43643
44213
|
let exerciseCount = 0;
|
|
43644
44214
|
try {
|
|
43645
44215
|
const moduleDirs = await fs15.readdir(exercisesDir);
|
|
43646
44216
|
for (const modDir of moduleDirs) {
|
|
43647
|
-
const modPath =
|
|
44217
|
+
const modPath = path17.join(exercisesDir, modDir);
|
|
43648
44218
|
const stat = await fs15.stat(modPath);
|
|
43649
44219
|
if (stat.isDirectory()) {
|
|
43650
44220
|
const lessonDirs = await fs15.readdir(modPath);
|
|
43651
44221
|
for (const lessonDir of lessonDirs) {
|
|
43652
|
-
const lessonPath =
|
|
44222
|
+
const lessonPath = path17.join(modPath, lessonDir);
|
|
43653
44223
|
const lstat = await fs15.stat(lessonPath);
|
|
43654
44224
|
if (lstat.isDirectory()) exerciseCount++;
|
|
43655
44225
|
}
|
|
@@ -43657,14 +44227,14 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43657
44227
|
}
|
|
43658
44228
|
} catch {
|
|
43659
44229
|
}
|
|
43660
|
-
const generatedDir =
|
|
44230
|
+
const generatedDir = path17.join(workspacePath, "generated");
|
|
43661
44231
|
let artifactCount = 0;
|
|
43662
44232
|
try {
|
|
43663
44233
|
const files = await fs15.readdir(generatedDir);
|
|
43664
44234
|
artifactCount = files.length;
|
|
43665
44235
|
} catch {
|
|
43666
44236
|
}
|
|
43667
|
-
const diagramsDir =
|
|
44237
|
+
const diagramsDir = path17.join(workspacePath, "diagrams");
|
|
43668
44238
|
let diagramCount = 0;
|
|
43669
44239
|
try {
|
|
43670
44240
|
const files = await fs15.readdir(diagramsDir);
|
|
@@ -43716,14 +44286,14 @@ Pr\xF3ximo passo: tostudy export
|
|
|
43716
44286
|
|
|
43717
44287
|
// src/commands/export.ts
|
|
43718
44288
|
import { Command as Command17 } from "commander";
|
|
43719
|
-
import
|
|
43720
|
-
import
|
|
44289
|
+
import path18 from "node:path";
|
|
44290
|
+
import os10 from "node:os";
|
|
43721
44291
|
import fs16 from "node:fs/promises";
|
|
43722
44292
|
var logger17, exportCommand;
|
|
43723
44293
|
var init_export = __esm({
|
|
43724
44294
|
"src/commands/export.ts"() {
|
|
43725
44295
|
"use strict";
|
|
43726
|
-
|
|
44296
|
+
init_dist();
|
|
43727
44297
|
init_workspace();
|
|
43728
44298
|
init_http();
|
|
43729
44299
|
init_guards();
|
|
@@ -43731,7 +44301,7 @@ var init_export = __esm({
|
|
|
43731
44301
|
init_resolve();
|
|
43732
44302
|
init_errors();
|
|
43733
44303
|
logger17 = createLogger("cli:export");
|
|
43734
|
-
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) => {
|
|
43735
44305
|
try {
|
|
43736
44306
|
const session = await requireSession();
|
|
43737
44307
|
const activeCourse = await requireActiveCourse();
|
|
@@ -43749,7 +44319,7 @@ var init_export = __esm({
|
|
|
43749
44319
|
opts.path
|
|
43750
44320
|
);
|
|
43751
44321
|
if (ws.found && ws.source === "cwd" && ws.workspacePath) {
|
|
43752
|
-
const configPath =
|
|
44322
|
+
const configPath = path18.join(ws.workspacePath, ".ana-config.json");
|
|
43753
44323
|
let hasConfig = false;
|
|
43754
44324
|
try {
|
|
43755
44325
|
await fs16.access(configPath);
|
|
@@ -43761,7 +44331,7 @@ var init_export = __esm({
|
|
|
43761
44331
|
logger17.info("Auto-initializing workspace", { workspacePath: ws.workspacePath });
|
|
43762
44332
|
await fs16.mkdir(ws.workspacePath, { recursive: true });
|
|
43763
44333
|
for (const dir of ["exercises", "generated", "notes", "diagrams"]) {
|
|
43764
|
-
await fs16.mkdir(
|
|
44334
|
+
await fs16.mkdir(path18.join(ws.workspacePath, dir), { recursive: true });
|
|
43765
44335
|
}
|
|
43766
44336
|
await fs16.writeFile(
|
|
43767
44337
|
configPath,
|
|
@@ -43781,7 +44351,7 @@ var init_export = __esm({
|
|
|
43781
44351
|
"utf-8"
|
|
43782
44352
|
);
|
|
43783
44353
|
await setCourseWorkspacePath(activeCourse.courseId, ws.workspacePath);
|
|
43784
|
-
const isNamespaced = ws.workspacePath ===
|
|
44354
|
+
const isNamespaced = ws.workspacePath === path18.join(process.cwd(), ".tostudy");
|
|
43785
44355
|
process.stderr.write(
|
|
43786
44356
|
isNamespaced ? `\u2728 Workspace inicializado em .tostudy/ (isolado do projeto).
|
|
43787
44357
|
` : `\u2728 Workspace inicializado nesta pasta.
|
|
@@ -43832,19 +44402,19 @@ ${result.files.map((f) => ` \u{1F4C4} ${f}`).join("\n")}
|
|
|
43832
44402
|
// src/commands/open.ts
|
|
43833
44403
|
import { Command as Command18 } from "commander";
|
|
43834
44404
|
import { execFile as execFile3 } from "node:child_process";
|
|
43835
|
-
import
|
|
43836
|
-
import
|
|
44405
|
+
import path19 from "node:path";
|
|
44406
|
+
import os11 from "node:os";
|
|
43837
44407
|
var logger18, openCommand;
|
|
43838
44408
|
var init_open = __esm({
|
|
43839
44409
|
"src/commands/open.ts"() {
|
|
43840
44410
|
"use strict";
|
|
43841
|
-
|
|
44411
|
+
init_dist();
|
|
43842
44412
|
init_guards();
|
|
43843
44413
|
init_course_state();
|
|
43844
44414
|
init_resolve();
|
|
43845
44415
|
init_errors();
|
|
43846
44416
|
logger18 = createLogger("cli:open");
|
|
43847
|
-
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) => {
|
|
43848
44418
|
try {
|
|
43849
44419
|
const activeCourse = await requireActiveCourse();
|
|
43850
44420
|
const onboardingState = await getCourseOnboardingState(activeCourse.courseId);
|
|
@@ -43898,14 +44468,14 @@ var init_types2 = __esm({
|
|
|
43898
44468
|
|
|
43899
44469
|
// ../../packages/tostudy-core/src/vault/write-vault.ts
|
|
43900
44470
|
import fs17 from "node:fs/promises";
|
|
43901
|
-
import
|
|
44471
|
+
import path20 from "node:path";
|
|
43902
44472
|
async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
|
|
43903
44473
|
for (const file2 of files) {
|
|
43904
|
-
const fullPath =
|
|
43905
|
-
await fs17.mkdir(
|
|
44474
|
+
const fullPath = path20.join(outputPath, file2.relativePath);
|
|
44475
|
+
await fs17.mkdir(path20.dirname(fullPath), { recursive: true });
|
|
43906
44476
|
await fs17.writeFile(fullPath, file2.content, "utf-8");
|
|
43907
44477
|
}
|
|
43908
|
-
const vaultPath =
|
|
44478
|
+
const vaultPath = path20.join(outputPath, courseSlug2);
|
|
43909
44479
|
const marker = {
|
|
43910
44480
|
courseId,
|
|
43911
44481
|
courseSlug: courseSlug2,
|
|
@@ -43914,7 +44484,7 @@ async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
|
|
|
43914
44484
|
};
|
|
43915
44485
|
await fs17.mkdir(vaultPath, { recursive: true });
|
|
43916
44486
|
await fs17.writeFile(
|
|
43917
|
-
|
|
44487
|
+
path20.join(vaultPath, VAULT_MARKER_FILENAME),
|
|
43918
44488
|
JSON.stringify(marker, null, 2),
|
|
43919
44489
|
"utf-8"
|
|
43920
44490
|
);
|
|
@@ -43939,14 +44509,14 @@ var init_vault = __esm({
|
|
|
43939
44509
|
|
|
43940
44510
|
// src/commands/vault.ts
|
|
43941
44511
|
import { Command as Command19 } from "commander";
|
|
43942
|
-
import
|
|
43943
|
-
import
|
|
44512
|
+
import path21 from "node:path";
|
|
44513
|
+
import os12 from "node:os";
|
|
43944
44514
|
import fs18 from "node:fs/promises";
|
|
43945
44515
|
var logger19, vaultCommand;
|
|
43946
44516
|
var init_vault2 = __esm({
|
|
43947
44517
|
"src/commands/vault.ts"() {
|
|
43948
44518
|
"use strict";
|
|
43949
|
-
|
|
44519
|
+
init_dist();
|
|
43950
44520
|
init_vault();
|
|
43951
44521
|
init_courses();
|
|
43952
44522
|
init_http();
|
|
@@ -43956,7 +44526,7 @@ var init_vault2 = __esm({
|
|
|
43956
44526
|
init_errors();
|
|
43957
44527
|
logger19 = createLogger("cli:vault");
|
|
43958
44528
|
vaultCommand = new Command19("vault").description("Gerenciar vault Obsidian do curso");
|
|
43959
|
-
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) => {
|
|
43960
44530
|
try {
|
|
43961
44531
|
const session = await requireSession();
|
|
43962
44532
|
const activeCourse = await requireActiveCourse();
|
|
@@ -44038,7 +44608,7 @@ Para visualizar:
|
|
|
44038
44608
|
process.exit(1);
|
|
44039
44609
|
}
|
|
44040
44610
|
});
|
|
44041
|
-
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) => {
|
|
44042
44612
|
try {
|
|
44043
44613
|
const session = await requireSession();
|
|
44044
44614
|
const activeCourse = await requireActiveCourse();
|
|
@@ -44064,7 +44634,7 @@ Para visualizar:
|
|
|
44064
44634
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
44065
44635
|
const deps = { data, logger: logger19 };
|
|
44066
44636
|
const progress3 = await getProgress({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
44067
|
-
const markerPath =
|
|
44637
|
+
const markerPath = path21.join(vaultPath, ".ana-vault.json");
|
|
44068
44638
|
const markerRaw = await fs18.readFile(markerPath, "utf-8");
|
|
44069
44639
|
const marker = JSON.parse(markerRaw);
|
|
44070
44640
|
marker.lastSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -44074,7 +44644,7 @@ Para visualizar:
|
|
|
44074
44644
|
currentLesson: progress3.currentLesson.title
|
|
44075
44645
|
};
|
|
44076
44646
|
await fs18.writeFile(markerPath, JSON.stringify(marker, null, 2), "utf-8");
|
|
44077
|
-
const courseIndexPath =
|
|
44647
|
+
const courseIndexPath = path21.join(vaultPath, slug, "index.md");
|
|
44078
44648
|
try {
|
|
44079
44649
|
let indexContent = await fs18.readFile(courseIndexPath, "utf-8");
|
|
44080
44650
|
indexContent = indexContent.replace(/\n---\n\n> 📊 Progresso:.*\n/g, "");
|
|
@@ -44200,7 +44770,7 @@ var logger20, syncCommand;
|
|
|
44200
44770
|
var init_sync = __esm({
|
|
44201
44771
|
"src/commands/sync.ts"() {
|
|
44202
44772
|
"use strict";
|
|
44203
|
-
|
|
44773
|
+
init_dist();
|
|
44204
44774
|
init_guards();
|
|
44205
44775
|
init_formatter();
|
|
44206
44776
|
init_instruction_pipeline();
|
|
@@ -44257,7 +44827,7 @@ var logger21, briefCommand;
|
|
|
44257
44827
|
var init_brief = __esm({
|
|
44258
44828
|
"src/commands/brief.ts"() {
|
|
44259
44829
|
"use strict";
|
|
44260
|
-
|
|
44830
|
+
init_dist();
|
|
44261
44831
|
init_guards();
|
|
44262
44832
|
init_cache();
|
|
44263
44833
|
init_api();
|
|
@@ -44309,7 +44879,7 @@ var logger22, briefCreateCommand;
|
|
|
44309
44879
|
var init_brief_create = __esm({
|
|
44310
44880
|
"src/commands/brief-create.ts"() {
|
|
44311
44881
|
"use strict";
|
|
44312
|
-
|
|
44882
|
+
init_dist();
|
|
44313
44883
|
init_guards();
|
|
44314
44884
|
init_bootstrap();
|
|
44315
44885
|
init_api();
|
|
@@ -44387,15 +44957,15 @@ var init_brief_open = __esm({
|
|
|
44387
44957
|
|
|
44388
44958
|
// src/sessions/storage.ts
|
|
44389
44959
|
import fs19 from "node:fs";
|
|
44390
|
-
import
|
|
44960
|
+
import path22 from "node:path";
|
|
44391
44961
|
function sessionsDir(workspacePath) {
|
|
44392
|
-
return
|
|
44962
|
+
return path22.join(workspacePath, ".tostudy", "sessions");
|
|
44393
44963
|
}
|
|
44394
44964
|
async function saveModuleSummary(workspacePath, input2) {
|
|
44395
44965
|
const dir = sessionsDir(workspacePath);
|
|
44396
44966
|
fs19.mkdirSync(dir, { recursive: true });
|
|
44397
44967
|
const filename = `module-${input2.moduleId}-summary.md`;
|
|
44398
|
-
const filePath =
|
|
44968
|
+
const filePath = path22.join(dir, filename);
|
|
44399
44969
|
const header = [
|
|
44400
44970
|
"---",
|
|
44401
44971
|
`moduleId: ${input2.moduleId}`,
|
|
@@ -44414,7 +44984,7 @@ async function loadSessionContext(workspacePath) {
|
|
|
44414
44984
|
const files = fs19.readdirSync(dir).filter((f) => f.startsWith("module-") && f.endsWith("-summary.md")).sort();
|
|
44415
44985
|
const summaries = [];
|
|
44416
44986
|
for (const file2 of files) {
|
|
44417
|
-
const content = fs19.readFileSync(
|
|
44987
|
+
const content = fs19.readFileSync(path22.join(dir, file2), "utf-8");
|
|
44418
44988
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
44419
44989
|
if (!frontmatterMatch) continue;
|
|
44420
44990
|
const meta3 = frontmatterMatch[1];
|
|
@@ -44430,7 +45000,7 @@ var logger23;
|
|
|
44430
45000
|
var init_storage = __esm({
|
|
44431
45001
|
"src/sessions/storage.ts"() {
|
|
44432
45002
|
"use strict";
|
|
44433
|
-
|
|
45003
|
+
init_dist();
|
|
44434
45004
|
logger23 = createLogger("cli:sessions");
|
|
44435
45005
|
}
|
|
44436
45006
|
});
|
|
@@ -44442,7 +45012,7 @@ var logger24, compactCommand;
|
|
|
44442
45012
|
var init_compact = __esm({
|
|
44443
45013
|
"src/commands/compact.ts"() {
|
|
44444
45014
|
"use strict";
|
|
44445
|
-
|
|
45015
|
+
init_dist();
|
|
44446
45016
|
init_guards();
|
|
44447
45017
|
init_workspace_state();
|
|
44448
45018
|
init_storage();
|
|
@@ -44491,7 +45061,7 @@ var logger25, contextCommand;
|
|
|
44491
45061
|
var init_context = __esm({
|
|
44492
45062
|
"src/commands/context.ts"() {
|
|
44493
45063
|
"use strict";
|
|
44494
|
-
|
|
45064
|
+
init_dist();
|
|
44495
45065
|
init_workspace_state();
|
|
44496
45066
|
init_storage();
|
|
44497
45067
|
init_formatter();
|
|
@@ -44545,21 +45115,125 @@ var init_context = __esm({
|
|
|
44545
45115
|
}
|
|
44546
45116
|
});
|
|
44547
45117
|
|
|
44548
|
-
// src/commands/
|
|
45118
|
+
// src/commands/memory.ts
|
|
44549
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";
|
|
44550
45224
|
function isExerciseLevel2(value) {
|
|
44551
45225
|
return ALL_LEVELS.includes(value);
|
|
44552
45226
|
}
|
|
44553
|
-
var
|
|
45227
|
+
var logger28, ALL_LEVELS, LEVEL_LABELS2, levelCommand;
|
|
44554
45228
|
var init_level = __esm({
|
|
44555
45229
|
"src/commands/level.ts"() {
|
|
44556
45230
|
"use strict";
|
|
44557
|
-
|
|
45231
|
+
init_dist();
|
|
44558
45232
|
init_http();
|
|
44559
45233
|
init_exercises();
|
|
44560
45234
|
init_guards();
|
|
44561
45235
|
init_formatter();
|
|
44562
|
-
|
|
45236
|
+
logger28 = createLogger("cli:level");
|
|
44563
45237
|
ALL_LEVELS = ["L0", "L1", "L2", "L3", "L4"];
|
|
44564
45238
|
LEVEL_LABELS2 = {
|
|
44565
45239
|
L0: "Pr\xE9-check (perguntas conceituais)",
|
|
@@ -44568,12 +45242,12 @@ var init_level = __esm({
|
|
|
44568
45242
|
L3: "Guiado (passo a passo + checkpoints)",
|
|
44569
45243
|
L4: "Desafio livre (folha em branco)"
|
|
44570
45244
|
};
|
|
44571
|
-
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) => {
|
|
44572
45246
|
try {
|
|
44573
45247
|
const session = await requireSession();
|
|
44574
45248
|
const activeCourse = await requireActiveCourse();
|
|
44575
45249
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
44576
|
-
const deps = { data, logger:
|
|
45250
|
+
const deps = { data, logger: logger28 };
|
|
44577
45251
|
if (!rawLevel) {
|
|
44578
45252
|
const levels = await getEnrollmentLevels({ enrollmentId: activeCourse.enrollmentId }, deps);
|
|
44579
45253
|
if (opts.json) {
|
|
@@ -44631,18 +45305,18 @@ var init_level = __esm({
|
|
|
44631
45305
|
});
|
|
44632
45306
|
|
|
44633
45307
|
// src/commands/theory.ts
|
|
44634
|
-
import { Command as
|
|
44635
|
-
var
|
|
45308
|
+
import { Command as Command30 } from "commander";
|
|
45309
|
+
var logger29, EXERCISE_LEVELS2, theoryCommand;
|
|
44636
45310
|
var init_theory = __esm({
|
|
44637
45311
|
"src/commands/theory.ts"() {
|
|
44638
45312
|
"use strict";
|
|
44639
|
-
|
|
45313
|
+
init_dist();
|
|
44640
45314
|
init_guards();
|
|
44641
45315
|
init_formatter();
|
|
44642
45316
|
init_errors();
|
|
44643
|
-
|
|
45317
|
+
logger29 = createLogger("cli:theory");
|
|
44644
45318
|
EXERCISE_LEVELS2 = ["L0", "L1", "L2", "L3", "L4"];
|
|
44645
|
-
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) => {
|
|
44646
45320
|
try {
|
|
44647
45321
|
const session = await requireSession();
|
|
44648
45322
|
const active = await requireActiveCourse();
|
|
@@ -44679,7 +45353,7 @@ var init_theory = __esm({
|
|
|
44679
45353
|
currentLevel = levels.currentLevel;
|
|
44680
45354
|
}
|
|
44681
45355
|
const requestUrl = `${session.apiUrl}/api/cli/exercises/more-theory`;
|
|
44682
|
-
|
|
45356
|
+
logger29.debug("Requesting more theory", { lessonId, currentLevel });
|
|
44683
45357
|
const res = await fetch(requestUrl, {
|
|
44684
45358
|
method: "POST",
|
|
44685
45359
|
headers: {
|
|
@@ -44997,7 +45671,7 @@ var init_resolve_enrollment = __esm({
|
|
|
44997
45671
|
});
|
|
44998
45672
|
|
|
44999
45673
|
// src/commands/export-grades.ts
|
|
45000
|
-
import { Command as
|
|
45674
|
+
import { Command as Command31 } from "commander";
|
|
45001
45675
|
function isFormat(value) {
|
|
45002
45676
|
return SUPPORTED_FORMATS.includes(value);
|
|
45003
45677
|
}
|
|
@@ -45084,15 +45758,15 @@ async function runExportGrades(opts, deps = defaultDeps5) {
|
|
|
45084
45758
|
if (!rendered.endsWith("\n")) rendered += "\n";
|
|
45085
45759
|
deps.stdoutWrite(rendered);
|
|
45086
45760
|
}
|
|
45087
|
-
var
|
|
45761
|
+
var logger30, SUPPORTED_FORMATS, defaultDeps5, exportGradesCommand;
|
|
45088
45762
|
var init_export_grades = __esm({
|
|
45089
45763
|
"src/commands/export-grades.ts"() {
|
|
45090
45764
|
"use strict";
|
|
45091
|
-
|
|
45765
|
+
init_dist();
|
|
45092
45766
|
init_guards();
|
|
45093
45767
|
init_grades();
|
|
45094
45768
|
init_resolve_enrollment();
|
|
45095
|
-
|
|
45769
|
+
logger30 = createLogger("cli:export-grades");
|
|
45096
45770
|
SUPPORTED_FORMATS = ["json", "csv", "md"];
|
|
45097
45771
|
defaultDeps5 = {
|
|
45098
45772
|
requireSession,
|
|
@@ -45102,10 +45776,10 @@ var init_export_grades = __esm({
|
|
|
45102
45776
|
stderrWrite: (message) => process.stderr.write(message),
|
|
45103
45777
|
// process.exit is typed as `never` — wrap so the cast is local to one line.
|
|
45104
45778
|
exit: (code) => process.exit(code),
|
|
45105
|
-
logger:
|
|
45779
|
+
logger: logger30,
|
|
45106
45780
|
resolveBySlug: resolveEnrollmentBySlug
|
|
45107
45781
|
};
|
|
45108
|
-
exportGradesCommand = new
|
|
45782
|
+
exportGradesCommand = new Command31("export-grades").description("Exporta o hist\xF3rico de valida\xE7\xF5es (notas) do curso ativo").option(
|
|
45109
45783
|
"--course <slug>",
|
|
45110
45784
|
"Slug do curso (gerado a partir do t\xEDtulo). Sem a flag, exporta o curso ativo."
|
|
45111
45785
|
).option("--format <json|csv|md>", "Formato de sa\xEDda (default: json)", "json").addHelpText(
|
|
@@ -45130,7 +45804,7 @@ C\xF3digos de sa\xEDda:
|
|
|
45130
45804
|
});
|
|
45131
45805
|
|
|
45132
45806
|
// src/commands/grades.ts
|
|
45133
|
-
import { Command as
|
|
45807
|
+
import { Command as Command32 } from "commander";
|
|
45134
45808
|
async function fetchAttempts(session, enrollmentId, deps) {
|
|
45135
45809
|
const url2 = `${session.apiUrl}/api/cli/validations/by-enrollment?enrollmentId=${encodeURIComponent(
|
|
45136
45810
|
enrollmentId
|
|
@@ -45271,29 +45945,29 @@ async function runGrades(opts, deps = defaultDeps6) {
|
|
|
45271
45945
|
);
|
|
45272
45946
|
deps.stdoutWrite(formatGradesAllEnrollmentsTable(summaries) + "\n");
|
|
45273
45947
|
}
|
|
45274
|
-
var
|
|
45948
|
+
var logger31, defaultDeps6, gradesCommand;
|
|
45275
45949
|
var init_grades2 = __esm({
|
|
45276
45950
|
"src/commands/grades.ts"() {
|
|
45277
45951
|
"use strict";
|
|
45278
|
-
|
|
45952
|
+
init_dist();
|
|
45279
45953
|
init_http();
|
|
45280
45954
|
init_courses();
|
|
45281
45955
|
init_guards();
|
|
45282
45956
|
init_grades();
|
|
45283
45957
|
init_resolve_enrollment();
|
|
45284
|
-
|
|
45958
|
+
logger31 = createLogger("cli:grades");
|
|
45285
45959
|
defaultDeps6 = {
|
|
45286
45960
|
requireSession,
|
|
45287
45961
|
fetch: globalThis.fetch.bind(globalThis),
|
|
45288
45962
|
stdoutWrite: (message) => process.stdout.write(message),
|
|
45289
45963
|
stderrWrite: (message) => process.stderr.write(message),
|
|
45290
45964
|
exit: (code) => process.exit(code),
|
|
45291
|
-
logger:
|
|
45965
|
+
logger: logger31,
|
|
45292
45966
|
resolveBySlug: resolveEnrollmentBySlug,
|
|
45293
45967
|
buildDataProvider: createHttpProvider,
|
|
45294
45968
|
listCoursesFn: listCourses
|
|
45295
45969
|
};
|
|
45296
|
-
gradesCommand = new
|
|
45970
|
+
gradesCommand = new Command32("grades").description("Mostra um resumo das notas (todas as matr\xEDculas ou um curso espec\xEDfico)").option(
|
|
45297
45971
|
"--course <slug>",
|
|
45298
45972
|
"Slug do curso (gerado a partir do t\xEDtulo). Sem a flag, lista todos os cursos."
|
|
45299
45973
|
).addHelpText(
|
|
@@ -45317,7 +45991,7 @@ C\xF3digos de sa\xEDda:
|
|
|
45317
45991
|
});
|
|
45318
45992
|
|
|
45319
45993
|
// src/commands/review.ts
|
|
45320
|
-
import { Command as
|
|
45994
|
+
import { Command as Command33 } from "commander";
|
|
45321
45995
|
import { createInterface } from "node:readline/promises";
|
|
45322
45996
|
import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
|
|
45323
45997
|
async function defaultPromptLessonChoice(lessonIds) {
|
|
@@ -45453,26 +46127,26 @@ async function runReview(slug, opts, deps = defaultDeps7) {
|
|
|
45453
46127
|
}) + "\n"
|
|
45454
46128
|
);
|
|
45455
46129
|
}
|
|
45456
|
-
var
|
|
46130
|
+
var logger32, defaultDeps7, reviewCommand;
|
|
45457
46131
|
var init_review2 = __esm({
|
|
45458
46132
|
"src/commands/review.ts"() {
|
|
45459
46133
|
"use strict";
|
|
45460
|
-
|
|
46134
|
+
init_dist();
|
|
45461
46135
|
init_guards();
|
|
45462
46136
|
init_grades();
|
|
45463
46137
|
init_resolve_enrollment();
|
|
45464
|
-
|
|
46138
|
+
logger32 = createLogger("cli:review");
|
|
45465
46139
|
defaultDeps7 = {
|
|
45466
46140
|
requireSession,
|
|
45467
46141
|
fetch: globalThis.fetch.bind(globalThis),
|
|
45468
46142
|
stdoutWrite: (message) => process.stdout.write(message),
|
|
45469
46143
|
stderrWrite: (message) => process.stderr.write(message),
|
|
45470
46144
|
exit: (code) => process.exit(code),
|
|
45471
|
-
logger:
|
|
46145
|
+
logger: logger32,
|
|
45472
46146
|
resolveBySlug: resolveEnrollmentBySlug,
|
|
45473
46147
|
promptLessonChoice: defaultPromptLessonChoice
|
|
45474
46148
|
};
|
|
45475
|
-
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(
|
|
45476
46150
|
"after",
|
|
45477
46151
|
`
|
|
45478
46152
|
Exemplos:
|
|
@@ -45501,9 +46175,9 @@ __export(cli_exports, {
|
|
|
45501
46175
|
CLI_VERSION: () => CLI_VERSION,
|
|
45502
46176
|
createProgram: () => createProgram
|
|
45503
46177
|
});
|
|
45504
|
-
import { Command as
|
|
46178
|
+
import { Command as Command34 } from "commander";
|
|
45505
46179
|
function createProgram() {
|
|
45506
|
-
const program2 = new
|
|
46180
|
+
const program2 = new Command34();
|
|
45507
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");
|
|
45508
46182
|
program2.addCommand(setupCommand);
|
|
45509
46183
|
program2.addCommand(doctorCommand);
|
|
@@ -45536,6 +46210,8 @@ function createProgram() {
|
|
|
45536
46210
|
program2.addCommand(vaultCommand);
|
|
45537
46211
|
program2.addCommand(compactCommand);
|
|
45538
46212
|
program2.addCommand(contextCommand);
|
|
46213
|
+
program2.addCommand(memoryCommand);
|
|
46214
|
+
program2.addCommand(insightCommand);
|
|
45539
46215
|
return program2;
|
|
45540
46216
|
}
|
|
45541
46217
|
var init_cli = __esm({
|
|
@@ -45567,6 +46243,8 @@ var init_cli = __esm({
|
|
|
45567
46243
|
init_brief_open();
|
|
45568
46244
|
init_compact();
|
|
45569
46245
|
init_context();
|
|
46246
|
+
init_memory();
|
|
46247
|
+
init_insight();
|
|
45570
46248
|
init_level();
|
|
45571
46249
|
init_theory();
|
|
45572
46250
|
init_export_grades();
|