@tostudy-ai/cli 0.18.13 → 0.18.17
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/main.js +80 -33
- package/dist/main.js.map +4 -4
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2330,6 +2330,7 @@ var init_instruction_template_v3 = __esm({
|
|
|
2330
2330
|
// src/workspace/runtime-registry.ts
|
|
2331
2331
|
var runtime_registry_exports = {};
|
|
2332
2332
|
__export(runtime_registry_exports, {
|
|
2333
|
+
CODEX_LOGIN_NOTICE: () => CODEX_LOGIN_NOTICE,
|
|
2333
2334
|
RUNTIMES: () => RUNTIMES,
|
|
2334
2335
|
antigravitySkillMd: () => antigravitySkillMd,
|
|
2335
2336
|
cursorMdc: () => cursorMdc,
|
|
@@ -2405,10 +2406,10 @@ ${content}`;
|
|
|
2405
2406
|
function detectedSlashHints(slug, home, cwd) {
|
|
2406
2407
|
return RUNTIMES.filter((r) => r.slashHint && r.detect(home, cwd)).map((r) => r.slashHint(slug));
|
|
2407
2408
|
}
|
|
2408
|
-
function slashHintLines(slug, home, cwd
|
|
2409
|
+
function slashHintLines(slug, home, cwd) {
|
|
2409
2410
|
const hints = slug ? detectedSlashHints(slug, home, cwd) : [];
|
|
2410
2411
|
if (hints.length > 0) return hints.map((h) => `\u2192 ${h}`);
|
|
2411
|
-
return [
|
|
2412
|
+
return ["\u2192 Na sua plataforma, pe\xE7a: vamos estudar (no terminal: tostudy menu)"];
|
|
2412
2413
|
}
|
|
2413
2414
|
function needsRootAgentsConsent(cwd) {
|
|
2414
2415
|
const filePath = join2(cwd, "AGENTS.md");
|
|
@@ -2428,7 +2429,7 @@ function upsertRootAgentsBlock(cwd, ctx) {
|
|
|
2428
2429
|
"",
|
|
2429
2430
|
`- **Course:** ${ctx.courseTitle} (${ctx.progress}% complete)`,
|
|
2430
2431
|
`- Read \`.tostudy/courses/${slug}/AGENTS.md\` for the full tutor instructions.`,
|
|
2431
|
-
|
|
2432
|
+
'- To study, ask in plain language (e.g. "vamos estudar"). In Claude Code or OpenCode you can also run `/tostudy`; in the terminal, `tostudy menu`.',
|
|
2432
2433
|
"",
|
|
2433
2434
|
"<!-- tostudy:end -->"
|
|
2434
2435
|
].join("\n");
|
|
@@ -2464,7 +2465,7 @@ function upsertRootAgentsBlock(cwd, ctx) {
|
|
|
2464
2465
|
return null;
|
|
2465
2466
|
}
|
|
2466
2467
|
}
|
|
2467
|
-
var logger2, detectOpencode, detectGrok, detectAntigravity, RUNTIMES, TOSTUDY_BLOCK_PATTERN, TOSTUDY_BLOCK_PATTERN_GLOBAL, slugifyTitle;
|
|
2468
|
+
var logger2, detectOpencode, detectGrok, detectAntigravity, CODEX_LOGIN_NOTICE, RUNTIMES, TOSTUDY_BLOCK_PATTERN, TOSTUDY_BLOCK_PATTERN_GLOBAL, slugifyTitle;
|
|
2468
2469
|
var init_runtime_registry = __esm({
|
|
2469
2470
|
"src/workspace/runtime-registry.ts"() {
|
|
2470
2471
|
"use strict";
|
|
@@ -2476,6 +2477,11 @@ var init_runtime_registry = __esm({
|
|
|
2476
2477
|
detectOpencode = (home) => existsSync2(join2(home, ".opencode")) || existsSync2(join2(home, ".config", "opencode"));
|
|
2477
2478
|
detectGrok = (home) => existsSync2(join2(home, ".grok")) || hasBinary("grok");
|
|
2478
2479
|
detectAntigravity = (home) => existsSync2(join2(home, ".gemini", "antigravity-cli")) || hasBinary("agy");
|
|
2480
|
+
CODEX_LOGIN_NOTICE = [
|
|
2481
|
+
" \u26A0 No Codex n\xE3o existe o comando /tostudy.",
|
|
2482
|
+
' \u2192 Abra o Codex na pasta do curso e pe\xE7a: "vamos estudar".',
|
|
2483
|
+
" \u2192 No terminal, tostudy menu tamb\xE9m funciona."
|
|
2484
|
+
];
|
|
2479
2485
|
RUNTIMES = [
|
|
2480
2486
|
{
|
|
2481
2487
|
id: "claude",
|
|
@@ -2518,11 +2524,15 @@ var init_runtime_registry = __esm({
|
|
|
2518
2524
|
detect: (home) => existsSync2(join2(home, ".codex")),
|
|
2519
2525
|
// No writePerCourse: Codex has no project-level command channel — the
|
|
2520
2526
|
// root AGENTS.md managed block (generic entry) is its per-course path.
|
|
2521
|
-
writeUniversal
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2527
|
+
// GH-2351 follow-up: no writeUniversal either. The hint below already stopped
|
|
2528
|
+
// naming /tostudy, but login still wrote ~10 KB to ~/.codex/prompts/tostudy.md
|
|
2529
|
+
// and printed "✓ Instalado: …/.codex/prompts/tostudy.md" — announcing, as the
|
|
2530
|
+
// last thing on screen, an install of a command that does not exist. Codex
|
|
2531
|
+
// never reads that directory, so nothing consumed the file. A stale one from
|
|
2532
|
+
// an older CLI is left on disk: we do not delete the student's files.
|
|
2533
|
+
// GH-2351: Codex never reads ~/.codex/prompts, so there is no /tostudy there;
|
|
2534
|
+
// asking in plain language works (it reads AGENTS.md and finds the course skill).
|
|
2535
|
+
slashHint: () => "No Codex, abra o Codex e pe\xE7a: vamos estudar"
|
|
2526
2536
|
},
|
|
2527
2537
|
{
|
|
2528
2538
|
id: "opencode",
|
|
@@ -3626,7 +3636,7 @@ var loginCommand = new Command("login").description("Autentica no ToStudy via br
|
|
|
3626
3636
|
try {
|
|
3627
3637
|
const { detectIDEs: detectIDEs2 } = await Promise.resolve().then(() => (init_ide_detector(), ide_detector_exports));
|
|
3628
3638
|
const { installUniversalCommand: installUniversalCommand2 } = await Promise.resolve().then(() => (init_instruction_files(), instruction_files_exports));
|
|
3629
|
-
const { RUNTIMES: RUNTIMES2 } = await Promise.resolve().then(() => (init_runtime_registry(), runtime_registry_exports));
|
|
3639
|
+
const { RUNTIMES: RUNTIMES2, CODEX_LOGIN_NOTICE: CODEX_LOGIN_NOTICE2 } = await Promise.resolve().then(() => (init_runtime_registry(), runtime_registry_exports));
|
|
3630
3640
|
const { homedir: homedir2 } = await import("node:os");
|
|
3631
3641
|
const ides = detectIDEs2();
|
|
3632
3642
|
const detected = ides.filter((ide) => ide.detected);
|
|
@@ -3663,6 +3673,10 @@ var loginCommand = new Command("login").description("Autentica no ToStudy via br
|
|
|
3663
3673
|
);
|
|
3664
3674
|
}
|
|
3665
3675
|
}
|
|
3676
|
+
if (detected.some((ide) => ide.id === "codex")) {
|
|
3677
|
+
console.log("");
|
|
3678
|
+
for (const line of CODEX_LOGIN_NOTICE2) console.log(line);
|
|
3679
|
+
}
|
|
3666
3680
|
} catch {
|
|
3667
3681
|
}
|
|
3668
3682
|
try {
|
|
@@ -3739,27 +3753,57 @@ import { Command as Command3 } from "commander";
|
|
|
3739
3753
|
|
|
3740
3754
|
// src/installer/mcp-setup.ts
|
|
3741
3755
|
import { spawn } from "node:child_process";
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3756
|
+
import { hostname } from "node:os";
|
|
3757
|
+
|
|
3758
|
+
// src/version.ts
|
|
3759
|
+
var CLI_VERSION = true ? "0.18.17" : "0.7.1";
|
|
3760
|
+
|
|
3761
|
+
// src/installer/mcp-setup.ts
|
|
3762
|
+
function safeServerError(text2) {
|
|
3763
|
+
if (typeof text2 !== "string" || text2.length === 0 || text2.length > 200) return null;
|
|
3764
|
+
return ["Bearer", "mcp_", "eyJ"].some((m) => text2.includes(m)) ? null : text2;
|
|
3765
|
+
}
|
|
3766
|
+
async function createMcpApiKey(session, fetchImpl = fetch) {
|
|
3767
|
+
let res;
|
|
3768
|
+
try {
|
|
3769
|
+
res = await fetchImpl(`${session.apiUrl}/api/mcp/sessions`, {
|
|
3770
|
+
method: "POST",
|
|
3771
|
+
headers: {
|
|
3772
|
+
Authorization: `Bearer ${session.token}`,
|
|
3773
|
+
"Content-Type": "application/json"
|
|
3774
|
+
},
|
|
3775
|
+
body: JSON.stringify({
|
|
3776
|
+
clientInfo: {
|
|
3777
|
+
source: "tostudy-cli-setup",
|
|
3778
|
+
hostname: hostname(),
|
|
3779
|
+
os: process.platform,
|
|
3780
|
+
version: CLI_VERSION
|
|
3781
|
+
}
|
|
3782
|
+
})
|
|
3783
|
+
});
|
|
3784
|
+
} catch {
|
|
3785
|
+
throw new Error("Falha ao criar a chave MCP: erro de rede");
|
|
3786
|
+
}
|
|
3749
3787
|
if (!res.ok) {
|
|
3750
3788
|
const body = await res.json().catch(() => ({}));
|
|
3751
|
-
throw new Error(
|
|
3789
|
+
throw new Error(
|
|
3790
|
+
`Falha ao criar a chave MCP: ${safeServerError(body.error) ?? `HTTP ${res.status}`}`
|
|
3791
|
+
);
|
|
3792
|
+
}
|
|
3793
|
+
const { apiKey } = await res.json().catch(() => ({}));
|
|
3794
|
+
if (typeof apiKey !== "string" || !apiKey.startsWith("mcp_")) {
|
|
3795
|
+
throw new Error("Falha ao criar a chave MCP: resposta inv\xE1lida do servidor");
|
|
3752
3796
|
}
|
|
3753
|
-
return
|
|
3797
|
+
return apiKey;
|
|
3754
3798
|
}
|
|
3755
|
-
async function runMcpSetup(session,
|
|
3799
|
+
async function runMcpSetup(session, apiKey, spawnImpl = spawn) {
|
|
3756
3800
|
const command = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
3757
3801
|
await new Promise((resolve, reject) => {
|
|
3758
3802
|
const child = spawnImpl(command, ["-y", "@tostudy-ai/mcp-setup", "--url", session.apiUrl], {
|
|
3759
3803
|
stdio: "inherit",
|
|
3760
3804
|
env: {
|
|
3761
3805
|
...process.env,
|
|
3762
|
-
TOSTUDY_API_KEY:
|
|
3806
|
+
TOSTUDY_API_KEY: apiKey
|
|
3763
3807
|
}
|
|
3764
3808
|
});
|
|
3765
3809
|
child.once("error", reject);
|
|
@@ -3794,8 +3838,15 @@ async function runSetupMcpSubcommand() {
|
|
|
3794
3838
|
const session = await requireSession();
|
|
3795
3839
|
console.log(` \u2713 Logado como ${session.userName}
|
|
3796
3840
|
`);
|
|
3797
|
-
const
|
|
3798
|
-
|
|
3841
|
+
const apiKey = await createMcpApiKey(session);
|
|
3842
|
+
try {
|
|
3843
|
+
await runMcpSetup(session, apiKey);
|
|
3844
|
+
} catch (error49) {
|
|
3845
|
+
console.error(
|
|
3846
|
+
" Instala\xE7\xE3o incompleta: a chave MCP criada aparece em Configura\xE7\xF5es \u203A MCP e pode ser revogada."
|
|
3847
|
+
);
|
|
3848
|
+
throw error49;
|
|
3849
|
+
}
|
|
3799
3850
|
console.log("\n Setup MCP completo!");
|
|
3800
3851
|
console.log(" \u2192 Reinicie o IDE para ativar o servidor MCP");
|
|
3801
3852
|
console.log(" \u2192 tostudy doctor (verificar conex\xE3o)\n");
|
|
@@ -3849,9 +3900,6 @@ init_session_store();
|
|
|
3849
3900
|
init_workspace_state();
|
|
3850
3901
|
init_formatter();
|
|
3851
3902
|
|
|
3852
|
-
// src/version.ts
|
|
3853
|
-
var CLI_VERSION = true ? "0.18.13" : "0.7.1";
|
|
3854
|
-
|
|
3855
3903
|
// src/update-checker.ts
|
|
3856
3904
|
init_config_dir();
|
|
3857
3905
|
import fs8 from "node:fs";
|
|
@@ -5210,7 +5258,6 @@ var selectCommand = new Command8("select").description("Activate a course by ID
|
|
|
5210
5258
|
{ json: true }
|
|
5211
5259
|
);
|
|
5212
5260
|
} else {
|
|
5213
|
-
const slashCmd = courseSlug2 ? `/tostudy-${courseSlug2}` : "/tostudy";
|
|
5214
5261
|
const home = os7.homedir();
|
|
5215
5262
|
const cwd = process.cwd();
|
|
5216
5263
|
const namespacedPath = `${cwd}/.tostudy`;
|
|
@@ -5242,7 +5289,7 @@ var selectCommand = new Command8("select").description("Activate a course by ID
|
|
|
5242
5289
|
lines.push(rootAgentsSkippedHint());
|
|
5243
5290
|
}
|
|
5244
5291
|
lines.push("", "\u2192 Abra sua plataforma (claude, codex, cursor...)");
|
|
5245
|
-
lines.push(...slashHintLines(courseSlug2, home, cwd
|
|
5292
|
+
lines.push(...slashHintLines(courseSlug2, home, cwd));
|
|
5246
5293
|
lines.push("\u2192 Em outras plataformas: tostudy init");
|
|
5247
5294
|
output(lines.join("\n"), { json: false });
|
|
5248
5295
|
}
|
|
@@ -5931,7 +5978,7 @@ __export(external_exports, {
|
|
|
5931
5978
|
guid: () => guid2,
|
|
5932
5979
|
hash: () => hash,
|
|
5933
5980
|
hex: () => hex2,
|
|
5934
|
-
hostname: () =>
|
|
5981
|
+
hostname: () => hostname3,
|
|
5935
5982
|
httpUrl: () => httpUrl,
|
|
5936
5983
|
includes: () => _includes,
|
|
5937
5984
|
instanceof: () => _instanceof,
|
|
@@ -7318,7 +7365,7 @@ __export(regexes_exports, {
|
|
|
7318
7365
|
extendedDuration: () => extendedDuration,
|
|
7319
7366
|
guid: () => guid,
|
|
7320
7367
|
hex: () => hex,
|
|
7321
|
-
hostname: () =>
|
|
7368
|
+
hostname: () => hostname2,
|
|
7322
7369
|
html5Email: () => html5Email,
|
|
7323
7370
|
idnEmail: () => idnEmail,
|
|
7324
7371
|
integer: () => integer,
|
|
@@ -7395,7 +7442,7 @@ var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]
|
|
|
7395
7442
|
var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
7396
7443
|
var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
7397
7444
|
var base64url = /^[A-Za-z0-9_-]*$/;
|
|
7398
|
-
var
|
|
7445
|
+
var hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
7399
7446
|
var domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
7400
7447
|
var e164 = /^\+[1-9]\d{6,14}$/;
|
|
7401
7448
|
var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
|
|
@@ -17765,7 +17812,7 @@ __export(schemas_exports2, {
|
|
|
17765
17812
|
guid: () => guid2,
|
|
17766
17813
|
hash: () => hash,
|
|
17767
17814
|
hex: () => hex2,
|
|
17768
|
-
hostname: () =>
|
|
17815
|
+
hostname: () => hostname3,
|
|
17769
17816
|
httpUrl: () => httpUrl,
|
|
17770
17817
|
instanceof: () => _instanceof,
|
|
17771
17818
|
int: () => int,
|
|
@@ -18269,7 +18316,7 @@ var ZodCustomStringFormat = /* @__PURE__ */ $constructor("ZodCustomStringFormat"
|
|
|
18269
18316
|
function stringFormat(format, fnOrRegex, _params = {}) {
|
|
18270
18317
|
return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
|
|
18271
18318
|
}
|
|
18272
|
-
function
|
|
18319
|
+
function hostname3(_params) {
|
|
18273
18320
|
return _stringFormat(ZodCustomStringFormat, "hostname", regexes_exports.hostname, _params);
|
|
18274
18321
|
}
|
|
18275
18322
|
function hex2(_params) {
|