@tostudy-ai/cli 0.16.0 → 0.16.1
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 +108 -30
- package/dist/cli.js.map +3 -3
- package/package.json +4 -4
- package/bin/cli.js +0 -6
- package/bin/tostudy.ts +0 -14
package/dist/cli.js
CHANGED
|
@@ -41,8 +41,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
41
41
|
mod
|
|
42
42
|
));
|
|
43
43
|
|
|
44
|
-
// ../../node_modules/@parisgroup-ai/logger/dist/sanitize-
|
|
44
|
+
// ../../node_modules/@parisgroup-ai/logger/dist/sanitize-4AyoT9ic.mjs
|
|
45
45
|
function isSensitiveKey(key) {
|
|
46
|
+
if (matchesSensitiveField(key)) return true;
|
|
47
|
+
return matchesPluralOfSensitiveField(key);
|
|
48
|
+
}
|
|
49
|
+
function matchesPluralOfSensitiveField(key) {
|
|
50
|
+
const lower = key.toLowerCase();
|
|
51
|
+
if (lower.endsWith("es") && matchesSensitiveField(key.slice(0, -2))) return true;
|
|
52
|
+
if (lower.endsWith("s") && matchesSensitiveField(key.slice(0, -1))) return true;
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function matchesSensitiveField(key) {
|
|
46
56
|
const lowerKey = key.toLowerCase();
|
|
47
57
|
return SENSITIVE_FIELDS.some((field) => {
|
|
48
58
|
const lowerField = field.toLowerCase();
|
|
@@ -106,7 +116,8 @@ function sanitizeRecord(obj, ctx) {
|
|
|
106
116
|
const sanitized = { ...obj };
|
|
107
117
|
for (const [key, value] of Object.entries(sanitized)) {
|
|
108
118
|
const isAdditionalKey = ctx.additionalSensitiveKeys?.some((k) => key.toLowerCase() === k.toLowerCase());
|
|
109
|
-
|
|
119
|
+
const pluralCountExemption = typeof value === "number" && !isAdditionalKey && !matchesSensitiveField(key) && matchesPluralOfSensitiveField(key);
|
|
120
|
+
if ((isSensitiveKey(key) || isAdditionalKey) && !pluralCountExemption) {
|
|
110
121
|
sanitized[key] = "[REDACTED]";
|
|
111
122
|
continue;
|
|
112
123
|
}
|
|
@@ -136,8 +147,8 @@ function sanitizeEntryData(obj, additionalSensitiveKeys, includeStack) {
|
|
|
136
147
|
});
|
|
137
148
|
}
|
|
138
149
|
var SENSITIVE_FIELDS;
|
|
139
|
-
var
|
|
140
|
-
"../../node_modules/@parisgroup-ai/logger/dist/sanitize-
|
|
150
|
+
var init_sanitize_4AyoT9ic = __esm({
|
|
151
|
+
"../../node_modules/@parisgroup-ai/logger/dist/sanitize-4AyoT9ic.mjs"() {
|
|
141
152
|
SENSITIVE_FIELDS = [
|
|
142
153
|
"password",
|
|
143
154
|
"senha",
|
|
@@ -268,7 +279,7 @@ var require_picocolors = __commonJS({
|
|
|
268
279
|
}
|
|
269
280
|
});
|
|
270
281
|
|
|
271
|
-
// ../../node_modules/@parisgroup-ai/logger/dist/logger.base-
|
|
282
|
+
// ../../node_modules/@parisgroup-ai/logger/dist/logger.base-DOZPgsDx.mjs
|
|
272
283
|
function formatJson(entry) {
|
|
273
284
|
const { timestamp, level, message, service, environment, context, data, error: error49 } = entry;
|
|
274
285
|
const output3 = {
|
|
@@ -327,6 +338,35 @@ function formatPretty(entry) {
|
|
|
327
338
|
}
|
|
328
339
|
return output3;
|
|
329
340
|
}
|
|
341
|
+
function filterStrings(value, safe, visited) {
|
|
342
|
+
if (typeof value === "string") return safe(value);
|
|
343
|
+
if (value === null || typeof value !== "object") return value;
|
|
344
|
+
if (visited.has(value)) return value;
|
|
345
|
+
visited.add(value);
|
|
346
|
+
if (Array.isArray(value)) return value.map((item) => filterStrings(item, safe, visited));
|
|
347
|
+
const proto = Object.getPrototypeOf(value);
|
|
348
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
349
|
+
const out = {};
|
|
350
|
+
for (const [key, item] of Object.entries(value)) out[key] = filterStrings(item, safe, visited);
|
|
351
|
+
return out;
|
|
352
|
+
}
|
|
353
|
+
function applyPiiFilterToEntry(entry, filter) {
|
|
354
|
+
const safe = (text) => {
|
|
355
|
+
try {
|
|
356
|
+
return filter(text);
|
|
357
|
+
} catch {
|
|
358
|
+
return "[PII_FILTER_ERROR]";
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
362
|
+
return {
|
|
363
|
+
...entry,
|
|
364
|
+
message: safe(entry.message),
|
|
365
|
+
context: filterStrings(entry.context, safe, visited),
|
|
366
|
+
data: entry.data ? filterStrings(entry.data, safe, visited) : entry.data,
|
|
367
|
+
error: entry.error ? filterStrings(entry.error, safe, visited) : entry.error
|
|
368
|
+
};
|
|
369
|
+
}
|
|
330
370
|
function extractErrorInfo(error49, includeStack, visited = /* @__PURE__ */ new WeakSet()) {
|
|
331
371
|
const info = {
|
|
332
372
|
name: error49.name,
|
|
@@ -343,9 +383,9 @@ function extractErrorInfo(error49, includeStack, visited = /* @__PURE__ */ new W
|
|
|
343
383
|
return info;
|
|
344
384
|
}
|
|
345
385
|
var import_picocolors, LOG_LEVELS, LEVEL_COLORS, LEVEL_WIDTH, BaseLogger;
|
|
346
|
-
var
|
|
347
|
-
"../../node_modules/@parisgroup-ai/logger/dist/logger.base-
|
|
348
|
-
|
|
386
|
+
var init_logger_base_DOZPgsDx = __esm({
|
|
387
|
+
"../../node_modules/@parisgroup-ai/logger/dist/logger.base-DOZPgsDx.mjs"() {
|
|
388
|
+
init_sanitize_4AyoT9ic();
|
|
349
389
|
import_picocolors = __toESM(require_picocolors(), 1);
|
|
350
390
|
LOG_LEVELS = {
|
|
351
391
|
trace: 0,
|
|
@@ -375,6 +415,7 @@ var init_logger_base_MYys2STJ = __esm({
|
|
|
375
415
|
shouldSanitize;
|
|
376
416
|
sensitiveFields;
|
|
377
417
|
includeCaller;
|
|
418
|
+
piiFilter;
|
|
378
419
|
constructor(options, defaults) {
|
|
379
420
|
this.level = options.level ?? defaults.level;
|
|
380
421
|
this.format = options.format ?? defaults.format;
|
|
@@ -386,6 +427,7 @@ var init_logger_base_MYys2STJ = __esm({
|
|
|
386
427
|
this.shouldSanitize = options.sanitize ?? true;
|
|
387
428
|
this.sensitiveFields = options.sensitiveFields;
|
|
388
429
|
this.includeCaller = options.includeCaller ?? "errors";
|
|
430
|
+
this.piiFilter = options.piiFilter;
|
|
389
431
|
}
|
|
390
432
|
/**
|
|
391
433
|
* Get caller information for error logging (Node.js only).
|
|
@@ -401,10 +443,11 @@ var init_logger_base_MYys2STJ = __esm({
|
|
|
401
443
|
return LOG_LEVELS[level] >= LOG_LEVELS[this.level];
|
|
402
444
|
}
|
|
403
445
|
buildEntry(level, message, data, error49) {
|
|
404
|
-
const
|
|
446
|
+
const merged = {
|
|
405
447
|
...this.getLogContext() ?? {},
|
|
406
448
|
...this.additionalContext
|
|
407
449
|
};
|
|
450
|
+
const context = this.shouldSanitize ? sanitizeEntryData(merged, this.sensitiveFields, !this.isProd()) : merged;
|
|
408
451
|
if (this.module) context.module = this.module;
|
|
409
452
|
if (this.includeCaller === true || this.includeCaller === "errors" && (level === "error" || level === "fatal")) {
|
|
410
453
|
const caller = this.getCaller();
|
|
@@ -447,7 +490,8 @@ var init_logger_base_MYys2STJ = __esm({
|
|
|
447
490
|
if (!this.shouldLog(level)) return;
|
|
448
491
|
const normalizedData = this.normalizeData(data);
|
|
449
492
|
const errorInfo = errorObj ? extractErrorInfo(errorObj, !this.isProd()) : void 0;
|
|
450
|
-
const
|
|
493
|
+
const built = this.buildEntry(level, message, normalizedData, errorInfo);
|
|
494
|
+
const entry = this.shouldSanitize && this.piiFilter ? applyPiiFilterToEntry(built, this.piiFilter) : built;
|
|
451
495
|
const formatted = this.format === "json" ? formatJson(entry) : formatPretty(entry);
|
|
452
496
|
for (const transport of this.transports) transport.log(entry, formatted);
|
|
453
497
|
this.flush();
|
|
@@ -609,8 +653,8 @@ function createLogger(module, options) {
|
|
|
609
653
|
var asyncLocalStorage, ConsoleTransport, FileTransport, HttpTransport, SINGLETON_KEY, Logger, logger;
|
|
610
654
|
var init_dist = __esm({
|
|
611
655
|
"../../node_modules/@parisgroup-ai/logger/dist/index.mjs"() {
|
|
612
|
-
|
|
613
|
-
|
|
656
|
+
init_logger_base_DOZPgsDx();
|
|
657
|
+
init_sanitize_4AyoT9ic();
|
|
614
658
|
asyncLocalStorage = new AsyncLocalStorage();
|
|
615
659
|
ConsoleTransport = class {
|
|
616
660
|
log(entry, formatted) {
|
|
@@ -768,7 +812,8 @@ var init_dist = __esm({
|
|
|
768
812
|
environment: this.environment,
|
|
769
813
|
sanitize: this.shouldSanitize,
|
|
770
814
|
sensitiveFields: this.sensitiveFields,
|
|
771
|
-
includeCaller: this.includeCaller
|
|
815
|
+
includeCaller: this.includeCaller,
|
|
816
|
+
piiFilter: this.piiFilter
|
|
772
817
|
});
|
|
773
818
|
child.additionalContext = {
|
|
774
819
|
...this.additionalContext,
|
|
@@ -836,9 +881,15 @@ async function cliApiFetch(url2, token, init) {
|
|
|
836
881
|
...init?.headers
|
|
837
882
|
}
|
|
838
883
|
});
|
|
839
|
-
const body = await response.json();
|
|
884
|
+
const body = await response.json().catch(() => ({}));
|
|
840
885
|
if (!response.ok) {
|
|
841
|
-
|
|
886
|
+
const code = typeof body.error === "string" && body.error.length > 0 ? body.error : void 0;
|
|
887
|
+
const friendly = typeof body.message === "string" && body.message.length > 0 ? body.message : void 0;
|
|
888
|
+
throw new CliApiError(
|
|
889
|
+
friendly ?? code ?? `API error ${response.status}`,
|
|
890
|
+
response.status,
|
|
891
|
+
code
|
|
892
|
+
);
|
|
842
893
|
}
|
|
843
894
|
return body;
|
|
844
895
|
}
|
|
@@ -973,12 +1024,14 @@ var init_http = __esm({
|
|
|
973
1024
|
"../../packages/tostudy-core/src/adapters/http.ts"() {
|
|
974
1025
|
"use strict";
|
|
975
1026
|
CliApiError = class extends Error {
|
|
976
|
-
constructor(message, status) {
|
|
1027
|
+
constructor(message, status, code) {
|
|
977
1028
|
super(message);
|
|
978
1029
|
this.status = status;
|
|
1030
|
+
this.code = code;
|
|
979
1031
|
this.name = "CliApiError";
|
|
980
1032
|
}
|
|
981
1033
|
status;
|
|
1034
|
+
code;
|
|
982
1035
|
};
|
|
983
1036
|
}
|
|
984
1037
|
});
|
|
@@ -2734,17 +2787,21 @@ function resolveLocale() {
|
|
|
2734
2787
|
function getErrors(locale) {
|
|
2735
2788
|
return BUNDLES[locale ?? resolveLocale()];
|
|
2736
2789
|
}
|
|
2790
|
+
function resolveErrorCode(err) {
|
|
2791
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
2792
|
+
const code = err.code;
|
|
2793
|
+
if (typeof code === "string" && code.length > 0) return code;
|
|
2794
|
+
}
|
|
2795
|
+
return err instanceof Error ? err.message : String(err);
|
|
2796
|
+
}
|
|
2737
2797
|
function isInsufficientCreditsError(err) {
|
|
2738
|
-
|
|
2739
|
-
return msg.includes("INSUFFICIENT_CREDITS");
|
|
2798
|
+
return resolveErrorCode(err).includes("INSUFFICIENT_CREDITS");
|
|
2740
2799
|
}
|
|
2741
2800
|
function isCourseArchivedError(err) {
|
|
2742
|
-
|
|
2743
|
-
return msg.includes("COURSE_ARCHIVED");
|
|
2801
|
+
return resolveErrorCode(err).includes("COURSE_ARCHIVED");
|
|
2744
2802
|
}
|
|
2745
2803
|
function isEnrollmentNotEntitledError(err) {
|
|
2746
|
-
|
|
2747
|
-
return msg.includes("ENROLLMENT_NOT_ENTITLED");
|
|
2804
|
+
return resolveErrorCode(err).includes("ENROLLMENT_NOT_ENTITLED");
|
|
2748
2805
|
}
|
|
2749
2806
|
var BUNDLES, _cachedLocale;
|
|
2750
2807
|
var init_errors = __esm({
|
|
@@ -2942,7 +2999,7 @@ var CLI_VERSION;
|
|
|
2942
2999
|
var init_version = __esm({
|
|
2943
3000
|
"src/version.ts"() {
|
|
2944
3001
|
"use strict";
|
|
2945
|
-
CLI_VERSION = true ? "0.16.
|
|
3002
|
+
CLI_VERSION = true ? "0.16.1" : "0.7.1";
|
|
2946
3003
|
}
|
|
2947
3004
|
});
|
|
2948
3005
|
|
|
@@ -4163,7 +4220,7 @@ async function runStart(opts, deps = defaultDeps3) {
|
|
|
4163
4220
|
`);
|
|
4164
4221
|
}
|
|
4165
4222
|
} catch (err) {
|
|
4166
|
-
if (err instanceof CliApiError && err.status === 403 && err.message === "CHANNEL_MISMATCH") {
|
|
4223
|
+
if (err instanceof CliApiError && err.status === 403 && (err.code ?? err.message) === "CHANNEL_MISMATCH") {
|
|
4167
4224
|
process.stderr.write("Este curso n\xE3o est\xE1 dispon\xEDvel via CLI.\n");
|
|
4168
4225
|
process.stderr.write("Acesse tostudy.ai para estudar este curso pelo ChatStudy.\n");
|
|
4169
4226
|
process.exit(1);
|
|
@@ -4251,7 +4308,7 @@ var init_start_next = __esm({
|
|
|
4251
4308
|
output(formatModuleStart(moduleData), { json: false });
|
|
4252
4309
|
}
|
|
4253
4310
|
} catch (err) {
|
|
4254
|
-
if (err instanceof CliApiError && err.message === "COURSE_COMPLETE") {
|
|
4311
|
+
if (err instanceof CliApiError && (err.code ?? err.message) === "COURSE_COMPLETE") {
|
|
4255
4312
|
process.stderr.write("\u{1F389} Parab\xE9ns! Curso conclu\xEDdo!\n");
|
|
4256
4313
|
process.stderr.write("\u2192 tostudy courses para ver outros cursos\n");
|
|
4257
4314
|
process.exit(0);
|
|
@@ -4324,26 +4381,37 @@ var init_next = __esm({
|
|
|
4324
4381
|
process.exit(1);
|
|
4325
4382
|
}
|
|
4326
4383
|
if (err instanceof CliApiError) {
|
|
4327
|
-
|
|
4384
|
+
const code = err.code ?? err.message;
|
|
4385
|
+
if (err.status === 403 && code === "CHANNEL_MISMATCH") {
|
|
4328
4386
|
process.stderr.write("Este curso n\xE3o est\xE1 dispon\xEDvel via CLI.\n");
|
|
4329
4387
|
process.stderr.write("Acesse tostudy.ai para estudar este curso pelo ChatStudy.\n");
|
|
4330
4388
|
process.exit(1);
|
|
4331
4389
|
}
|
|
4332
|
-
if (
|
|
4390
|
+
if (code === "MODULE_COMPLETE") {
|
|
4333
4391
|
process.stderr.write("\u2713 M\xF3dulo conclu\xEDdo!\n");
|
|
4334
4392
|
process.stderr.write("\u2192 tostudy start-next para iniciar o pr\xF3ximo m\xF3dulo\n");
|
|
4335
4393
|
process.exit(0);
|
|
4336
4394
|
}
|
|
4337
|
-
if (
|
|
4395
|
+
if (code === "COURSE_COMPLETE") {
|
|
4338
4396
|
process.stderr.write("\u{1F389} Parab\xE9ns! Curso conclu\xEDdo!\n");
|
|
4339
4397
|
process.stderr.write("\u2192 tostudy courses para ver outros cursos\n");
|
|
4340
4398
|
process.exit(0);
|
|
4341
4399
|
}
|
|
4342
|
-
if (
|
|
4400
|
+
if (code === "EXERCISE_NOT_PASSED") {
|
|
4401
|
+
process.stderr.write("Voc\xEA ainda n\xE3o foi aprovado no exerc\xEDcio desta li\xE7\xE3o.\n");
|
|
4402
|
+
process.stderr.write("\u2192 tostudy validate para enviar sua solu\xE7\xE3o\n");
|
|
4403
|
+
process.exit(1);
|
|
4404
|
+
}
|
|
4405
|
+
if (code === "NO_ACTIVE_LESSON") {
|
|
4343
4406
|
process.stderr.write("Nenhuma li\xE7\xE3o em progresso.\n");
|
|
4344
4407
|
process.stderr.write("\u2192 tostudy start-next para iniciar o pr\xF3ximo m\xF3dulo\n");
|
|
4345
4408
|
process.exit(0);
|
|
4346
4409
|
}
|
|
4410
|
+
if (err.status === 409) {
|
|
4411
|
+
process.stderr.write(`${err.message}
|
|
4412
|
+
`);
|
|
4413
|
+
process.exit(1);
|
|
4414
|
+
}
|
|
4347
4415
|
}
|
|
4348
4416
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4349
4417
|
if (opts.json) jsonError(msg);
|
|
@@ -4611,6 +4679,11 @@ var init_hint = __esm({
|
|
|
4611
4679
|
else process.stderr.write(friendly);
|
|
4612
4680
|
process.exit(1);
|
|
4613
4681
|
}
|
|
4682
|
+
if (err instanceof CliApiError && (err.code ?? err.message) === "NO_ACTIVE_LESSON") {
|
|
4683
|
+
process.stderr.write("Nenhuma li\xE7\xE3o em progresso.\n");
|
|
4684
|
+
process.stderr.write("\u2192 tostudy start-next para iniciar o pr\xF3ximo m\xF3dulo\n");
|
|
4685
|
+
process.exit(0);
|
|
4686
|
+
}
|
|
4614
4687
|
if (isInsufficientCreditsError(err)) {
|
|
4615
4688
|
const friendly = getErrors().insufficientCredits;
|
|
4616
4689
|
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
@@ -21666,7 +21739,12 @@ var init_theory = __esm({
|
|
|
21666
21739
|
});
|
|
21667
21740
|
if (!res.ok) {
|
|
21668
21741
|
const body = await res.json().catch(() => ({}));
|
|
21669
|
-
|
|
21742
|
+
if (body.error === "INSUFFICIENT_CREDITS" || (body.message ?? "").includes("INSUFFICIENT_CREDITS")) {
|
|
21743
|
+
const friendly = getErrors().insufficientCredits;
|
|
21744
|
+
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
21745
|
+
error(friendly);
|
|
21746
|
+
}
|
|
21747
|
+
const msg = body.error ?? body.message ?? `Falha ao pedir teoria (${res.status})`;
|
|
21670
21748
|
if (opts.json) jsonError("request_failed", { message: msg, code: res.status });
|
|
21671
21749
|
error(msg);
|
|
21672
21750
|
}
|