@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.
Files changed (47) hide show
  1. package/README.md +1 -1
  2. package/dist/__tests__/e2e-wizard-flow.test.d.ts.map +1 -1
  3. package/dist/__tests__/e2e-wizard-flow.test.js +128 -117
  4. package/dist/__tests__/e2e-wizard-flow.test.js.map +1 -1
  5. package/dist/__tests__/ide-handlers.test.js +15 -11
  6. package/dist/__tests__/ide-handlers.test.js.map +1 -1
  7. package/dist/__tests__/install-command.test.js +106 -95
  8. package/dist/__tests__/install-command.test.js.map +1 -1
  9. package/dist/config.d.ts +15 -4
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +79 -29
  12. package/dist/config.js.map +1 -1
  13. package/dist/diagnose.d.ts +1 -1
  14. package/dist/diagnose.d.ts.map +1 -1
  15. package/dist/diagnose.js +154 -164
  16. package/dist/diagnose.js.map +1 -1
  17. package/dist/ide-handlers/antigravity.js +1 -1
  18. package/dist/ide-handlers/antigravity.js.map +1 -1
  19. package/dist/ide-handlers/base.d.ts +8 -8
  20. package/dist/ide-handlers/base.d.ts.map +1 -1
  21. package/dist/ide-handlers/base.js +29 -4
  22. package/dist/ide-handlers/base.js.map +1 -1
  23. package/dist/ide-handlers/claude-code.js +1 -1
  24. package/dist/ide-handlers/claude-code.js.map +1 -1
  25. package/dist/ide-handlers/codex.js +1 -1
  26. package/dist/ide-handlers/codex.js.map +1 -1
  27. package/dist/ide-handlers/cursor.js +1 -1
  28. package/dist/ide-handlers/cursor.js.map +1 -1
  29. package/dist/ide-handlers/desktop.d.ts +3 -3
  30. package/dist/ide-handlers/desktop.d.ts.map +1 -1
  31. package/dist/ide-handlers/desktop.js +32 -8
  32. package/dist/ide-handlers/desktop.js.map +1 -1
  33. package/dist/ide-handlers/manual.js +1 -1
  34. package/dist/ide-handlers/manual.js.map +1 -1
  35. package/dist/ide-handlers/opencode.js +1 -1
  36. package/dist/ide-handlers/opencode.js.map +1 -1
  37. package/dist/ide-handlers/vscode.js +1 -1
  38. package/dist/ide-handlers/vscode.js.map +1 -1
  39. package/dist/ide-handlers/windsurf.js +1 -1
  40. package/dist/ide-handlers/windsurf.js.map +1 -1
  41. package/dist/index.js +198 -156
  42. package/dist/index.js.map +1 -1
  43. package/dist/repair.d.ts +1 -1
  44. package/dist/repair.d.ts.map +1 -1
  45. package/dist/repair.js +213 -168
  46. package/dist/repair.js.map +1 -1
  47. 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 '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 = '') {
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('') + chalk.white.bold(' Catalyst MCP Setup ') + 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: 'POST',
45
+ method: "POST",
46
46
  headers: {
47
- 'Authorization': `Bearer ${apiKey}`,
48
- 'Content-Type': 'application/json',
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('! Nao foi possivel validar a API key (servidor offline?)'));
57
- println(chalk.yellow(' A configuracao sera salva mesmo assim.'));
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('X Claude Code nao encontrado.'));
68
+ println(chalk.red("X Claude Code nao encontrado."));
69
69
  println();
70
- println(' Por favor, instale o Claude Code primeiro:');
71
- println(chalk.cyan(' https://claude.ai/download'));
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('! Catalyst MCP ja esta configurado.'));
81
- const overwrite = await confirm('Deseja reconfigurar?', false);
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('Operacao cancelada.'));
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('Validando API key... '));
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('FALHOU'));
96
+ println(chalk.red("FALHOU"));
97
97
  println();
98
- println(chalk.red('API key invalida ou expirada.'));
98
+ println(chalk.red("API key invalida ou expirada."));
99
99
  println();
100
- println('Para gerar uma nova API key:');
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('OK'));
105
+ println(chalk.green("OK"));
106
106
  // Configure Claude Code
107
- process.stdout.write(chalk.gray('Configurando Claude Code... '));
107
+ process.stdout.write(chalk.gray("Configurando Claude Code... "));
108
108
  try {
109
109
  addTostudyMcpServer(key, url);
110
- println(chalk.green('OK'));
110
+ println(chalk.green("OK"));
111
111
  }
112
112
  catch (error) {
113
- println(chalk.red('FALHOU'));
113
+ println(chalk.red("FALHOU"));
114
114
  eprintln();
115
- eprintln(chalk.red('Erro ao salvar configuracao:'));
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('Configuracao concluida!'));
121
+ println(chalk.green.bold("Configuracao concluida!"));
122
122
  println();
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');
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('Catalyst MCP nao esta configurado.'));
144
+ println(chalk.yellow("Catalyst MCP nao esta configurado."));
136
145
  process.exit(0);
137
146
  }
138
- const shouldUninstall = await confirm('Remover configuracao do Catalyst MCP?', false);
147
+ const shouldUninstall = await confirm("Remover configuracao do Catalyst MCP?", false);
139
148
  if (!shouldUninstall) {
140
- println(chalk.gray('Operacao cancelada.'));
149
+ println(chalk.gray("Operacao cancelada."));
141
150
  process.exit(0);
142
151
  }
143
- process.stdout.write(chalk.gray('Removendo configuracao... '));
152
+ process.stdout.write(chalk.gray("Removendo configuracao... "));
144
153
  try {
145
154
  removeTostudyMcpServer();
146
- println(chalk.green('OK'));
155
+ println(chalk.green("OK"));
147
156
  println();
148
- println(chalk.green('Configuracao removida com sucesso.'));
149
- println(chalk.gray('Reinicie o Claude Code para aplicar as mudancas.'));
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('FALHOU'));
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(' Nenhuma IDE suportada detectada.'));
172
- println(chalk.gray(' O setup continuara para Claude Code.'));
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(' IDEs detectadas:'));
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('')} ${ide.name}${version}`);
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('') + chalk.white.bold(' Catalyst MCP Setup Wizard ') + chalk.cyan('║'));
192
- println(chalk.cyan(' ║') + chalk.gray(' Configuracao guiada passo a passo ') + chalk.cyan('║'));
193
- println(chalk.cyan(' ╚═══════════════════════════════════════════════╝'));
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(' Este assistente vai configurar o Claude Code para'));
196
- println(chalk.gray(' conectar ao servidor MCP da plataforma Catalyst.'));
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, 'Detectando ambiente');
210
+ printStep(1, TOTAL_STEPS, "Detectando ambiente");
200
211
  // Check Claude Code
201
- process.stdout.write(' Verificando Claude Code... ');
212
+ process.stdout.write(" Verificando Claude Code... ");
202
213
  if (!isClaudeInstalled()) {
203
- println(chalk.red('NAO ENCONTRADO'));
214
+ println(chalk.red("NAO ENCONTRADO"));
204
215
  println();
205
- println(chalk.red(' Claude Code nao esta instalado.'));
216
+ println(chalk.red(" Claude Code nao esta instalado."));
206
217
  println();
207
- println(' Por favor, instale primeiro:');
208
- println(chalk.cyan(' https://claude.ai/download'));
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('OK'));
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(' Detectando IDEs... ');
227
+ process.stdout.write(" Detectando IDEs... ");
217
228
  const installedIDEs = getInstalledIDEs();
218
- println(chalk.green('OK'));
229
+ println(chalk.green("OK"));
219
230
  printIDEDetection(installedIDEs);
220
231
  // Check existing configuration
221
- process.stdout.write(' Verificando configuracao atual... ');
232
+ process.stdout.write(" Verificando configuracao atual... ");
222
233
  const alreadyConfigured = isTostudyMcpConfigured();
223
234
  if (alreadyConfigured) {
224
- println(chalk.yellow('JA CONFIGURADO'));
235
+ println(chalk.yellow("JA CONFIGURADO"));
225
236
  println();
226
- const overwrite = await confirm(' Deseja reconfigurar?', false);
237
+ const overwrite = await confirm(" Deseja reconfigurar?", false);
227
238
  if (!overwrite) {
228
239
  println();
229
- println(chalk.gray(' Operacao cancelada.'));
240
+ println(chalk.gray(" Operacao cancelada."));
230
241
  process.exit(0);
231
242
  }
232
243
  }
233
244
  else {
234
- println(chalk.gray('Nao configurado'));
245
+ println(chalk.gray("Nao configurado"));
235
246
  }
236
247
  // ━━━ Step 2: API Key Configuration ━━━
237
- printStep(2, TOTAL_STEPS, 'Configurando API Key');
238
- println(chalk.gray(' A API key conecta o Claude Code a sua conta na plataforma.'));
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(' Acesse sua API key em:');
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(' ✓ API key fornecida via parametro ou ambiente'));
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(' Validando API key... '));
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('FALHOU'));
267
+ println(chalk.red("FALHOU"));
257
268
  println();
258
- println(chalk.red(' API key invalida ou expirada.'));
269
+ println(chalk.red(" API key invalida ou expirada."));
259
270
  println();
260
- println(' Para gerar uma nova API key:');
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('OK'));
276
+ println(chalk.green("OK"));
266
277
  // ━━━ Step 3: Save Configuration ━━━
267
- printStep(3, TOTAL_STEPS, 'Salvando configuracao');
268
- process.stdout.write(' Configurando Claude Code... ');
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('OK'));
282
+ println(chalk.green("OK"));
272
283
  }
273
284
  catch (error) {
274
- println(chalk.red('FALHOU'));
285
+ println(chalk.red("FALHOU"));
275
286
  eprintln();
276
- eprintln(chalk.red(' Erro ao salvar configuracao:'));
277
- eprintln(' ' + (error instanceof Error ? error.message : String(error)));
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, 'Verificacao final');
292
+ printStep(4, TOTAL_STEPS, "Verificacao final");
282
293
  if (!options.skipDiagnostics) {
283
- process.stdout.write(' Executando diagnostico... ');
294
+ process.stdout.write(" Executando diagnostico... ");
284
295
  const report = await runDiagnostics();
285
- println(chalk.green('OK'));
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) => !['mcp-not-configured', 'config-missing'].includes(issue.id));
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(' Avisos encontrados:'));
301
+ println(chalk.yellow(" Avisos encontrados:"));
291
302
  for (const issue of remainingIssues) {
292
- const icon = issue.severity === 'critical' ? chalk.red('●') :
293
- issue.severity === 'warning' ? chalk.yellow('') : chalk.blue('●');
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(' Tentando reparar automaticamente... ');
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('Nenhum reparo aplicado'));
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(' ✓ Nenhum problema encontrado!'));
327
+ println(chalk.green(" ✓ Nenhum problema encontrado!"));
314
328
  }
315
329
  }
316
330
  else {
317
- println(chalk.gray(' Diagnostico ignorado (--skip-diagnostics)'));
331
+ println(chalk.gray(" Diagnostico ignorado (--skip-diagnostics)"));
318
332
  }
319
333
  // ━━━ Success ━━━
320
334
  println();
321
- println(chalk.green(' ╔═══════════════════════════════════════════════╗'));
322
- println(chalk.green('') + chalk.white.bold(' Configuracao concluida com sucesso! ') + chalk.green('║'));
323
- println(chalk.green(' ╚═══════════════════════════════════════════════╝'));
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.white(' Proximos passos:'));
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(' 1.') + ' Reinicie o Claude Code');
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.gray(' Comandos uteis:'));
332
- println(chalk.gray(' ') + chalk.cyan('npx @tostudy-ai/mcp-setup diagnose') + chalk.gray(' - Verificar problemas'));
333
- println(chalk.gray(' ') + chalk.cyan('npx @tostudy-ai/mcp-setup repair') + chalk.gray(' - Reparar automaticamente'));
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('tostudy-mcp-setup')
339
- .description('Configura o Claude Code para usar o Catalyst MCP server')
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('-k, --api-key <key>', 'API key da plataforma Catalyst')
344
- .option('-u, --url <url>', 'URL da plataforma (default: https://tostudy.com)')
345
- .option('--uninstall', 'Remove a configuracao do Catalyst MCP')
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('Erro:') + ' ' + (error instanceof Error ? error.message : String(error)));
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('wizard')
364
- .description('Assistente interativo de configuracao passo a passo')
365
- .option('-k, --api-key <key>', 'API key da plataforma Catalyst')
366
- .option('-u, --url <url>', 'URL da plataforma (default: https://tostudy.com)')
367
- .option('--skip-diagnostics', 'Pula a verificacao de diagnostico apos setup')
368
- .option('--auto-repair', 'Tenta reparar problemas automaticamente')
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('Erro:') + ' ' + (error instanceof Error ? error.message : String(error)));
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('diagnose')
387
- .description('Executa diagnostico de problemas na configuracao MCP')
388
- .option('--json', 'Saida em formato JSON')
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('Erro ao executar diagnostico:'));
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('repair')
410
- .description('Repara problemas de configuracao automaticamente')
411
- .option('-k, --api-key <key>', 'API key para reparos que necessitam autenticacao')
412
- .option('-u, --url <url>', 'URL da plataforma (default: https://tostudy.com)')
413
- .option('--json', 'Saida em formato JSON')
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 === 'critical' && !repair.results.find((r) => r.issueId === issue.id && r.success));
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('Erro ao executar reparo:'));
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 = ['claude-code', 'cursor', 'vscode', 'desktop', 'windsurf', 'opencode', 'codex', 'antigravity', 'manual'];
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('install')
440
- .description('Install MCP config for a specific IDE (used by the web setup wizard)')
441
- .requiredOption('--ide <ide>', `Target IDE: ${SUPPORTED_IDES.join(', ')}`)
442
- .requiredOption('--key <key>', 'API key from the platform')
443
- .option('--url <url>', 'Platform URL (default: https://tostudy.com)', DEFAULT_PLATFORM_URL)
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(' Writing config... '));
497
+ process.stdout.write(chalk.gray(" Writing config... "));
458
498
  await handler.writeConfig(options.key, mcpUrl);
459
- println(chalk.green('OK'));
460
- if (ide !== 'manual') {
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(' Verifying connection... '));
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('OK'));
507
+ println(chalk.green("OK"));
468
508
  }
469
509
  else {
470
- println(chalk.yellow('SKIPPED (server not reachable)'));
471
- println(chalk.gray(' The config was saved. Connection will work when the server is available.'));
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(' Done! Restart your IDE to activate the MCP server.'));
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('Install failed:') + ' ' + (error instanceof Error ? error.message : String(error)));
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(':3700')) {
489
- return platformUrl.replace(':3700', ':3701');
530
+ if (platformUrl.includes(":3700")) {
531
+ return platformUrl.replace(":3700", ":3701");
490
532
  }
491
- if (platformUrl.includes('localhost') && !platformUrl.includes(':')) {
492
- return 'http://localhost:3701';
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('tostudy')) {
496
- return process.env.MCP_SERVER_URL || 'https://mcp.tostudy.ai';
537
+ if (platformUrl.includes("tostudy")) {
538
+ return process.env.MCP_SERVER_URL || "https://mcp.tostudy.ai";
497
539
  }
498
540
  return platformUrl;
499
541
  }