@tostudy-ai/cli 0.2.0 → 0.3.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/bin/tostudy.ts +4 -1
- package/dist/cli.js +139 -19
- package/dist/cli.js.map +4 -4
- package/package.json +2 -2
package/bin/tostudy.ts
CHANGED
|
@@ -3,7 +3,10 @@ if (!process.env.LOG_LEVEL) {
|
|
|
3
3
|
process.env.LOG_LEVEL = "fatal";
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
import { createProgram } from "../src/cli.js";
|
|
6
|
+
import { createProgram, CLI_VERSION } from "../src/cli.js";
|
|
7
|
+
import { checkForUpdates } from "../src/update-checker.js";
|
|
7
8
|
|
|
8
9
|
const program = createProgram();
|
|
9
10
|
program.parse();
|
|
11
|
+
|
|
12
|
+
checkForUpdates(CLI_VERSION);
|
package/dist/cli.js
CHANGED
|
@@ -835,6 +835,104 @@ var init_setup = __esm({
|
|
|
835
835
|
}
|
|
836
836
|
});
|
|
837
837
|
|
|
838
|
+
// src/update-checker.ts
|
|
839
|
+
var update_checker_exports = {};
|
|
840
|
+
__export(update_checker_exports, {
|
|
841
|
+
checkForUpdates: () => checkForUpdates,
|
|
842
|
+
checkVersionSync: () => checkVersionSync,
|
|
843
|
+
fetchLatestVersion: () => fetchLatestVersion,
|
|
844
|
+
isNewerVersion: () => isNewerVersion
|
|
845
|
+
});
|
|
846
|
+
import fs4 from "node:fs";
|
|
847
|
+
import path4 from "node:path";
|
|
848
|
+
import os4 from "node:os";
|
|
849
|
+
function getConfigDir2() {
|
|
850
|
+
if (process.platform === "linux" && process.env["XDG_CONFIG_HOME"]) {
|
|
851
|
+
return path4.join(process.env["XDG_CONFIG_HOME"], "tostudy");
|
|
852
|
+
}
|
|
853
|
+
return path4.join(os4.homedir(), ".tostudy");
|
|
854
|
+
}
|
|
855
|
+
function readCache() {
|
|
856
|
+
try {
|
|
857
|
+
const p = path4.join(getConfigDir2(), CACHE_FILE);
|
|
858
|
+
if (!fs4.existsSync(p)) return null;
|
|
859
|
+
return JSON.parse(fs4.readFileSync(p, "utf-8"));
|
|
860
|
+
} catch {
|
|
861
|
+
return null;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function writeCache(cache) {
|
|
865
|
+
try {
|
|
866
|
+
const dir = getConfigDir2();
|
|
867
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
868
|
+
fs4.writeFileSync(path4.join(dir, CACHE_FILE), JSON.stringify(cache));
|
|
869
|
+
} catch {
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
function isNewerVersion(latest, current) {
|
|
873
|
+
const parse3 = (v) => v.split(".").map(Number);
|
|
874
|
+
const [lMaj, lMin, lPatch] = parse3(latest);
|
|
875
|
+
const [cMaj, cMin, cPatch] = parse3(current);
|
|
876
|
+
if (lMaj !== cMaj) return lMaj > cMaj;
|
|
877
|
+
if (lMin !== cMin) return lMin > cMin;
|
|
878
|
+
return lPatch > cPatch;
|
|
879
|
+
}
|
|
880
|
+
async function fetchLatestVersion() {
|
|
881
|
+
try {
|
|
882
|
+
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
|
|
883
|
+
signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS)
|
|
884
|
+
});
|
|
885
|
+
if (!res.ok) return null;
|
|
886
|
+
const data = await res.json();
|
|
887
|
+
return data.version ?? null;
|
|
888
|
+
} catch {
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
function showUpdateNotification(current, latest) {
|
|
893
|
+
process.stderr.write(
|
|
894
|
+
[
|
|
895
|
+
"",
|
|
896
|
+
` Atualiza\xE7\xE3o dispon\xEDvel: ${current} \u2192 ${latest}`,
|
|
897
|
+
" Atualize com: npm i -g @tostudy-ai/cli",
|
|
898
|
+
""
|
|
899
|
+
].join("\n")
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
function checkForUpdates(currentVersion) {
|
|
903
|
+
if (process.env["CI"] || process.argv.includes("--json")) return;
|
|
904
|
+
const cache = readCache();
|
|
905
|
+
if (cache && isNewerVersion(cache.latest, currentVersion)) {
|
|
906
|
+
showUpdateNotification(currentVersion, cache.latest);
|
|
907
|
+
}
|
|
908
|
+
const isStale = !cache || Date.now() - cache.checkedAt >= CHECK_INTERVAL_MS;
|
|
909
|
+
if (isStale) {
|
|
910
|
+
fetchLatestVersion().then((latest) => {
|
|
911
|
+
if (latest) writeCache({ latest, checkedAt: Date.now() });
|
|
912
|
+
}).catch(() => {
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async function checkVersionSync(currentVersion) {
|
|
917
|
+
const latest = await fetchLatestVersion();
|
|
918
|
+
if (latest) writeCache({ latest, checkedAt: Date.now() });
|
|
919
|
+
return {
|
|
920
|
+
current: currentVersion,
|
|
921
|
+
latest,
|
|
922
|
+
updateAvailable: latest ? isNewerVersion(latest, currentVersion) : false
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
var PACKAGE_NAME, CACHE_FILE, CHECK_INTERVAL_MS, REGISTRY_TIMEOUT_MS;
|
|
926
|
+
var init_update_checker = __esm({
|
|
927
|
+
"src/update-checker.ts"() {
|
|
928
|
+
"use strict";
|
|
929
|
+
PACKAGE_NAME = "@tostudy-ai/cli";
|
|
930
|
+
CACHE_FILE = "update-check.json";
|
|
931
|
+
CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
932
|
+
REGISTRY_TIMEOUT_MS = 5e3;
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
|
|
838
936
|
// src/commands/doctor.ts
|
|
839
937
|
import { Command as Command4 } from "commander";
|
|
840
938
|
var doctorCommand;
|
|
@@ -845,6 +943,8 @@ var init_doctor = __esm({
|
|
|
845
943
|
init_ide_detector();
|
|
846
944
|
init_session();
|
|
847
945
|
init_formatter();
|
|
946
|
+
init_cli();
|
|
947
|
+
init_update_checker();
|
|
848
948
|
doctorCommand = new Command4("doctor").description("Diagn\xF3stico do ambiente").option("--json", "Output JSON").option("--fix", "Auto-corrigir problemas (reservado para vers\xF5es futuras)").action(async (opts) => {
|
|
849
949
|
const checks = {};
|
|
850
950
|
const node = detectNode();
|
|
@@ -887,6 +987,8 @@ var init_doctor = __esm({
|
|
|
887
987
|
} catch {
|
|
888
988
|
checks["connectivity"] = { ok: false, latencyMs: null };
|
|
889
989
|
}
|
|
990
|
+
const versionInfo = await checkVersionSync(CLI_VERSION);
|
|
991
|
+
checks["version"] = versionInfo;
|
|
890
992
|
let ides = [];
|
|
891
993
|
try {
|
|
892
994
|
ides = detectIDEs();
|
|
@@ -919,6 +1021,19 @@ var init_doctor = __esm({
|
|
|
919
1021
|
console.log(
|
|
920
1022
|
` ${connectivity.ok ? "\u2713" : "\u2717"} API ${connectivity.ok ? `OK (${connectivity.latencyMs}ms)` : "indispon\xEDvel"}`
|
|
921
1023
|
);
|
|
1024
|
+
console.log("\n Vers\xE3o");
|
|
1025
|
+
console.log(` \u2713 Instalada ${versionInfo.current}`);
|
|
1026
|
+
if (versionInfo.latest) {
|
|
1027
|
+
const upToDate = !versionInfo.updateAvailable;
|
|
1028
|
+
console.log(
|
|
1029
|
+
` ${upToDate ? "\u2713" : "\u2717"} \xDAltima ${versionInfo.latest}${versionInfo.updateAvailable ? " (atualiza\xE7\xE3o dispon\xEDvel)" : ""}`
|
|
1030
|
+
);
|
|
1031
|
+
if (versionInfo.updateAvailable) {
|
|
1032
|
+
console.log(" \u2192 npm i -g @tostudy-ai/cli");
|
|
1033
|
+
}
|
|
1034
|
+
} else {
|
|
1035
|
+
console.log(" \u25CB \xDAltima n\xE3o foi poss\xEDvel verificar");
|
|
1036
|
+
}
|
|
922
1037
|
console.log("\n LLM Clients");
|
|
923
1038
|
for (const ide of ides) {
|
|
924
1039
|
console.log(
|
|
@@ -2677,10 +2792,10 @@ function mergeDefs(...defs) {
|
|
|
2677
2792
|
function cloneDef(schema) {
|
|
2678
2793
|
return mergeDefs(schema._zod.def);
|
|
2679
2794
|
}
|
|
2680
|
-
function getElementAtPath(obj,
|
|
2681
|
-
if (!
|
|
2795
|
+
function getElementAtPath(obj, path5) {
|
|
2796
|
+
if (!path5)
|
|
2682
2797
|
return obj;
|
|
2683
|
-
return
|
|
2798
|
+
return path5.reduce((acc, key) => acc?.[key], obj);
|
|
2684
2799
|
}
|
|
2685
2800
|
function promiseAllObject(promisesObj) {
|
|
2686
2801
|
const keys = Object.keys(promisesObj);
|
|
@@ -2992,11 +3107,11 @@ function aborted(x, startIndex = 0) {
|
|
|
2992
3107
|
}
|
|
2993
3108
|
return false;
|
|
2994
3109
|
}
|
|
2995
|
-
function prefixIssues(
|
|
3110
|
+
function prefixIssues(path5, issues) {
|
|
2996
3111
|
return issues.map((iss) => {
|
|
2997
3112
|
var _a2;
|
|
2998
3113
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
2999
|
-
iss.path.unshift(
|
|
3114
|
+
iss.path.unshift(path5);
|
|
3000
3115
|
return iss;
|
|
3001
3116
|
});
|
|
3002
3117
|
}
|
|
@@ -3238,7 +3353,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
|
|
|
3238
3353
|
}
|
|
3239
3354
|
function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
3240
3355
|
const result = { errors: [] };
|
|
3241
|
-
const processError = (error50,
|
|
3356
|
+
const processError = (error50, path5 = []) => {
|
|
3242
3357
|
var _a2, _b;
|
|
3243
3358
|
for (const issue2 of error50.issues) {
|
|
3244
3359
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -3248,7 +3363,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
3248
3363
|
} else if (issue2.code === "invalid_element") {
|
|
3249
3364
|
processError({ issues: issue2.issues }, issue2.path);
|
|
3250
3365
|
} else {
|
|
3251
|
-
const fullpath = [...
|
|
3366
|
+
const fullpath = [...path5, ...issue2.path];
|
|
3252
3367
|
if (fullpath.length === 0) {
|
|
3253
3368
|
result.errors.push(mapper(issue2));
|
|
3254
3369
|
continue;
|
|
@@ -3280,8 +3395,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
3280
3395
|
}
|
|
3281
3396
|
function toDotPath(_path) {
|
|
3282
3397
|
const segs = [];
|
|
3283
|
-
const
|
|
3284
|
-
for (const seg of
|
|
3398
|
+
const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
3399
|
+
for (const seg of path5) {
|
|
3285
3400
|
if (typeof seg === "number")
|
|
3286
3401
|
segs.push(`[${seg}]`);
|
|
3287
3402
|
else if (typeof seg === "symbol")
|
|
@@ -15975,13 +16090,13 @@ function resolveRef(ref, ctx) {
|
|
|
15975
16090
|
if (!ref.startsWith("#")) {
|
|
15976
16091
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15977
16092
|
}
|
|
15978
|
-
const
|
|
15979
|
-
if (
|
|
16093
|
+
const path5 = ref.slice(1).split("/").filter(Boolean);
|
|
16094
|
+
if (path5.length === 0) {
|
|
15980
16095
|
return ctx.rootSchema;
|
|
15981
16096
|
}
|
|
15982
16097
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15983
|
-
if (
|
|
15984
|
-
const key =
|
|
16098
|
+
if (path5[0] === defsKey) {
|
|
16099
|
+
const key = path5[1];
|
|
15985
16100
|
if (!key || !ctx.defs[key]) {
|
|
15986
16101
|
throw new Error(`Reference not found: ${ref}`);
|
|
15987
16102
|
}
|
|
@@ -16972,7 +17087,7 @@ var init_exercises = __esm({
|
|
|
16972
17087
|
});
|
|
16973
17088
|
|
|
16974
17089
|
// src/commands/validate.ts
|
|
16975
|
-
import
|
|
17090
|
+
import fs5 from "node:fs";
|
|
16976
17091
|
import { Command as Command13 } from "commander";
|
|
16977
17092
|
var logger10, validateCommand;
|
|
16978
17093
|
var init_validate = __esm({
|
|
@@ -16996,12 +17111,12 @@ var init_validate = __esm({
|
|
|
16996
17111
|
}
|
|
16997
17112
|
let solution;
|
|
16998
17113
|
if (opts.stdin) {
|
|
16999
|
-
solution =
|
|
17114
|
+
solution = fs5.readFileSync("/dev/stdin", "utf-8");
|
|
17000
17115
|
} else if (file2) {
|
|
17001
|
-
if (!
|
|
17116
|
+
if (!fs5.existsSync(file2)) {
|
|
17002
17117
|
error(`Arquivo n\xE3o encontrado: ${file2}`);
|
|
17003
17118
|
}
|
|
17004
|
-
solution =
|
|
17119
|
+
solution = fs5.readFileSync(file2, "utf-8");
|
|
17005
17120
|
} else {
|
|
17006
17121
|
error("Forne\xE7a um arquivo ou use --stdin.\n\nExemplo: tostudy validate resposta.md");
|
|
17007
17122
|
}
|
|
@@ -17298,12 +17413,13 @@ Rode \`tostudy select <n\xFAmero>\` para ativar um curso.`,
|
|
|
17298
17413
|
// src/cli.ts
|
|
17299
17414
|
var cli_exports = {};
|
|
17300
17415
|
__export(cli_exports, {
|
|
17416
|
+
CLI_VERSION: () => CLI_VERSION,
|
|
17301
17417
|
createProgram: () => createProgram
|
|
17302
17418
|
});
|
|
17303
17419
|
import { Command as Command16 } from "commander";
|
|
17304
17420
|
function createProgram() {
|
|
17305
17421
|
const program2 = new Command16();
|
|
17306
|
-
program2.name("tostudy").description("ToStudy CLI \u2014 study courses from the terminal").version(
|
|
17422
|
+
program2.name("tostudy").description("ToStudy CLI \u2014 study courses from the terminal").version(CLI_VERSION).option("--json", "Output structured JSON (for LLM agents)").option("--verbose", "Enable debug output").option("--course <id>", "Override active course ID");
|
|
17307
17423
|
program2.addCommand(setupCommand);
|
|
17308
17424
|
program2.addCommand(doctorCommand);
|
|
17309
17425
|
program2.addCommand(initCommand);
|
|
@@ -17321,6 +17437,7 @@ function createProgram() {
|
|
|
17321
17437
|
program2.addCommand(menuCommand);
|
|
17322
17438
|
return program2;
|
|
17323
17439
|
}
|
|
17440
|
+
var CLI_VERSION;
|
|
17324
17441
|
var init_cli = __esm({
|
|
17325
17442
|
"src/cli.ts"() {
|
|
17326
17443
|
"use strict";
|
|
@@ -17339,6 +17456,7 @@ var init_cli = __esm({
|
|
|
17339
17456
|
init_validate();
|
|
17340
17457
|
init_menu();
|
|
17341
17458
|
init_init();
|
|
17459
|
+
CLI_VERSION = "0.3.0";
|
|
17342
17460
|
}
|
|
17343
17461
|
});
|
|
17344
17462
|
|
|
@@ -17346,7 +17464,9 @@ var init_cli = __esm({
|
|
|
17346
17464
|
if (!process.env.LOG_LEVEL) {
|
|
17347
17465
|
process.env.LOG_LEVEL = "fatal";
|
|
17348
17466
|
}
|
|
17349
|
-
var { createProgram: createProgram2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
17467
|
+
var { createProgram: createProgram2, CLI_VERSION: CLI_VERSION2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
17468
|
+
var { checkForUpdates: checkForUpdates2 } = await Promise.resolve().then(() => (init_update_checker(), update_checker_exports));
|
|
17350
17469
|
var program = createProgram2();
|
|
17351
17470
|
program.parse();
|
|
17471
|
+
checkForUpdates2(CLI_VERSION2);
|
|
17352
17472
|
//# sourceMappingURL=cli.js.map
|