@tostudy-ai/cli 0.16.11 → 0.16.12
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 +103 -41
- package/dist/cli.js.map +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1058,8 +1058,9 @@ async function cliApiFetch(url2, token, init) {
|
|
|
1058
1058
|
if (!response.ok) {
|
|
1059
1059
|
const code = typeof body.error === "string" && body.error.length > 0 ? body.error : void 0;
|
|
1060
1060
|
const friendly = typeof body.message === "string" && body.message.length > 0 ? body.message : void 0;
|
|
1061
|
+
const unauthenticated = response.status === 401 ? "Sess\xE3o inv\xE1lida ou expirada. Rode: tostudy login" : void 0;
|
|
1061
1062
|
throw new CliApiError(
|
|
1062
|
-
friendly ?? code ?? `API error ${response.status}`,
|
|
1063
|
+
friendly ?? unauthenticated ?? code ?? `API error ${response.status}`,
|
|
1063
1064
|
response.status,
|
|
1064
1065
|
code
|
|
1065
1066
|
);
|
|
@@ -2617,11 +2618,18 @@ var init_login = __esm({
|
|
|
2617
2618
|
}
|
|
2618
2619
|
if (opts.manual) {
|
|
2619
2620
|
console.log(`
|
|
2620
|
-
|
|
2621
|
-
console.log(`
|
|
2621
|
+
Login sem browser nesta m\xE1quina:`);
|
|
2622
|
+
console.log(` 1. Em um computador com browser, acesse:`);
|
|
2623
|
+
console.log(` ${apiUrl}/api/cli/auth/authorize`);
|
|
2624
|
+
console.log(
|
|
2625
|
+
` 2. Ap\xF3s autorizar, o browser tenta abrir http://localhost:9876/callback?code=...`
|
|
2626
|
+
);
|
|
2627
|
+
console.log(
|
|
2628
|
+
` e falha (n\xE3o h\xE1 CLI nesse computador). Copie o valor de "code" da barra de endere\xE7o.`
|
|
2629
|
+
);
|
|
2630
|
+
console.log(` 3. Em at\xE9 5 minutos, volte aqui e rode:`);
|
|
2631
|
+
console.log(` tostudy login --code <code>
|
|
2622
2632
|
`);
|
|
2623
|
-
console.log(" Ap\xF3s autorizar, o browser ser\xE1 redirecionado e o login ser\xE1 conclu\xEDdo.");
|
|
2624
|
-
console.log(" Certifique-se de rodar este comando sem --manual para o fluxo autom\xE1tico.\n");
|
|
2625
2633
|
return;
|
|
2626
2634
|
}
|
|
2627
2635
|
console.log("\n Abrindo browser para autentica\xE7\xE3o...\n");
|
|
@@ -3224,30 +3232,43 @@ var init_resolve = __esm({
|
|
|
3224
3232
|
});
|
|
3225
3233
|
|
|
3226
3234
|
// src/auth/guards.ts
|
|
3235
|
+
var guards_exports = {};
|
|
3236
|
+
__export(guards_exports, {
|
|
3237
|
+
requireActiveCourse: () => requireActiveCourse,
|
|
3238
|
+
requireSession: () => requireSession
|
|
3239
|
+
});
|
|
3227
3240
|
async function refreshCliSession(session, configDir) {
|
|
3241
|
+
let response;
|
|
3228
3242
|
try {
|
|
3229
|
-
|
|
3243
|
+
response = await fetch(`${session.apiUrl}/api/cli/auth/refresh`, {
|
|
3230
3244
|
method: "POST",
|
|
3231
3245
|
headers: { "Content-Type": "application/json" },
|
|
3232
3246
|
body: JSON.stringify({ refreshToken: session.refreshToken })
|
|
3233
3247
|
});
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
const data = await response.json();
|
|
3239
|
-
const refreshed = {
|
|
3240
|
-
...session,
|
|
3241
|
-
token: data.token,
|
|
3242
|
-
refreshToken: data.refreshToken,
|
|
3243
|
-
expiresAt: data.expiresAt
|
|
3244
|
-
};
|
|
3245
|
-
await saveSession(refreshed, configDir);
|
|
3246
|
-
return refreshed;
|
|
3247
|
-
} catch {
|
|
3248
|
+
} catch (err) {
|
|
3249
|
+
return { status: "unavailable", reason: err instanceof Error ? err.message : String(err) };
|
|
3250
|
+
}
|
|
3251
|
+
if (response.status === 401 || response.status === 403) {
|
|
3248
3252
|
await clearSessionArtifacts(configDir);
|
|
3249
|
-
return
|
|
3253
|
+
return { status: "rejected" };
|
|
3250
3254
|
}
|
|
3255
|
+
if (!response.ok) {
|
|
3256
|
+
return { status: "unavailable", reason: `HTTP ${response.status}` };
|
|
3257
|
+
}
|
|
3258
|
+
let data;
|
|
3259
|
+
try {
|
|
3260
|
+
data = await response.json();
|
|
3261
|
+
} catch (err) {
|
|
3262
|
+
return { status: "unavailable", reason: err instanceof Error ? err.message : String(err) };
|
|
3263
|
+
}
|
|
3264
|
+
const refreshed = {
|
|
3265
|
+
...session,
|
|
3266
|
+
token: data.token,
|
|
3267
|
+
refreshToken: data.refreshToken,
|
|
3268
|
+
expiresAt: data.expiresAt
|
|
3269
|
+
};
|
|
3270
|
+
await saveSession(refreshed, configDir);
|
|
3271
|
+
return { status: "ok", session: refreshed };
|
|
3251
3272
|
}
|
|
3252
3273
|
async function requireSession(configDir) {
|
|
3253
3274
|
const session = await getSession(configDir);
|
|
@@ -3257,12 +3278,17 @@ async function requireSession(configDir) {
|
|
|
3257
3278
|
}
|
|
3258
3279
|
const expiresAt = new Date(session.expiresAt);
|
|
3259
3280
|
if (expiresAt < /* @__PURE__ */ new Date()) {
|
|
3260
|
-
const
|
|
3261
|
-
if (
|
|
3281
|
+
const outcome = await refreshCliSession(session, configDir);
|
|
3282
|
+
if (outcome.status === "ok") return outcome.session;
|
|
3283
|
+
if (outcome.status === "rejected") {
|
|
3262
3284
|
process.stderr.write("Erro: Sess\xE3o expirada. Rode: tostudy login\n");
|
|
3263
3285
|
process.exit(2);
|
|
3264
3286
|
}
|
|
3265
|
-
|
|
3287
|
+
process.stderr.write(
|
|
3288
|
+
`Erro: N\xE3o foi poss\xEDvel renovar a sess\xE3o (${outcome.reason}). Sua sess\xE3o foi mantida \u2014 verifique a conex\xE3o e tente de novo.
|
|
3289
|
+
`
|
|
3290
|
+
);
|
|
3291
|
+
process.exit(4);
|
|
3266
3292
|
}
|
|
3267
3293
|
return session;
|
|
3268
3294
|
}
|
|
@@ -3413,7 +3439,7 @@ var CLI_VERSION;
|
|
|
3413
3439
|
var init_version = __esm({
|
|
3414
3440
|
"src/version.ts"() {
|
|
3415
3441
|
"use strict";
|
|
3416
|
-
CLI_VERSION = true ? "0.16.
|
|
3442
|
+
CLI_VERSION = true ? "0.16.12" : "0.7.1";
|
|
3417
3443
|
}
|
|
3418
3444
|
});
|
|
3419
3445
|
|
|
@@ -4372,6 +4398,7 @@ var init_select = __esm({
|
|
|
4372
4398
|
interactive: isInteractiveTerminal(opts.json)
|
|
4373
4399
|
});
|
|
4374
4400
|
let pipelineResult = null;
|
|
4401
|
+
let pipelineError = null;
|
|
4375
4402
|
try {
|
|
4376
4403
|
pipelineResult = await resolveAndGenerate(
|
|
4377
4404
|
{ courseId: detail.courseId, enrollmentId },
|
|
@@ -4382,9 +4409,8 @@ var init_select = __esm({
|
|
|
4382
4409
|
}
|
|
4383
4410
|
);
|
|
4384
4411
|
} catch (err) {
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
});
|
|
4412
|
+
pipelineError = err instanceof Error ? err.message : String(err);
|
|
4413
|
+
logger8.warn("Failed to run instruction pipeline", { error: pipelineError });
|
|
4388
4414
|
}
|
|
4389
4415
|
const slugMatch = pipelineResult?.wroteFiles.find((f) => f.startsWith(".claude/commands/"))?.match(/tostudy-(.+)\.md$/);
|
|
4390
4416
|
const courseSlug2 = slugMatch?.[1] ?? "";
|
|
@@ -4402,7 +4428,8 @@ var init_select = __esm({
|
|
|
4402
4428
|
usedT0: pipelineResult?.usedT0 ?? false,
|
|
4403
4429
|
usedT1: pipelineResult?.usedT1 ?? false,
|
|
4404
4430
|
usedT2: pipelineResult?.usedT2 ?? false,
|
|
4405
|
-
instruction: pipelineResult?.renderedInstruction ?? null
|
|
4431
|
+
instruction: pipelineResult?.renderedInstruction ?? null,
|
|
4432
|
+
pipelineError
|
|
4406
4433
|
},
|
|
4407
4434
|
{ json: true }
|
|
4408
4435
|
);
|
|
@@ -4426,7 +4453,8 @@ var init_select = __esm({
|
|
|
4426
4453
|
` Progresso: ${detail.progress}% | ${detail.moduleCount} m\xF3dulos | ${detail.lessonCount} li\xE7\xF5es`,
|
|
4427
4454
|
wsLine,
|
|
4428
4455
|
"",
|
|
4429
|
-
|
|
4456
|
+
pipelineError ? `\u26A0 Arquivos de contexto N\xC3O foram criados (${pipelineError}).
|
|
4457
|
+
Rode \`tostudy select\` de novo com a conex\xE3o ativa.` : " Arquivos de contexto criados para seu assistente AI."
|
|
4430
4458
|
];
|
|
4431
4459
|
if (pipelineResult && !pipelineResult.usedT0) {
|
|
4432
4460
|
lines.push(" (sem persona do creator \u2014 usando tutor neutro)");
|
|
@@ -20427,15 +20455,27 @@ Rode \`tostudy select <n\xFAmero>\` para ativar um curso.`,
|
|
|
20427
20455
|
progressData,
|
|
20428
20456
|
learnerProfile
|
|
20429
20457
|
);
|
|
20430
|
-
await deps.saveRemoteEnrollmentOnboarding({
|
|
20431
|
-
apiUrl: session.apiUrl,
|
|
20432
|
-
token: session.token,
|
|
20433
|
-
enrollmentId: activeCourse.enrollmentId,
|
|
20434
|
-
learnerBrief: artifacts.learnerBrief,
|
|
20435
|
-
learnerProfile,
|
|
20436
|
-
source: "cli"
|
|
20437
|
-
});
|
|
20438
20458
|
await deps.saveCourseLearnerProfile(activeCourse, learnerProfile, artifacts);
|
|
20459
|
+
try {
|
|
20460
|
+
await deps.saveRemoteEnrollmentOnboarding({
|
|
20461
|
+
apiUrl: session.apiUrl,
|
|
20462
|
+
token: session.token,
|
|
20463
|
+
enrollmentId: activeCourse.enrollmentId,
|
|
20464
|
+
learnerBrief: artifacts.learnerBrief,
|
|
20465
|
+
learnerProfile,
|
|
20466
|
+
source: "cli"
|
|
20467
|
+
});
|
|
20468
|
+
} catch (err) {
|
|
20469
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
20470
|
+
deps.logger.warn("Failed to save enrollment onboarding remotely", { error: reason });
|
|
20471
|
+
if (!flags.json) {
|
|
20472
|
+
process.stderr.write(
|
|
20473
|
+
`\u26A0 Suas respostas foram salvas neste computador, mas n\xE3o chegaram ao servidor (${reason}).
|
|
20474
|
+
Rode \`tostudy init\` de novo com a conex\xE3o ativa para sincronizar.
|
|
20475
|
+
`
|
|
20476
|
+
);
|
|
20477
|
+
}
|
|
20478
|
+
}
|
|
20439
20479
|
try {
|
|
20440
20480
|
const rootAgents = await resolveRootAgentsConsent({
|
|
20441
20481
|
cwd: process.cwd(),
|
|
@@ -20493,7 +20533,13 @@ var init_init = __esm({
|
|
|
20493
20533
|
init_pipeline_deps();
|
|
20494
20534
|
logger17 = createLogger("cli:init");
|
|
20495
20535
|
defaultDeps4 = {
|
|
20496
|
-
|
|
20536
|
+
// GH #1419 item 3 — `init` used the raw session, so an expired access
|
|
20537
|
+
// token met the POST as a 401. Refresh through the guard when one exists.
|
|
20538
|
+
getSession: async () => {
|
|
20539
|
+
if (!await getSession()) return null;
|
|
20540
|
+
const { requireSession: requireSession2 } = await Promise.resolve().then(() => (init_guards(), guards_exports));
|
|
20541
|
+
return requireSession2();
|
|
20542
|
+
},
|
|
20497
20543
|
findWorkspaceState,
|
|
20498
20544
|
listCourses,
|
|
20499
20545
|
getProgress,
|
|
@@ -22957,8 +23003,17 @@ __export(cli_exports, {
|
|
|
22957
23003
|
import { Command as Command35 } from "commander";
|
|
22958
23004
|
function createProgram() {
|
|
22959
23005
|
const program2 = new Command35();
|
|
22960
|
-
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")
|
|
22961
|
-
|
|
23006
|
+
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").addHelpText(
|
|
23007
|
+
"before",
|
|
23008
|
+
[
|
|
23009
|
+
"",
|
|
23010
|
+
" Come\xE7ando: login \u2192 courses \u2192 select <n> \u2192 start",
|
|
23011
|
+
" Estudando: next \xB7 lesson \xB7 hint \xB7 validate \xB7 theory \xB7 progress",
|
|
23012
|
+
" Com d\xFAvida: tostudy menu (mostra onde voc\xEA est\xE1 e o que fazer)",
|
|
23013
|
+
""
|
|
23014
|
+
].join("\n")
|
|
23015
|
+
);
|
|
23016
|
+
program2.addCommand(setupCommand, { hidden: true });
|
|
22962
23017
|
program2.addCommand(doctorCommand);
|
|
22963
23018
|
program2.addCommand(initCommand);
|
|
22964
23019
|
program2.addCommand(loginCommand);
|
|
@@ -23134,6 +23189,13 @@ if (!process.env["TOSTUDY_LOCALE"]) {
|
|
|
23134
23189
|
var { createProgram: createProgram2, CLI_VERSION: CLI_VERSION2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
23135
23190
|
var { checkForUpdates: checkForUpdates2 } = await Promise.resolve().then(() => (init_update_checker(), update_checker_exports));
|
|
23136
23191
|
var { maybeAutoUpdate: maybeAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_updater(), auto_updater_exports));
|
|
23192
|
+
process.on("unhandledRejection", (reason) => {
|
|
23193
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
23194
|
+
process.stderr.write(`Erro: ${msg}
|
|
23195
|
+
Se o problema continuar, rode: tostudy doctor
|
|
23196
|
+
`);
|
|
23197
|
+
process.exit(1);
|
|
23198
|
+
});
|
|
23137
23199
|
var program = createProgram2();
|
|
23138
23200
|
program.parse();
|
|
23139
23201
|
checkForUpdates2(CLI_VERSION2);
|