komplian 0.7.0 → 0.7.1

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.
@@ -42,6 +42,7 @@ const c = {
42
42
  };
43
43
 
44
44
  function log(s = "") {
45
+ if (process.env.KOMPLIAN_CLI_QUIET === "1") return;
45
46
  console.log(s);
46
47
  }
47
48
 
@@ -148,9 +149,9 @@ function collectUrlsFromEnv() {
148
149
 
149
150
  async function collectUrlsInteractive(rl) {
150
151
  log(` ${c.dim}postgresql://… desde Neon (rama development) u homólogo.${c.reset}`);
151
- const app = (await rl.question(`${c.bold}URL APP${c.reset} (app + API): `)).trim();
152
- const admin = (await rl.question(`${c.bold}URL ADMIN${c.reset}: `)).trim();
153
- const web = (await rl.question(`${c.bold}URL WEB${c.reset} (pilot): `)).trim();
152
+ const app = (await rl.question(`${c.bold}APP URL${c.reset} (app + API): `)).trim();
153
+ const admin = (await rl.question(`${c.bold}ADMIN URL${c.reset}: `)).trim();
154
+ const web = (await rl.question(`${c.bold}WEB URL${c.reset}: `)).trim();
154
155
  return { app, admin, web };
155
156
  }
156
157
 
@@ -178,15 +179,16 @@ function parseArgs(argv) {
178
179
  }
179
180
 
180
181
  function usage() {
181
- log(`Uso: npx komplian db:all:dev [opciones] [monorepo]`);
182
- log(``);
183
- log(` Tras ${c.bold}npx komplian postman login${c.reset}: verifica @komplian.com y configura las 3 bases de desarrollo.`);
184
- log(` Guarda en ${c.dim}~/.komplian/dev-databases.json${c.reset} y actualiza ${c.dim}app|api|web|admin/.env.local${c.reset}.`);
185
- log(``);
186
- log(` Sin prompts: ${c.dim}KOMPLIAN_DEV_APP_DATABASE_URL${c.reset}, ${c.dim}_ADMIN_${c.reset}, ${c.dim}_WEB_${c.reset} + ${c.bold}--yes${c.reset}`);
187
- log(` ${c.bold}--force${c.reset} Volver a pedir URLs (o usar env) aunque exista el JSON`);
188
- log(` -w, --workspace Raíz del monorepo`);
189
- log(` -h, --help`);
182
+ const p = (s) => console.log(s);
183
+ p(`Usage: npx komplian db:all:dev [options] [monorepo]`);
184
+ p(``);
185
+ p(` Verifies @komplian.com (Postman) and writes 3 dev DB URLs.`);
186
+ p(` Saves ${c.dim}~/.komplian/dev-databases.json${c.reset} and updates app|api|web|admin ${c.dim}.env.local${c.reset}.`);
187
+ p(``);
188
+ p(` Non-interactive: ${c.dim}KOMPLIAN_DEV_*_DATABASE_URL${c.reset} + ${c.bold}--yes${c.reset}`);
189
+ p(` ${c.bold}--force${c.reset} Re-prompt / re-read env even if JSON exists`);
190
+ p(` -w, --workspace Monorepo root`);
191
+ p(` -h, --help`);
190
192
  }
191
193
 
192
194
  export async function runDbAllDev(argv) {
@@ -201,11 +203,11 @@ export async function runDbAllDev(argv) {
201
203
  : findWorkspaceRoot(process.cwd());
202
204
 
203
205
  if (!existsSync(join(workspaceRoot, "api", "package.json"))) {
204
- log(`${c.red}✗${c.reset} No parece un monorepo Komplian: ${workspaceRoot}`);
206
+ console.error(`${c.red}✗${c.reset} Not a Komplian monorepo.`);
205
207
  process.exit(1);
206
208
  }
207
209
 
208
- log(`${c.cyan}━━ Komplian bases de datos (development) ━━${c.reset}`);
210
+ log(`${c.cyan}━━ dev databases ━━${c.reset}`);
209
211
  await assertKomplianEmployeePostman();
210
212
 
211
213
  const fromEnv = collectUrlsFromEnv();
@@ -218,27 +220,25 @@ export async function runDbAllDev(argv) {
218
220
 
219
221
  if (envOk) {
220
222
  data = fromEnv;
221
- log(`${c.green}✓${c.reset} URLs desde variables de entorno (KOMPLIAN_DEV_*_DATABASE_URL).`);
223
+ log(`${c.green}✓${c.reset} URLs from env.`);
222
224
  } else if (savedOk && !opts.force && !envOk) {
223
225
  data = saved;
224
- log(
225
- `${c.dim}○${c.reset} Usando ${c.bold}~/.komplian/dev-databases.json${c.reset} (${c.dim}--force${c.reset} para cambiar).`
226
- );
226
+ log(`${c.dim}○${c.reset} Using saved ${c.bold}dev-databases.json${c.reset} (${c.dim}--force${c.reset} to replace).`);
227
227
  } else if (opts.yes && !envOk) {
228
- log(
229
- `${c.red}✗${c.reset} Con ${c.bold}--yes${c.reset} define las tres variables ${c.dim}KOMPLIAN_DEV_APP_DATABASE_URL${c.reset}, ${c.dim}_ADMIN_${c.reset}, ${c.dim}_WEB_${c.reset}, o ejecuta sin ${c.bold}--yes${c.reset} para modo interactivo.`
228
+ console.error(
229
+ `${c.red}✗${c.reset} With ${c.bold}--yes${c.reset} set ${c.dim}KOMPLIAN_DEV_*_DATABASE_URL${c.reset} or run without ${c.bold}--yes${c.reset}.`
230
230
  );
231
231
  process.exit(1);
232
232
  } else {
233
233
  const rl = createInterface({ input, output });
234
234
  log(``);
235
- log(`${c.bold}Introduce las connection strings de desarrollo (3).${c.reset}`);
235
+ log(`${c.bold}Enter 3 development connection strings.${c.reset}`);
236
236
  data = await collectUrlsInteractive(rl);
237
237
  rl.close();
238
238
  }
239
239
 
240
240
  if (!isValidTriplet(data)) {
241
- log(`${c.red}✗${c.reset} Las tres URLs deben ser postgres:// o postgresql:// válidas (sin placeholder).`);
241
+ console.error(`${c.red}✗${c.reset} All three URLs must be valid postgres:// or postgresql:// (no placeholders).`);
242
242
  process.exit(1);
243
243
  }
244
244
 
@@ -246,11 +246,14 @@ export async function runDbAllDev(argv) {
246
246
  propagateToMonorepo(workspaceRoot, data);
247
247
 
248
248
  log(``);
249
- log(`${c.green}✓${c.reset} Guardado ${c.dim}~/.komplian/${DEV_DB_NAME}${c.reset} y .env.local en app, api, web, admin.`);
250
- log(` ${c.dim}APP${c.reset} ${maskDatabaseUrl(data.app)}`);
251
- log(` ${c.dim}ADMIN${c.reset} ${maskDatabaseUrl(data.admin)}`);
252
- log(` ${c.dim}WEB${c.reset} ${maskDatabaseUrl(data.web)}`);
253
- log(``);
254
- log(`${c.dim}Siguiente: ${c.reset}${c.cyan}npx komplian localhost --yes${c.reset}`);
255
- log(`${c.dim}psql: ${c.reset}${c.cyan}npx komplian db:app:development${c.reset} …`);
249
+ if (process.env.KOMPLIAN_CLI_QUIET === "1") {
250
+ console.log(`${c.green}✓${c.reset} dev databases`);
251
+ } else {
252
+ log(`${c.green}✓${c.reset} Saved ${c.dim}~/.komplian/${DEV_DB_NAME}${c.reset} and repo ${c.dim}.env.local${c.reset} files.`);
253
+ log(` ${c.dim}APP${c.reset} ${maskDatabaseUrl(data.app)}`);
254
+ log(` ${c.dim}ADMIN${c.reset} ${maskDatabaseUrl(data.admin)}`);
255
+ log(` ${c.dim}WEB${c.reset} ${maskDatabaseUrl(data.web)}`);
256
+ log(``);
257
+ log(`${c.dim}Next: ${c.reset}${c.cyan}npx komplian localhost --yes${c.reset}`);
258
+ }
256
259
  }
@@ -35,7 +35,16 @@ const c = {
35
35
  yellow: "\x1b[33m",
36
36
  };
37
37
 
38
+ function cliQuiet() {
39
+ return process.env.KOMPLIAN_CLI_QUIET === "1";
40
+ }
41
+
38
42
  function log(s = "") {
43
+ if (cliQuiet()) return;
44
+ console.log(s);
45
+ }
46
+
47
+ function logAlways(s = "") {
39
48
  console.log(s);
40
49
  }
41
50
 
@@ -292,7 +301,7 @@ function envFromOverridesOnly(overrides) {
292
301
 
293
302
  function writeAppEnv(root, s, db, opts) {
294
303
  const p = join(root, "app", ".env.local");
295
- if (existsSync(p) && !opts.force) return { path: p, skipped: true };
304
+ if (existsSync(p) && !opts.force) return { path: p, skipped: true, label: "app" };
296
305
  const examplePath = join(root, "app", ".env.example");
297
306
  const overrides = buildAppOverrides(s, db, opts);
298
307
  let body;
@@ -302,12 +311,12 @@ function writeAppEnv(root, s, db, opts) {
302
311
  body = envFromOverridesOnly(overrides);
303
312
  }
304
313
  writeAtomic(p, header("app") + body);
305
- return { path: p, skipped: false };
314
+ return { path: p, skipped: false, label: "app" };
306
315
  }
307
316
 
308
317
  function writeApiEnv(root, s, db, opts) {
309
318
  const p = join(root, "api", ".env.local");
310
- if (existsSync(p) && !opts.force) return { path: p, skipped: true };
319
+ if (existsSync(p) && !opts.force) return { path: p, skipped: true, label: "api" };
311
320
  const examplePath = join(root, "api", ".env.example");
312
321
  const overrides = buildApiOverrides(s, db);
313
322
  let body;
@@ -317,12 +326,12 @@ function writeApiEnv(root, s, db, opts) {
317
326
  body = envFromOverridesOnly(overrides);
318
327
  }
319
328
  writeAtomic(p, header("api") + body);
320
- return { path: p, skipped: false };
329
+ return { path: p, skipped: false, label: "api" };
321
330
  }
322
331
 
323
332
  function writeWebEnv(root, s, db, opts) {
324
333
  const p = join(root, "web", ".env.local");
325
- if (existsSync(p) && !opts.force) return { path: p, skipped: true };
334
+ if (existsSync(p) && !opts.force) return { path: p, skipped: true, label: "web" };
326
335
  const examplePath = join(root, "web", ".env.example");
327
336
  const overrides = buildWebOverrides(s, db);
328
337
  let body;
@@ -332,12 +341,12 @@ function writeWebEnv(root, s, db, opts) {
332
341
  body = envFromOverridesOnly(overrides);
333
342
  }
334
343
  writeAtomic(p, header("web") + body);
335
- return { path: p, skipped: false };
344
+ return { path: p, skipped: false, label: "web" };
336
345
  }
337
346
 
338
347
  function writeAdminEnv(root, s, db, opts) {
339
348
  const p = join(root, "admin", ".env.local");
340
- if (existsSync(p) && !opts.force) return { path: p, skipped: true };
349
+ if (existsSync(p) && !opts.force) return { path: p, skipped: true, label: "admin" };
341
350
  const examplePath = join(root, "admin", ".env.example");
342
351
  const overrides = buildAdminOverrides(s, db);
343
352
  let body;
@@ -347,41 +356,47 @@ function writeAdminEnv(root, s, db, opts) {
347
356
  body = envFromOverridesOnly(overrides);
348
357
  }
349
358
  writeAtomic(p, header("admin") + body);
350
- return { path: p, skipped: false };
359
+ return { path: p, skipped: false, label: "admin" };
351
360
  }
352
361
 
353
362
  function writeDocsEnv(root, opts) {
354
363
  const p = join(root, "docs", ".env.local");
355
- if (existsSync(p) && !opts.force) return { path: p, skipped: true };
364
+ if (existsSync(p) && !opts.force) return { path: p, skipped: true, label: "docs" };
356
365
  const examplePath = join(root, "docs", ".env.example");
357
366
  if (!existsSync(examplePath)) {
358
367
  writeAtomic(
359
368
  p,
360
369
  `${header("docs")}# Sin variables obligatorias para next dev.\n`
361
370
  );
362
- return { path: p, skipped: false };
371
+ return { path: p, skipped: false, label: "docs" };
363
372
  }
364
373
  const overrides = buildDocsOverrides();
365
374
  let content = readFileSync(examplePath, "utf8");
366
375
  content = applyOverridesToEnvContent(content, overrides);
367
376
  writeAtomic(p, header("docs") + content);
368
- return { path: p, skipped: false };
377
+ return { path: p, skipped: false, label: "docs" };
369
378
  }
370
379
 
371
380
  function printLocalUrls(minimal) {
381
+ if (cliQuiet()) {
382
+ logAlways(
383
+ `${c.dim}dev ·${c.reset} ${!minimal ? "4000 " : ""}3001${!minimal ? " 3002 3003" : " 3003"} 3004`
384
+ );
385
+ return;
386
+ }
372
387
  log("");
373
- log(`${c.bold}Local — abre en el navegador${c.reset}`);
388
+ log(`${c.bold}Local${c.reset}`);
374
389
  if (!minimal) {
375
- log(` ${c.cyan}API${c.reset} http://localhost:4000 ${c.dim}(/health)${c.reset}`);
390
+ log(` ${c.cyan}api${c.reset} http://localhost:4000`);
376
391
  }
377
- log(` ${c.cyan}App${c.reset} http://localhost:3001`);
392
+ log(` ${c.cyan}app${c.reset} http://localhost:3001`);
378
393
  if (!minimal) {
379
- log(` ${c.cyan}Admin${c.reset} http://localhost:3002`);
380
- log(` ${c.cyan}Web${c.reset} http://localhost:3003`);
394
+ log(` ${c.cyan}admin${c.reset} http://localhost:3002`);
395
+ log(` ${c.cyan}web${c.reset} http://localhost:3003`);
381
396
  } else {
382
- log(` ${c.cyan}Web${c.reset} http://localhost:3003`);
397
+ log(` ${c.cyan}web${c.reset} http://localhost:3003`);
383
398
  }
384
- log(` ${c.cyan}Docs${c.reset} http://localhost:3004`);
399
+ log(` ${c.cyan}docs${c.reset} http://localhost:3004`);
385
400
  log("");
386
401
  }
387
402
 
@@ -389,7 +404,7 @@ async function confirmOverwrite(yes) {
389
404
  if (yes) return true;
390
405
  const rl = createInterface({ input, output });
391
406
  const ans = await rl.question(
392
- `\n${c.bold}Sobrescribir .env.local existentes? [y/N]${c.reset} `
407
+ `\n${c.bold}Overwrite existing .env.local files? [y/N]${c.reset} `
393
408
  );
394
409
  rl.close();
395
410
  return /^y(es)?$/i.test((ans || "").trim());
@@ -414,7 +429,7 @@ function parseLocalhostArgs(argv) {
414
429
  else if (a === "-h" || a === "--help") opts.help = true;
415
430
  else if (a === "--workspace" || a === "-w") opts.workspace = argv[++i] || "";
416
431
  else if (a.startsWith("-")) {
417
- log(`${c.red}✗${c.reset} Opción desconocida: ${a}`);
432
+ logAlways(`${c.red}✗${c.reset} Unknown option: ${a}`);
418
433
  process.exit(1);
419
434
  } else rest.push(a);
420
435
  }
@@ -423,17 +438,17 @@ function parseLocalhostArgs(argv) {
423
438
  }
424
439
 
425
440
  function usageLocalhost() {
426
- log(`Uso: npx komplian localhost [opciones] [carpeta-monorepo]`);
427
- log(``);
428
- log(` Genera .env.local completos (desde cada .env.example + secretos KOMPLIAN) y arranca todos los dev servers.`);
429
- log(` ${c.dim}DBs: npx komplian db:all:dev antes (o ~/.komplian/dev-databases.json / variables en sesión).${c.reset}`);
430
- log(``);
431
- log(` -y, --yes Sin confirmación`);
432
- log(` --force Regenerar .env.local`);
433
- log(` --minimal Solo app + web + docs`);
434
- log(` --env-only Solo escribir .env.local`);
435
- log(` -w, --workspace Ruta al monorepo`);
436
- log(` -h, --help`);
441
+ logAlways(`Usage: npx komplian localhost [options] [monorepo-dir]`);
442
+ logAlways(``);
443
+ logAlways(` Writes .env.local from each .env.example + generated secrets, then runs dev servers.`);
444
+ logAlways(` ${c.dim}DBs: run db:all:dev first (or use ~/.komplian/dev-databases.json / env).${c.reset}`);
445
+ logAlways(``);
446
+ logAlways(` -y, --yes No overwrite prompt`);
447
+ logAlways(` --force Regenerate .env.local`);
448
+ logAlways(` --minimal app + web + docs only`);
449
+ logAlways(` --env-only Write .env.local only`);
450
+ logAlways(` -w, --workspace Monorepo root`);
451
+ logAlways(` -h, --help`);
437
452
  }
438
453
 
439
454
  function checkNodeModules(root, names) {
@@ -456,7 +471,7 @@ export async function runLocalhost(argv) {
456
471
  : findWorkspaceRoot(process.cwd());
457
472
 
458
473
  if (!existsSync(join(workspaceRoot, "api", "package.json"))) {
459
- log(`${c.red}✗${c.reset} No parece un monorepo Komplian (falta api/package.json): ${workspaceRoot}`);
474
+ logAlways(`${c.red}✗${c.reset} Not a Komplian monorepo (missing api/package.json).`);
460
475
  process.exit(1);
461
476
  }
462
477
 
@@ -481,7 +496,7 @@ export async function runLocalhost(argv) {
481
496
  if (hasAnyEnv && !opts.force) {
482
497
  const ok = await confirmOverwrite(opts.yes);
483
498
  if (!ok) {
484
- log(`${c.yellow}○${c.reset} Cancelado. Usa ${c.bold}--force${c.reset} para regenerar.`);
499
+ logAlways(`${c.yellow}○${c.reset} Cancelled. Use ${c.bold}--force${c.reset} to regenerate.`);
485
500
  return;
486
501
  }
487
502
  opts.force = true;
@@ -501,23 +516,30 @@ export async function runLocalhost(argv) {
501
516
  written.push(writeDocsEnv(workspaceRoot, opts));
502
517
 
503
518
  log("");
504
- log(`${c.cyan}━━ .env.local ━━${c.reset} ${c.dim}(600, no se publican en npm)${c.reset}`);
519
+ if (!cliQuiet()) {
520
+ log(`${c.cyan}━━ .env.local ━━${c.reset}`);
521
+ }
505
522
  for (const w of written) {
506
- const st = w.skipped ? `${c.dim}sin cambios${c.reset}` : `${c.green}ok${c.reset}`;
507
- log(` ${st} ${w.path}`);
523
+ const st = w.skipped ? `${c.dim}skip${c.reset}` : `${c.green}ok${c.reset}`;
524
+ const name = w.label || "?";
525
+ if (cliQuiet()) {
526
+ logAlways(` ${st} ${name}`);
527
+ } else {
528
+ log(` ${st} ${name}`);
529
+ }
508
530
  }
509
531
 
510
532
  printLocalUrls(opts.minimal);
511
533
 
512
534
  if (!db.hasReal && !opts.minimal) {
513
- log(
514
- `${c.yellow}⚠${c.reset} Sin URLs de desarrollo reales. Ejecuta ${c.bold}npx komplian db:all:dev${c.reset} y luego vuelve a lanzar localhost (o ${c.bold}--minimal${c.reset}).`
535
+ logAlways(
536
+ `${c.yellow}⚠${c.reset} No dev database URLs. Run ${c.bold}npx komplian db:all:dev${c.reset} then localhost again (or ${c.bold}--minimal${c.reset}).`
515
537
  );
516
- log("");
538
+ logAlways("");
517
539
  }
518
540
 
519
541
  if (opts.envOnly) {
520
- log(`${c.green}✓${c.reset} Entorno listo. Arranca: ${c.bold}npx komplian localhost --yes${c.reset}`);
542
+ logAlways(`${c.green}✓${c.reset} env files written.`);
521
543
  return;
522
544
  }
523
545
 
@@ -526,9 +548,9 @@ export async function runLocalhost(argv) {
526
548
  : ["api", "app", "web", "admin", "docs"];
527
549
  const missing = checkNodeModules(workspaceRoot, services);
528
550
  if (missing.length) {
529
- log("");
530
- log(`${c.red}✗${c.reset} Falta node_modules en: ${missing.join(", ")}`);
531
- log(` ${c.dim}Ejecuta npm install en cada carpeta (o npx komplian onboard --yes --install).${c.reset}`);
551
+ logAlways("");
552
+ logAlways(`${c.red}✗${c.reset} Missing node_modules: ${missing.join(", ")}`);
553
+ logAlways(` ${c.dim}npm install per repo or npx komplian onboard --yes${c.reset}`);
532
554
  process.exit(1);
533
555
  }
534
556
 
@@ -542,19 +564,22 @@ export async function runLocalhost(argv) {
542
564
  return `npm run dev --prefix ${dir}`;
543
565
  });
544
566
 
545
- log(`${c.cyan}━━ Arranque (${services.length}) ━━${c.reset} ${c.dim}Ctrl+C detiene todo${c.reset}`);
546
- log("");
567
+ if (cliQuiet()) {
568
+ logAlways(`${c.cyan}━━ dev servers ━━${c.reset}`);
569
+ } else {
570
+ log(`${c.cyan}━━ dev servers (${services.length}) ━━${c.reset} ${c.dim}Ctrl+C stop${c.reset}`);
571
+ log("");
572
+ }
547
573
 
548
- // shell: false — con shell:true Node concatena args para /bin/sh -c y concurrently
549
- // recibe un número de comandos/names incoherente → TypeError en logger (prev.replace).
550
574
  const npx = process.platform === "win32" ? "npx.cmd" : "npx";
575
+ const useShell = process.platform === "win32";
551
576
  const child = spawn(
552
577
  npx,
553
578
  ["--yes", "concurrently@9", "-c", colors, "-n", names, ...scripts],
554
579
  {
555
580
  cwd: workspaceRoot,
556
581
  stdio: "inherit",
557
- shell: false,
582
+ shell: useShell,
558
583
  windowsHide: true,
559
584
  env: { ...process.env },
560
585
  }
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Komplian MCP — escribe `.cursor/mcp.json` con servidores MCP por stdio (prefijo KOMPLIAN-*)
4
- * y genera `.cursor/KOMPLIAN_MCP_SETUP.md` (plugins de Cursor que no van en JSON).
3
+ * Komplian MCP — writes `.cursor/mcp.json` with stdio MCP servers (KOMPLIAN-* prefix)
4
+ * and generates `.cursor/KOMPLIAN_MCP_SETUP.md` (Cursor-only notes not expressible in JSON).
5
5
  *
6
- * No incluye secretos: tokens vacíos; rellena en Cursor o vía KOMPLIAN_MCP_SECRETS.env (local, gitignored).
6
+ * No secrets in repo: empty env; fill in Cursor or via KOMPLIAN_MCP_SECRETS.env (local, gitignored).
7
7
  *
8
- * Uso: npx komplian mcp-tools --yes
8
+ * Usage: npx komplian mcp-tools --yes
9
9
  */
10
10
 
11
11
  import { mkdirSync, readFileSync, existsSync, writeFileSync } from "node:fs";
@@ -25,10 +25,11 @@ const c = {
25
25
  };
26
26
 
27
27
  function log(s = "") {
28
+ if (process.env.KOMPLIAN_CLI_QUIET === "1") return;
28
29
  console.log(s);
29
30
  }
30
31
 
31
- /** Preset Komplian: solo claves KOMPLIAN-* para no pisar servidores del dev. */
32
+ /** Komplian preset: only KOMPLIAN-* keys so we do not overwrite the dev's own servers. */
32
33
  const KOMPLIAN_MCP_PRESET = {
33
34
  mcpServers: {
34
35
  "KOMPLIAN-github": {
@@ -67,33 +68,33 @@ const KOMPLIAN_MCP_PRESET = {
67
68
  },
68
69
  };
69
70
 
70
- const SETUP_MD = `# KOMPLIAN — MCP en Cursor
71
+ const SETUP_MD = `# KOMPLIAN — MCP in Cursor
71
72
 
72
- Este archivo lo genera \`npx komplian mcp-tools\`. **No commitees** tokens; \`.cursor/mcp.json\` puede llevar env vacíos que rellenas solo en local.
73
+ Generated by \`npx komplian mcp-tools\`. **Do not commit** tokens; \`.cursor/mcp.json\` may keep empty env you fill only locally.
73
74
 
74
- ## 1. Servidores en \`.cursor/mcp.json\` (stdio / npx)
75
+ ## 1. Servers in \`.cursor/mcp.json\` (stdio / npx)
75
76
 
76
- Activa cada fila en **Cursor → Settings → MCP** (interruptor). Rellena \`env\` según la tabla.
77
+ Enable each row in **Cursor → Settings → MCP**. Fill \`env\` per the table.
77
78
 
78
- | ID | Paquete | Qué es | Rellena / notas |
79
- |----|---------|--------|-----------------|
80
- | **KOMPLIAN-github** | \`@modelcontextprotocol/server-github\` | GitHub API | \`GITHUB_PERSONAL_ACCESS_TOKEN\` (PAT). El paquete npm está deprecado; alternativa: [github/github-mcp-server](https://github.com/github/github-mcp-server). |
81
- | **KOMPLIAN-atlassian** | \`mcp-atlassian\` | Jira + Confluence (Cloud) | \`ATLASSIAN_EMAIL\` + \`ATLASSIAN_API_TOKEN\` ([crear token](https://id.atlassian.com/manage-profile/security/api-tokens)). \`ATLASSIAN_BASE_URL\` ya apunta a \`https://komplian.atlassian.net\`. Jira proyecto **KAPP**. |
82
- | **KOMPLIAN-sentry** | \`@sentry/mcp-server\` | Sentry | Primera vez: login en navegador. **Komplian:** org \`komplian\`, \`regionUrl\` \`https://de.sentry.io\`, proyectos \`komplian-api\` / \`komplian-app\`. |
83
- | **KOMPLIAN-stripe** | \`@stripe/mcp\` | Stripe API | \`STRIPE_SECRET_KEY\` (restricted key / test en dev). [Docs Stripe MCP](https://docs.stripe.com/mcp). |
84
- | **KOMPLIAN-chrome-devtools** | \`chrome-devtools-mcp\` | Chrome (red, consola, screenshots) | Requiere **Node 20.19+** y Chrome estable. Ver [Chrome DevTools MCP](https://developer.chrome.com/blog/chrome-devtools-mcp). |
79
+ | ID | Package | What | Fill / notes |
80
+ |----|---------|------|--------------|
81
+ | **KOMPLIAN-github** | \`@modelcontextprotocol/server-github\` | GitHub API | \`GITHUB_PERSONAL_ACCESS_TOKEN\` (PAT). npm package is deprecated; alternative: [github/github-mcp-server](https://github.com/github/github-mcp-server). |
82
+ | **KOMPLIAN-atlassian** | \`mcp-atlassian\` | Jira + Confluence (Cloud) | \`ATLASSIAN_EMAIL\` + \`ATLASSIAN_API_TOKEN\` ([create token](https://id.atlassian.com/manage-profile/security/api-tokens)). \`ATLASSIAN_BASE_URL\` is \`https://komplian.atlassian.net\`. Jira project **KAPP**. |
83
+ | **KOMPLIAN-sentry** | \`@sentry/mcp-server\` | Sentry | First time: browser login. **Komplian:** org \`komplian\`, \`regionUrl\` \`https://de.sentry.io\`, projects \`komplian-api\` / \`komplian-app\`. |
84
+ | **KOMPLIAN-stripe** | \`@stripe/mcp\` | Stripe API | \`STRIPE_SECRET_KEY\` (restricted / test in dev). [Stripe MCP docs](https://docs.stripe.com/mcp). |
85
+ | **KOMPLIAN-chrome-devtools** | \`chrome-devtools-mcp\` | Chrome (network, console, screenshots) | Needs **Node 20.19+** and stable Chrome. [Chrome DevTools MCP](https://developer.chrome.com/blog/chrome-devtools-mcp). |
85
86
 
86
- ## 2. Opcional: integraciones nativas de Cursor
87
+ ## 2. Optional: Cursor native connectors
87
88
 
88
- Si además quieres los conectores de Cursor (OAuth / UI): **Settings → MCP** y busca **Atlassian**, **Sentry**, **Stripe**, **Chrome DevTools** pueden coexistir con las entradas **KOMPLIAN-***; evita duplicar la misma acción en dos servidores.
89
+ For Cursor OAuth/UI connectors: **Settings → MCP** **Atlassian**, **Sentry**, **Stripe**, **Chrome DevTools**. They can coexist with **KOMPLIAN-*** entries; avoid duplicating the same capability twice.
89
90
 
90
- ## 3. Reinicio
91
+ ## 3. Restart
91
92
 
92
- Tras editar \`mcp.json\`, **reinicia Cursor** para cargar MCP.
93
+ After editing \`mcp.json\`, **restart Cursor** to load MCP.
93
94
 
94
- ## 4. Referencia interna
95
+ ## 4. Internal reference
95
96
 
96
- \`.cursor/rules/mcp-integrations.mdc\` (org Sentry, Stripe, KAPP).
97
+ \`.cursor/rules/mcp-integrations.mdc\` (Sentry org, Stripe, KAPP).
97
98
  `;
98
99
 
99
100
  function findWorkspaceRoot(start) {
@@ -145,7 +146,7 @@ function parseMcpArgs(argv) {
145
146
  else if (a === "-h" || a === "--help") opts.help = true;
146
147
  else if (a === "--workspace" || a === "-w") opts.workspace = argv[++i] || "";
147
148
  else if (a.startsWith("-")) {
148
- log(`${c.red}✗${c.reset} Opción desconocida: ${a}`);
149
+ console.error(`${c.red}✗${c.reset} Unknown option: ${a}`);
149
150
  process.exit(1);
150
151
  } else rest.push(a);
151
152
  }
@@ -154,18 +155,18 @@ function parseMcpArgs(argv) {
154
155
  }
155
156
 
156
157
  function usageMcpTools() {
157
- log(`Uso: npx komplian mcp-tools [opciones] [carpeta-monorepo]`);
158
+ log(`Usage: npx komplian mcp-tools [options] [monorepo-root]`);
158
159
  log(``);
159
- log(` Añade servidores MCP KOMPLIAN-* en .cursor/mcp.json (GitHub, Atlassian, Sentry, Stripe, Chrome).`);
160
- log(` y genera .cursor/KOMPLIAN_MCP_SETUP.md.`);
160
+ log(` Adds KOMPLIAN-* MCP servers to .cursor/mcp.json (GitHub, Atlassian, Sentry, Stripe, Chrome)`);
161
+ log(` and writes .cursor/KOMPLIAN_MCP_SETUP.md.`);
161
162
  log(``);
162
- log(` ${c.dim}Secretos: vacíos en JSON; no se publican en el paquete npm komplian.${c.reset}`);
163
+ log(` ${c.dim}Secrets stay empty in JSON; the komplian npm package never ships your values.${c.reset}`);
163
164
  log(``);
164
- log(` -y, --yes Sin confirmación`);
165
- log(` --force Sobreescribe entradas KOMPLIAN-* existentes`);
166
- log(` --dry-run Imprime JSON sin escribir`);
167
- log(` --global Fusiona en ~/.cursor/mcp.json (toda la máquina)`);
168
- log(` -w, --workspace Raíz del monorepo (por defecto: cwd)`);
165
+ log(` -y, --yes Non-interactive`);
166
+ log(` --force Overwrite existing KOMPLIAN-* entries`);
167
+ log(` --dry-run Print JSON without writing`);
168
+ log(` --global Merge into ~/.cursor/mcp.json (machine-wide)`);
169
+ log(` -w, --workspace Monorepo root (default: cwd)`);
169
170
  log(` -h, --help`);
170
171
  }
171
172
 
@@ -173,7 +174,7 @@ async function confirmForceOverwrite(yes) {
173
174
  if (yes) return true;
174
175
  const rl = createInterface({ input, output });
175
176
  const ans = await rl.question(
176
- `\n${c.bold}¿Sobrescribir entradas KOMPLIAN-* existentes? [y/N]${c.reset} `
177
+ `\n${c.bold}Overwrite existing KOMPLIAN-* entries? [y/N]${c.reset} `
177
178
  );
178
179
  rl.close();
179
180
  return /^y(es)?$/i.test((ans || "").trim());
@@ -201,7 +202,7 @@ export async function runMcpTools(argv) {
201
202
  try {
202
203
  existing = JSON.parse(readFileSync(mcpPath, "utf8"));
203
204
  } catch {
204
- log(`${c.red}✗${c.reset} JSON inválido: ${mcpPath}`);
205
+ log(`${c.red}✗${c.reset} Invalid JSON: ${mcpPath}`);
205
206
  process.exit(1);
206
207
  }
207
208
  }
@@ -212,7 +213,7 @@ export async function runMcpTools(argv) {
212
213
  if (opts.force && hadKomplian && !opts.yes) {
213
214
  const ok = await confirmForceOverwrite(opts.yes);
214
215
  if (!ok) {
215
- log(`${c.yellow}○${c.reset} Cancelado.`);
216
+ log(`${c.yellow}○${c.reset} Cancelled.`);
216
217
  return;
217
218
  }
218
219
  }
@@ -236,16 +237,20 @@ export async function runMcpTools(argv) {
236
237
  }
237
238
  writeFileSync(setupPath, SETUP_MD, "utf8");
238
239
 
240
+ if (process.env.KOMPLIAN_CLI_QUIET === "1") {
241
+ console.log(`${changed ? c.green : c.dim}${changed ? "✓" : "○"}${c.reset} mcp`);
242
+ return;
243
+ }
239
244
  log("");
240
245
  const mcpMark = changed ? `${c.green}✓${c.reset}` : `${c.dim}○${c.reset}`;
241
- const mcpNote = changed ? "" : ` ${c.dim}(sin cambios)${c.reset}`;
246
+ const mcpNote = changed ? "" : ` ${c.dim}(unchanged)${c.reset}`;
242
247
  log(`${mcpMark} ${c.bold}mcp.json${c.reset} ${c.dim}${mcpPath}${c.reset}${mcpNote}`);
243
248
  log(`${c.green}✓${c.reset} ${c.bold}KOMPLIAN_MCP_SETUP.md${c.reset} ${c.dim}${setupPath}${c.reset}`);
244
249
  log("");
245
- log(`${c.bold}Siguiente${c.reset}`);
246
- log(` 1. Rellena tokens vacíos en Cursor (Settings → MCP) o edita ${c.bold}mcp.json${c.reset} en local.`);
247
- log(` 2. Activa en Cursor: ${c.dim}Atlassian + Chrome DevTools${c.reset} (ver guía arriba).`);
248
- log(` 3. Reinicia Cursor.`);
250
+ log(`${c.bold}Next${c.reset}`);
251
+ log(` 1. Fill empty tokens in Cursor (Settings → MCP) or edit ${c.bold}mcp.json${c.reset} locally.`);
252
+ log(` 2. Enable Atlassian + Chrome DevTools (see guide above).`);
253
+ log(` 3. Restart Cursor.`);
249
254
  log("");
250
- log(`${c.dim}Paquete npm komplian solo incluye *.mjs — nunca sube tu mcp.json.${c.reset}`);
255
+ log(`${c.dim}The komplian npm package only ships *.mjs — it never uploads your mcp.json.${c.reset}`);
251
256
  }