@tostudy-ai/mcp-setup 1.0.2 → 1.1.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/README.md +1 -1
- package/dist/__tests__/e2e-wizard-flow.test.d.ts.map +1 -1
- package/dist/__tests__/e2e-wizard-flow.test.js +128 -117
- package/dist/__tests__/e2e-wizard-flow.test.js.map +1 -1
- package/dist/__tests__/ide-handlers.test.js +15 -11
- package/dist/__tests__/ide-handlers.test.js.map +1 -1
- package/dist/__tests__/install-command.test.js +106 -95
- package/dist/__tests__/install-command.test.js.map +1 -1
- package/dist/config.d.ts +15 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +79 -29
- package/dist/config.js.map +1 -1
- package/dist/diagnose.d.ts +1 -1
- package/dist/diagnose.d.ts.map +1 -1
- package/dist/diagnose.js +154 -164
- package/dist/diagnose.js.map +1 -1
- package/dist/ide-handlers/antigravity.js +1 -1
- package/dist/ide-handlers/antigravity.js.map +1 -1
- package/dist/ide-handlers/base.d.ts +8 -8
- package/dist/ide-handlers/base.d.ts.map +1 -1
- package/dist/ide-handlers/base.js +29 -4
- package/dist/ide-handlers/base.js.map +1 -1
- package/dist/ide-handlers/claude-code.js +1 -1
- package/dist/ide-handlers/claude-code.js.map +1 -1
- package/dist/ide-handlers/codex.js +1 -1
- package/dist/ide-handlers/codex.js.map +1 -1
- package/dist/ide-handlers/cursor.js +1 -1
- package/dist/ide-handlers/cursor.js.map +1 -1
- package/dist/ide-handlers/desktop.d.ts +3 -3
- package/dist/ide-handlers/desktop.d.ts.map +1 -1
- package/dist/ide-handlers/desktop.js +32 -8
- package/dist/ide-handlers/desktop.js.map +1 -1
- package/dist/ide-handlers/manual.js +1 -1
- package/dist/ide-handlers/manual.js.map +1 -1
- package/dist/ide-handlers/opencode.js +1 -1
- package/dist/ide-handlers/opencode.js.map +1 -1
- package/dist/ide-handlers/vscode.js +1 -1
- package/dist/ide-handlers/vscode.js.map +1 -1
- package/dist/ide-handlers/windsurf.js +1 -1
- package/dist/ide-handlers/windsurf.js.map +1 -1
- package/dist/index.js +198 -156
- package/dist/index.js.map +1 -1
- package/dist/repair.d.ts +1 -1
- package/dist/repair.d.ts.map +1 -1
- package/dist/repair.js +213 -168
- package/dist/repair.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
* npx @tostudy-ai/mcp-setup --api-key <key>
|
|
11
11
|
* npx @tostudy-ai/mcp-setup --uninstall
|
|
12
12
|
*/
|
|
13
|
-
import { program } from
|
|
14
|
-
import chalk from
|
|
15
|
-
import { getClaudeConfigPath, isClaudeInstalled, addTostudyMcpServer, removeTostudyMcpServer, isTostudyMcpConfigured, } from
|
|
16
|
-
import { promptApiKey, confirm } from
|
|
17
|
-
import { getInstalledIDEs } from
|
|
18
|
-
import { runDiagnostics, printDiagnosticReport } from
|
|
19
|
-
import { repairAllIssues, printRepairReport } from
|
|
20
|
-
import { getIDEHandler } from
|
|
21
|
-
const VERSION =
|
|
22
|
-
const DEFAULT_PLATFORM_URL =
|
|
23
|
-
function println(message =
|
|
13
|
+
import { program } from "commander";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { getClaudeConfigPath, isClaudeInstalled, addTostudyMcpServer, removeTostudyMcpServer, isTostudyMcpConfigured, } from "./config.js";
|
|
16
|
+
import { promptApiKey, confirm } from "./prompts.js";
|
|
17
|
+
import { getInstalledIDEs } from "./detect.js";
|
|
18
|
+
import { runDiagnostics, printDiagnosticReport } from "./diagnose.js";
|
|
19
|
+
import { repairAllIssues, printRepairReport } from "./repair.js";
|
|
20
|
+
import { getIDEHandler } from "./ide-handlers/index.js";
|
|
21
|
+
const VERSION = "1.0.0";
|
|
22
|
+
const DEFAULT_PLATFORM_URL = "https://tostudy.com";
|
|
23
|
+
function println(message = "") {
|
|
24
24
|
process.stdout.write(`${message}\n`);
|
|
25
25
|
}
|
|
26
|
-
function eprintln(message =
|
|
26
|
+
function eprintln(message = "") {
|
|
27
27
|
process.stderr.write(`${message}\n`);
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -31,9 +31,9 @@ function eprintln(message = '') {
|
|
|
31
31
|
*/
|
|
32
32
|
function printBanner() {
|
|
33
33
|
println();
|
|
34
|
-
println(chalk.cyan(
|
|
35
|
-
println(chalk.cyan(
|
|
36
|
-
println(chalk.cyan(
|
|
34
|
+
println(chalk.cyan(" ╔═══════════════════════════════════════╗"));
|
|
35
|
+
println(chalk.cyan(" ║") + chalk.white.bold(" Catalyst MCP Setup ") + chalk.cyan("║"));
|
|
36
|
+
println(chalk.cyan(" ╚═══════════════════════════════════════╝"));
|
|
37
37
|
println();
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -42,10 +42,10 @@ function printBanner() {
|
|
|
42
42
|
async function validateApiKey(apiKey, platformUrl) {
|
|
43
43
|
try {
|
|
44
44
|
const response = await fetch(`${platformUrl}/api/mcp/heartbeat`, {
|
|
45
|
-
method:
|
|
45
|
+
method: "POST",
|
|
46
46
|
headers: {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
Authorization: `Bearer ${apiKey}`,
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
49
|
},
|
|
50
50
|
body: JSON.stringify({ timestamp: new Date().toISOString() }),
|
|
51
51
|
});
|
|
@@ -53,8 +53,8 @@ async function validateApiKey(apiKey, platformUrl) {
|
|
|
53
53
|
}
|
|
54
54
|
catch {
|
|
55
55
|
// Network error - can't validate, but allow anyway for offline setup
|
|
56
|
-
println(chalk.yellow(
|
|
57
|
-
println(chalk.yellow(
|
|
56
|
+
println(chalk.yellow("! Nao foi possivel validar a API key (servidor offline?)"));
|
|
57
|
+
println(chalk.yellow(" A configuracao sera salva mesmo assim."));
|
|
58
58
|
return true;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -65,10 +65,10 @@ async function setup(apiKey, platformUrl) {
|
|
|
65
65
|
printBanner();
|
|
66
66
|
// Check if Claude Code is installed
|
|
67
67
|
if (!isClaudeInstalled()) {
|
|
68
|
-
println(chalk.red(
|
|
68
|
+
println(chalk.red("X Claude Code nao encontrado."));
|
|
69
69
|
println();
|
|
70
|
-
println(
|
|
71
|
-
println(chalk.cyan(
|
|
70
|
+
println(" Por favor, instale o Claude Code primeiro:");
|
|
71
|
+
println(chalk.cyan(" https://claude.ai/download"));
|
|
72
72
|
println();
|
|
73
73
|
process.exit(1);
|
|
74
74
|
}
|
|
@@ -77,53 +77,62 @@ async function setup(apiKey, platformUrl) {
|
|
|
77
77
|
println();
|
|
78
78
|
// Check if already configured
|
|
79
79
|
if (isTostudyMcpConfigured()) {
|
|
80
|
-
println(chalk.yellow(
|
|
81
|
-
const overwrite = await confirm(
|
|
80
|
+
println(chalk.yellow("! Catalyst MCP ja esta configurado."));
|
|
81
|
+
const overwrite = await confirm("Deseja reconfigurar?", false);
|
|
82
82
|
if (!overwrite) {
|
|
83
|
-
println(chalk.gray(
|
|
83
|
+
println(chalk.gray("Operacao cancelada."));
|
|
84
84
|
process.exit(0);
|
|
85
85
|
}
|
|
86
86
|
println();
|
|
87
87
|
}
|
|
88
88
|
// Get API key
|
|
89
|
-
const key = apiKey || process.env.TOSTUDY_API_KEY || await promptApiKey();
|
|
89
|
+
const key = apiKey || process.env.TOSTUDY_API_KEY || (await promptApiKey());
|
|
90
90
|
const url = platformUrl || process.env.TOSTUDY_PLATFORM_URL || DEFAULT_PLATFORM_URL;
|
|
91
91
|
// Validate API key
|
|
92
92
|
println();
|
|
93
|
-
process.stdout.write(chalk.gray(
|
|
93
|
+
process.stdout.write(chalk.gray("Validando API key... "));
|
|
94
94
|
const valid = await validateApiKey(key, url);
|
|
95
95
|
if (!valid) {
|
|
96
|
-
println(chalk.red(
|
|
96
|
+
println(chalk.red("FALHOU"));
|
|
97
97
|
println();
|
|
98
|
-
println(chalk.red(
|
|
98
|
+
println(chalk.red("API key invalida ou expirada."));
|
|
99
99
|
println();
|
|
100
|
-
println(
|
|
100
|
+
println("Para gerar uma nova API key:");
|
|
101
101
|
println(chalk.cyan(` ${url}/student/settings/mcp`));
|
|
102
102
|
println();
|
|
103
103
|
process.exit(1);
|
|
104
104
|
}
|
|
105
|
-
println(chalk.green(
|
|
105
|
+
println(chalk.green("OK"));
|
|
106
106
|
// Configure Claude Code
|
|
107
|
-
process.stdout.write(chalk.gray(
|
|
107
|
+
process.stdout.write(chalk.gray("Configurando Claude Code... "));
|
|
108
108
|
try {
|
|
109
109
|
addTostudyMcpServer(key, url);
|
|
110
|
-
println(chalk.green(
|
|
110
|
+
println(chalk.green("OK"));
|
|
111
111
|
}
|
|
112
112
|
catch (error) {
|
|
113
|
-
println(chalk.red(
|
|
113
|
+
println(chalk.red("FALHOU"));
|
|
114
114
|
eprintln();
|
|
115
|
-
eprintln(chalk.red(
|
|
115
|
+
eprintln(chalk.red("Erro ao salvar configuracao:"));
|
|
116
116
|
eprintln(error instanceof Error ? error.message : String(error));
|
|
117
117
|
process.exit(1);
|
|
118
118
|
}
|
|
119
119
|
// Success
|
|
120
120
|
println();
|
|
121
|
-
println(chalk.green.bold(
|
|
121
|
+
println(chalk.green.bold("Configuracao concluida!"));
|
|
122
122
|
println();
|
|
123
|
-
println(chalk.white(
|
|
124
|
-
println(chalk.gray(
|
|
125
|
-
println(chalk.gray(
|
|
126
|
-
println(chalk.gray(
|
|
123
|
+
println(chalk.white("Proximos passos:"));
|
|
124
|
+
println(chalk.gray(" 1.") + " Reinicie o Claude Code");
|
|
125
|
+
println(chalk.gray(" 2.") + " O servidor MCP iniciara automaticamente");
|
|
126
|
+
println(chalk.gray(" 3.") + " Use " + chalk.cyan("/courses") + " para ver seus cursos");
|
|
127
|
+
println();
|
|
128
|
+
println(chalk.gray(" ─────────────────────────────────────────"));
|
|
129
|
+
println();
|
|
130
|
+
println(chalk.white(" Prefere estudar pelo terminal?"));
|
|
131
|
+
println(chalk.gray(" ") + chalk.cyan("npm install -g @tostudy-ai/cli"));
|
|
132
|
+
println(chalk.gray(" ") +
|
|
133
|
+
chalk.cyan("tostudy login") +
|
|
134
|
+
chalk.gray(" → ") +
|
|
135
|
+
chalk.cyan("tostudy courses"));
|
|
127
136
|
println();
|
|
128
137
|
}
|
|
129
138
|
/**
|
|
@@ -132,25 +141,25 @@ async function setup(apiKey, platformUrl) {
|
|
|
132
141
|
async function uninstall() {
|
|
133
142
|
printBanner();
|
|
134
143
|
if (!isTostudyMcpConfigured()) {
|
|
135
|
-
println(chalk.yellow(
|
|
144
|
+
println(chalk.yellow("Catalyst MCP nao esta configurado."));
|
|
136
145
|
process.exit(0);
|
|
137
146
|
}
|
|
138
|
-
const shouldUninstall = await confirm(
|
|
147
|
+
const shouldUninstall = await confirm("Remover configuracao do Catalyst MCP?", false);
|
|
139
148
|
if (!shouldUninstall) {
|
|
140
|
-
println(chalk.gray(
|
|
149
|
+
println(chalk.gray("Operacao cancelada."));
|
|
141
150
|
process.exit(0);
|
|
142
151
|
}
|
|
143
|
-
process.stdout.write(chalk.gray(
|
|
152
|
+
process.stdout.write(chalk.gray("Removendo configuracao... "));
|
|
144
153
|
try {
|
|
145
154
|
removeTostudyMcpServer();
|
|
146
|
-
println(chalk.green(
|
|
155
|
+
println(chalk.green("OK"));
|
|
147
156
|
println();
|
|
148
|
-
println(chalk.green(
|
|
149
|
-
println(chalk.gray(
|
|
157
|
+
println(chalk.green("Configuracao removida com sucesso."));
|
|
158
|
+
println(chalk.gray("Reinicie o Claude Code para aplicar as mudancas."));
|
|
150
159
|
println();
|
|
151
160
|
}
|
|
152
161
|
catch (error) {
|
|
153
|
-
println(chalk.red(
|
|
162
|
+
println(chalk.red("FALHOU"));
|
|
154
163
|
eprintln(error instanceof Error ? error.message : String(error));
|
|
155
164
|
process.exit(1);
|
|
156
165
|
}
|
|
@@ -168,14 +177,14 @@ function printStep(step, total, title) {
|
|
|
168
177
|
*/
|
|
169
178
|
function printIDEDetection(installedIDEs) {
|
|
170
179
|
if (installedIDEs.length === 0) {
|
|
171
|
-
println(chalk.yellow(
|
|
172
|
-
println(chalk.gray(
|
|
180
|
+
println(chalk.yellow(" Nenhuma IDE suportada detectada."));
|
|
181
|
+
println(chalk.gray(" O setup continuara para Claude Code."));
|
|
173
182
|
}
|
|
174
183
|
else {
|
|
175
|
-
println(chalk.green(
|
|
184
|
+
println(chalk.green(" IDEs detectadas:"));
|
|
176
185
|
for (const ide of installedIDEs) {
|
|
177
|
-
const version = ide.version ? chalk.gray(` (${ide.version})`) :
|
|
178
|
-
println(` ${chalk.green(
|
|
186
|
+
const version = ide.version ? chalk.gray(` (${ide.version})`) : "";
|
|
187
|
+
println(` ${chalk.green("✓")} ${ide.name}${version}`);
|
|
179
188
|
}
|
|
180
189
|
}
|
|
181
190
|
}
|
|
@@ -187,122 +196,127 @@ async function wizard(options) {
|
|
|
187
196
|
const TOTAL_STEPS = 4;
|
|
188
197
|
// Print wizard banner
|
|
189
198
|
println();
|
|
190
|
-
println(chalk.cyan(
|
|
191
|
-
println(chalk.cyan(
|
|
192
|
-
|
|
193
|
-
|
|
199
|
+
println(chalk.cyan(" ╔═══════════════════════════════════════════════╗"));
|
|
200
|
+
println(chalk.cyan(" ║") +
|
|
201
|
+
chalk.white.bold(" Catalyst MCP Setup Wizard ") +
|
|
202
|
+
chalk.cyan("║"));
|
|
203
|
+
println(chalk.cyan(" ║") + chalk.gray(" Configuracao guiada passo a passo ") + chalk.cyan("║"));
|
|
204
|
+
println(chalk.cyan(" ╚═══════════════════════════════════════════════╝"));
|
|
194
205
|
println();
|
|
195
|
-
println(chalk.gray(
|
|
196
|
-
println(chalk.gray(
|
|
206
|
+
println(chalk.gray(" Este assistente vai configurar o Claude Code para"));
|
|
207
|
+
println(chalk.gray(" conectar ao servidor MCP da plataforma Catalyst."));
|
|
197
208
|
println();
|
|
198
209
|
// ━━━ Step 1: Environment Detection ━━━
|
|
199
|
-
printStep(1, TOTAL_STEPS,
|
|
210
|
+
printStep(1, TOTAL_STEPS, "Detectando ambiente");
|
|
200
211
|
// Check Claude Code
|
|
201
|
-
process.stdout.write(
|
|
212
|
+
process.stdout.write(" Verificando Claude Code... ");
|
|
202
213
|
if (!isClaudeInstalled()) {
|
|
203
|
-
println(chalk.red(
|
|
214
|
+
println(chalk.red("NAO ENCONTRADO"));
|
|
204
215
|
println();
|
|
205
|
-
println(chalk.red(
|
|
216
|
+
println(chalk.red(" Claude Code nao esta instalado."));
|
|
206
217
|
println();
|
|
207
|
-
println(
|
|
208
|
-
println(chalk.cyan(
|
|
218
|
+
println(" Por favor, instale primeiro:");
|
|
219
|
+
println(chalk.cyan(" https://claude.ai/download"));
|
|
209
220
|
println();
|
|
210
221
|
process.exit(1);
|
|
211
222
|
}
|
|
212
|
-
println(chalk.green(
|
|
223
|
+
println(chalk.green("OK"));
|
|
213
224
|
const configPath = getClaudeConfigPath();
|
|
214
225
|
println(chalk.gray(` Config: ${configPath}`));
|
|
215
226
|
// Check for other IDEs
|
|
216
|
-
process.stdout.write(
|
|
227
|
+
process.stdout.write(" Detectando IDEs... ");
|
|
217
228
|
const installedIDEs = getInstalledIDEs();
|
|
218
|
-
println(chalk.green(
|
|
229
|
+
println(chalk.green("OK"));
|
|
219
230
|
printIDEDetection(installedIDEs);
|
|
220
231
|
// Check existing configuration
|
|
221
|
-
process.stdout.write(
|
|
232
|
+
process.stdout.write(" Verificando configuracao atual... ");
|
|
222
233
|
const alreadyConfigured = isTostudyMcpConfigured();
|
|
223
234
|
if (alreadyConfigured) {
|
|
224
|
-
println(chalk.yellow(
|
|
235
|
+
println(chalk.yellow("JA CONFIGURADO"));
|
|
225
236
|
println();
|
|
226
|
-
const overwrite = await confirm(
|
|
237
|
+
const overwrite = await confirm(" Deseja reconfigurar?", false);
|
|
227
238
|
if (!overwrite) {
|
|
228
239
|
println();
|
|
229
|
-
println(chalk.gray(
|
|
240
|
+
println(chalk.gray(" Operacao cancelada."));
|
|
230
241
|
process.exit(0);
|
|
231
242
|
}
|
|
232
243
|
}
|
|
233
244
|
else {
|
|
234
|
-
println(chalk.gray(
|
|
245
|
+
println(chalk.gray("Nao configurado"));
|
|
235
246
|
}
|
|
236
247
|
// ━━━ Step 2: API Key Configuration ━━━
|
|
237
|
-
printStep(2, TOTAL_STEPS,
|
|
238
|
-
println(chalk.gray(
|
|
248
|
+
printStep(2, TOTAL_STEPS, "Configurando API Key");
|
|
249
|
+
println(chalk.gray(" A API key conecta o Claude Code a sua conta na plataforma."));
|
|
239
250
|
println();
|
|
240
251
|
let apiKey = options.apiKey || process.env.TOSTUDY_API_KEY;
|
|
241
252
|
if (!apiKey) {
|
|
242
|
-
println(
|
|
253
|
+
println(" Acesse sua API key em:");
|
|
243
254
|
println(chalk.cyan(` ${options.url || DEFAULT_PLATFORM_URL}/student/settings/mcp`));
|
|
244
255
|
println();
|
|
245
256
|
apiKey = await promptApiKey();
|
|
246
257
|
}
|
|
247
258
|
else {
|
|
248
|
-
println(chalk.green(
|
|
259
|
+
println(chalk.green(" ✓ API key fornecida via parametro ou ambiente"));
|
|
249
260
|
}
|
|
250
261
|
const platformUrl = options.url || process.env.TOSTUDY_PLATFORM_URL || DEFAULT_PLATFORM_URL;
|
|
251
262
|
// Validate API key
|
|
252
263
|
println();
|
|
253
|
-
process.stdout.write(chalk.gray(
|
|
264
|
+
process.stdout.write(chalk.gray(" Validando API key... "));
|
|
254
265
|
const valid = await validateApiKey(apiKey, platformUrl);
|
|
255
266
|
if (!valid) {
|
|
256
|
-
println(chalk.red(
|
|
267
|
+
println(chalk.red("FALHOU"));
|
|
257
268
|
println();
|
|
258
|
-
println(chalk.red(
|
|
269
|
+
println(chalk.red(" API key invalida ou expirada."));
|
|
259
270
|
println();
|
|
260
|
-
println(
|
|
271
|
+
println(" Para gerar uma nova API key:");
|
|
261
272
|
println(chalk.cyan(` ${platformUrl}/student/settings/mcp`));
|
|
262
273
|
println();
|
|
263
274
|
process.exit(1);
|
|
264
275
|
}
|
|
265
|
-
println(chalk.green(
|
|
276
|
+
println(chalk.green("OK"));
|
|
266
277
|
// ━━━ Step 3: Save Configuration ━━━
|
|
267
|
-
printStep(3, TOTAL_STEPS,
|
|
268
|
-
process.stdout.write(
|
|
278
|
+
printStep(3, TOTAL_STEPS, "Salvando configuracao");
|
|
279
|
+
process.stdout.write(" Configurando Claude Code... ");
|
|
269
280
|
try {
|
|
270
281
|
addTostudyMcpServer(apiKey, platformUrl);
|
|
271
|
-
println(chalk.green(
|
|
282
|
+
println(chalk.green("OK"));
|
|
272
283
|
}
|
|
273
284
|
catch (error) {
|
|
274
|
-
println(chalk.red(
|
|
285
|
+
println(chalk.red("FALHOU"));
|
|
275
286
|
eprintln();
|
|
276
|
-
eprintln(chalk.red(
|
|
277
|
-
eprintln(
|
|
287
|
+
eprintln(chalk.red(" Erro ao salvar configuracao:"));
|
|
288
|
+
eprintln(" " + (error instanceof Error ? error.message : String(error)));
|
|
278
289
|
process.exit(1);
|
|
279
290
|
}
|
|
280
291
|
// ━━━ Step 4: Diagnostics & Verification ━━━
|
|
281
|
-
printStep(4, TOTAL_STEPS,
|
|
292
|
+
printStep(4, TOTAL_STEPS, "Verificacao final");
|
|
282
293
|
if (!options.skipDiagnostics) {
|
|
283
|
-
process.stdout.write(
|
|
294
|
+
process.stdout.write(" Executando diagnostico... ");
|
|
284
295
|
const report = await runDiagnostics();
|
|
285
|
-
println(chalk.green(
|
|
296
|
+
println(chalk.green("OK"));
|
|
286
297
|
println();
|
|
287
298
|
// Filter out expected issues that we just fixed
|
|
288
|
-
const remainingIssues = report.issues.filter((issue) => ![
|
|
299
|
+
const remainingIssues = report.issues.filter((issue) => !["mcp-not-configured", "config-missing"].includes(issue.id));
|
|
289
300
|
if (remainingIssues.length > 0) {
|
|
290
|
-
println(chalk.yellow(
|
|
301
|
+
println(chalk.yellow(" Avisos encontrados:"));
|
|
291
302
|
for (const issue of remainingIssues) {
|
|
292
|
-
const icon = issue.severity ===
|
|
293
|
-
|
|
303
|
+
const icon = issue.severity === "critical"
|
|
304
|
+
? chalk.red("●")
|
|
305
|
+
: issue.severity === "warning"
|
|
306
|
+
? chalk.yellow("●")
|
|
307
|
+
: chalk.blue("●");
|
|
294
308
|
println(` ${icon} ${issue.title}`);
|
|
295
309
|
}
|
|
296
310
|
println();
|
|
297
311
|
// Auto-repair if enabled
|
|
298
312
|
if (options.autoRepair) {
|
|
299
|
-
process.stdout.write(
|
|
313
|
+
process.stdout.write(" Tentando reparar automaticamente... ");
|
|
300
314
|
const repairReport = repairAllIssues(report, apiKey, platformUrl);
|
|
301
315
|
if (repairReport.repairsSucceeded > 0) {
|
|
302
316
|
println(chalk.green(`${repairReport.repairsSucceeded} corrigido(s)`));
|
|
303
317
|
}
|
|
304
318
|
else {
|
|
305
|
-
println(chalk.yellow(
|
|
319
|
+
println(chalk.yellow("Nenhum reparo aplicado"));
|
|
306
320
|
}
|
|
307
321
|
}
|
|
308
322
|
else {
|
|
@@ -310,39 +324,54 @@ async function wizard(options) {
|
|
|
310
324
|
}
|
|
311
325
|
}
|
|
312
326
|
else {
|
|
313
|
-
println(chalk.green(
|
|
327
|
+
println(chalk.green(" ✓ Nenhum problema encontrado!"));
|
|
314
328
|
}
|
|
315
329
|
}
|
|
316
330
|
else {
|
|
317
|
-
println(chalk.gray(
|
|
331
|
+
println(chalk.gray(" Diagnostico ignorado (--skip-diagnostics)"));
|
|
318
332
|
}
|
|
319
333
|
// ━━━ Success ━━━
|
|
320
334
|
println();
|
|
321
|
-
println(chalk.green(
|
|
322
|
-
println(chalk.green(
|
|
323
|
-
|
|
335
|
+
println(chalk.green(" ╔═══════════════════════════════════════════════╗"));
|
|
336
|
+
println(chalk.green(" ║") +
|
|
337
|
+
chalk.white.bold(" Configuracao concluida com sucesso! ") +
|
|
338
|
+
chalk.green("║"));
|
|
339
|
+
println(chalk.green(" ╚═══════════════════════════════════════════════╝"));
|
|
340
|
+
println();
|
|
341
|
+
println(chalk.white(" Proximos passos:"));
|
|
342
|
+
println();
|
|
343
|
+
println(chalk.gray(" 1.") + " Reinicie o Claude Code");
|
|
344
|
+
println(chalk.gray(" 2.") + " O servidor MCP iniciara automaticamente");
|
|
345
|
+
println(chalk.gray(" 3.") + " Use " + chalk.cyan("/courses") + " para ver seus cursos");
|
|
324
346
|
println();
|
|
325
|
-
println(chalk.
|
|
347
|
+
println(chalk.gray(" Comandos uteis:"));
|
|
348
|
+
println(chalk.gray(" ") +
|
|
349
|
+
chalk.cyan("npx @tostudy-ai/mcp-setup diagnose") +
|
|
350
|
+
chalk.gray(" - Verificar problemas"));
|
|
351
|
+
println(chalk.gray(" ") +
|
|
352
|
+
chalk.cyan("npx @tostudy-ai/mcp-setup repair") +
|
|
353
|
+
chalk.gray(" - Reparar automaticamente"));
|
|
326
354
|
println();
|
|
327
|
-
println(chalk.gray(
|
|
328
|
-
println(chalk.gray(' 2.') + ' O servidor MCP iniciara automaticamente');
|
|
329
|
-
println(chalk.gray(' 3.') + ' Use ' + chalk.cyan('/courses') + ' para ver seus cursos');
|
|
355
|
+
println(chalk.gray(" ─────────────────────────────────────────"));
|
|
330
356
|
println();
|
|
331
|
-
println(chalk.
|
|
332
|
-
println(chalk.gray(
|
|
333
|
-
println(chalk.gray(
|
|
357
|
+
println(chalk.white(" Prefere estudar pelo terminal?"));
|
|
358
|
+
println(chalk.gray(" ") + chalk.cyan("npm install -g @tostudy-ai/cli"));
|
|
359
|
+
println(chalk.gray(" ") +
|
|
360
|
+
chalk.cyan("tostudy login") +
|
|
361
|
+
chalk.gray(" → ") +
|
|
362
|
+
chalk.cyan("tostudy courses"));
|
|
334
363
|
println();
|
|
335
364
|
}
|
|
336
365
|
// CLI setup
|
|
337
366
|
program
|
|
338
|
-
.name(
|
|
339
|
-
.description(
|
|
367
|
+
.name("tostudy-mcp-setup")
|
|
368
|
+
.description("Configura o Claude Code para usar o Catalyst MCP server")
|
|
340
369
|
.version(VERSION);
|
|
341
370
|
// Default command (setup)
|
|
342
371
|
program
|
|
343
|
-
.option(
|
|
344
|
-
.option(
|
|
345
|
-
.option(
|
|
372
|
+
.option("-k, --api-key <key>", "API key da plataforma Catalyst")
|
|
373
|
+
.option("-u, --url <url>", "URL da plataforma (default: https://tostudy.com)")
|
|
374
|
+
.option("--uninstall", "Remove a configuracao do Catalyst MCP")
|
|
346
375
|
.action(async (options) => {
|
|
347
376
|
try {
|
|
348
377
|
if (options.uninstall) {
|
|
@@ -354,18 +383,18 @@ program
|
|
|
354
383
|
}
|
|
355
384
|
catch (error) {
|
|
356
385
|
eprintln();
|
|
357
|
-
eprintln(chalk.red(
|
|
386
|
+
eprintln(chalk.red("Erro:") + " " + (error instanceof Error ? error.message : String(error)));
|
|
358
387
|
process.exit(1);
|
|
359
388
|
}
|
|
360
389
|
});
|
|
361
390
|
// Wizard command - interactive step-by-step setup
|
|
362
391
|
program
|
|
363
|
-
.command(
|
|
364
|
-
.description(
|
|
365
|
-
.option(
|
|
366
|
-
.option(
|
|
367
|
-
.option(
|
|
368
|
-
.option(
|
|
392
|
+
.command("wizard")
|
|
393
|
+
.description("Assistente interativo de configuracao passo a passo")
|
|
394
|
+
.option("-k, --api-key <key>", "API key da plataforma Catalyst")
|
|
395
|
+
.option("-u, --url <url>", "URL da plataforma (default: https://tostudy.com)")
|
|
396
|
+
.option("--skip-diagnostics", "Pula a verificacao de diagnostico apos setup")
|
|
397
|
+
.option("--auto-repair", "Tenta reparar problemas automaticamente")
|
|
369
398
|
.action(async (options) => {
|
|
370
399
|
try {
|
|
371
400
|
await wizard({
|
|
@@ -377,15 +406,15 @@ program
|
|
|
377
406
|
}
|
|
378
407
|
catch (error) {
|
|
379
408
|
eprintln();
|
|
380
|
-
eprintln(chalk.red(
|
|
409
|
+
eprintln(chalk.red("Erro:") + " " + (error instanceof Error ? error.message : String(error)));
|
|
381
410
|
process.exit(1);
|
|
382
411
|
}
|
|
383
412
|
});
|
|
384
413
|
// Diagnose command
|
|
385
414
|
program
|
|
386
|
-
.command(
|
|
387
|
-
.description(
|
|
388
|
-
.option(
|
|
415
|
+
.command("diagnose")
|
|
416
|
+
.description("Executa diagnostico de problemas na configuracao MCP")
|
|
417
|
+
.option("--json", "Saida em formato JSON")
|
|
389
418
|
.action(async (options) => {
|
|
390
419
|
try {
|
|
391
420
|
const report = await runDiagnostics();
|
|
@@ -399,18 +428,18 @@ program
|
|
|
399
428
|
}
|
|
400
429
|
catch (error) {
|
|
401
430
|
eprintln();
|
|
402
|
-
eprintln(chalk.red(
|
|
431
|
+
eprintln(chalk.red("Erro ao executar diagnostico:"));
|
|
403
432
|
eprintln(error instanceof Error ? error.message : String(error));
|
|
404
433
|
process.exit(1);
|
|
405
434
|
}
|
|
406
435
|
});
|
|
407
436
|
// Repair command
|
|
408
437
|
program
|
|
409
|
-
.command(
|
|
410
|
-
.description(
|
|
411
|
-
.option(
|
|
412
|
-
.option(
|
|
413
|
-
.option(
|
|
438
|
+
.command("repair")
|
|
439
|
+
.description("Repara problemas de configuracao automaticamente")
|
|
440
|
+
.option("-k, --api-key <key>", "API key para reparos que necessitam autenticacao")
|
|
441
|
+
.option("-u, --url <url>", "URL da plataforma (default: https://tostudy.com)")
|
|
442
|
+
.option("--json", "Saida em formato JSON")
|
|
414
443
|
.action(async (options) => {
|
|
415
444
|
try {
|
|
416
445
|
const apiKey = options.apiKey || process.env.TOSTUDY_API_KEY;
|
|
@@ -423,30 +452,41 @@ program
|
|
|
423
452
|
else {
|
|
424
453
|
printRepairReport(repair);
|
|
425
454
|
}
|
|
426
|
-
const hasUnfixedCritical = diagnostic.issues.some((issue) => issue.severity ===
|
|
455
|
+
const hasUnfixedCritical = diagnostic.issues.some((issue) => issue.severity === "critical" &&
|
|
456
|
+
!repair.results.find((r) => r.issueId === issue.id && r.success));
|
|
427
457
|
process.exit(hasUnfixedCritical ? 1 : 0);
|
|
428
458
|
}
|
|
429
459
|
catch (error) {
|
|
430
460
|
eprintln();
|
|
431
|
-
eprintln(chalk.red(
|
|
461
|
+
eprintln(chalk.red("Erro ao executar reparo:"));
|
|
432
462
|
eprintln(error instanceof Error ? error.message : String(error));
|
|
433
463
|
process.exit(1);
|
|
434
464
|
}
|
|
435
465
|
});
|
|
436
466
|
// Install command - non-interactive, used by the web wizard's npx command
|
|
437
|
-
const SUPPORTED_IDES = [
|
|
467
|
+
const SUPPORTED_IDES = [
|
|
468
|
+
"claude-code",
|
|
469
|
+
"cursor",
|
|
470
|
+
"vscode",
|
|
471
|
+
"desktop",
|
|
472
|
+
"windsurf",
|
|
473
|
+
"opencode",
|
|
474
|
+
"codex",
|
|
475
|
+
"antigravity",
|
|
476
|
+
"manual",
|
|
477
|
+
];
|
|
438
478
|
program
|
|
439
|
-
.command(
|
|
440
|
-
.description(
|
|
441
|
-
.requiredOption(
|
|
442
|
-
.requiredOption(
|
|
443
|
-
.option(
|
|
479
|
+
.command("install")
|
|
480
|
+
.description("Install MCP config for a specific IDE (used by the web setup wizard)")
|
|
481
|
+
.requiredOption("--ide <ide>", `Target IDE: ${SUPPORTED_IDES.join(", ")}`)
|
|
482
|
+
.requiredOption("--key <key>", "API key from the platform")
|
|
483
|
+
.option("--url <url>", "Platform URL (default: https://tostudy.com)", DEFAULT_PLATFORM_URL)
|
|
444
484
|
.action(async (options) => {
|
|
445
485
|
try {
|
|
446
486
|
const ide = options.ide;
|
|
447
487
|
if (!SUPPORTED_IDES.includes(ide)) {
|
|
448
488
|
eprintln(chalk.red(`Unknown IDE: ${ide}`));
|
|
449
|
-
eprintln(`Supported: ${SUPPORTED_IDES.join(
|
|
489
|
+
eprintln(`Supported: ${SUPPORTED_IDES.join(", ")}`);
|
|
450
490
|
process.exit(1);
|
|
451
491
|
}
|
|
452
492
|
const handler = getIDEHandler(ide);
|
|
@@ -454,29 +494,31 @@ program
|
|
|
454
494
|
println();
|
|
455
495
|
println(chalk.cyan(` Installing MCP config for ${handler.name}...`));
|
|
456
496
|
// Write config
|
|
457
|
-
process.stdout.write(chalk.gray(
|
|
497
|
+
process.stdout.write(chalk.gray(" Writing config... "));
|
|
458
498
|
await handler.writeConfig(options.key, mcpUrl);
|
|
459
|
-
println(chalk.green(
|
|
460
|
-
if (ide !==
|
|
499
|
+
println(chalk.green("OK"));
|
|
500
|
+
if (ide !== "manual") {
|
|
461
501
|
println(chalk.gray(` Config: ${handler.getConfigPath()}`));
|
|
462
502
|
}
|
|
463
503
|
// Verify heartbeat
|
|
464
|
-
process.stdout.write(chalk.gray(
|
|
504
|
+
process.stdout.write(chalk.gray(" Verifying connection... "));
|
|
465
505
|
const verified = await handler.verify(options.key, options.url);
|
|
466
506
|
if (verified) {
|
|
467
|
-
println(chalk.green(
|
|
507
|
+
println(chalk.green("OK"));
|
|
468
508
|
}
|
|
469
509
|
else {
|
|
470
|
-
println(chalk.yellow(
|
|
471
|
-
println(chalk.gray(
|
|
510
|
+
println(chalk.yellow("SKIPPED (server not reachable)"));
|
|
511
|
+
println(chalk.gray(" The config was saved. Connection will work when the server is available."));
|
|
472
512
|
}
|
|
473
513
|
println();
|
|
474
|
-
println(chalk.green.bold(
|
|
514
|
+
println(chalk.green.bold(" Done! Restart your IDE to activate the MCP server."));
|
|
475
515
|
println();
|
|
476
516
|
}
|
|
477
517
|
catch (error) {
|
|
478
518
|
eprintln();
|
|
479
|
-
eprintln(chalk.red(
|
|
519
|
+
eprintln(chalk.red("Install failed:") +
|
|
520
|
+
" " +
|
|
521
|
+
(error instanceof Error ? error.message : String(error)));
|
|
480
522
|
process.exit(1);
|
|
481
523
|
}
|
|
482
524
|
});
|
|
@@ -485,15 +527,15 @@ program
|
|
|
485
527
|
* The platform runs on port 3700, MCP server on 3701.
|
|
486
528
|
*/
|
|
487
529
|
function resolveMcpServerUrl(platformUrl) {
|
|
488
|
-
if (platformUrl.includes(
|
|
489
|
-
return platformUrl.replace(
|
|
530
|
+
if (platformUrl.includes(":3700")) {
|
|
531
|
+
return platformUrl.replace(":3700", ":3701");
|
|
490
532
|
}
|
|
491
|
-
if (platformUrl.includes(
|
|
492
|
-
return
|
|
533
|
+
if (platformUrl.includes("localhost") && !platformUrl.includes(":")) {
|
|
534
|
+
return "http://localhost:3701";
|
|
493
535
|
}
|
|
494
536
|
// Production: use dedicated MCP subdomain
|
|
495
|
-
if (platformUrl.includes(
|
|
496
|
-
return process.env.MCP_SERVER_URL ||
|
|
537
|
+
if (platformUrl.includes("tostudy")) {
|
|
538
|
+
return process.env.MCP_SERVER_URL || "https://mcp.tostudy.ai";
|
|
497
539
|
}
|
|
498
540
|
return platformUrl;
|
|
499
541
|
}
|