komplian 0.7.0 → 0.7.2
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/komplian-db-all-dev.mjs +32 -29
- package/komplian-localhost.mjs +73 -48
- package/komplian-mcp-tools.mjs +46 -41
- package/komplian-onboard.mjs +237 -116
- package/komplian-postman.mjs +35 -27
- package/komplian-setup.mjs +359 -168
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Opcional: `export POSTMAN_API_KEY=…` solo para la sesión actual (tiene priori
|
|
|
26
26
|
|
|
27
27
|
El comando llama a `GET https://api.getpostman.com/me` y **solo continúa** si el email de la cuenta es `@komplian.com`. **Si ya existen** la colección **Komplian API** y los entornos con el mismo nombre en ese workspace, se **actualizan**; si no, se crean.
|
|
28
28
|
|
|
29
|
-
**Variables de la API Komplian** (`apiKey`, `adminApiKey`, `workspaceId`, …) se rellenan en Postman automáticamente si están en `process.env` o en archivos `.env` (busca `api/.env`, `.env`, etc.; o `KOMPLIAN_DOTENV` / `--dotenv ruta`). Nombres típicos: `API_KEY`, `ADMIN_API_KEY`, `KOMPLIAN_WORKSPACE_ID`. Los JSON exportados en
|
|
29
|
+
**Variables de la API Komplian** (`apiKey`, `adminApiKey`, `workspaceId`, …) se rellenan en Postman automáticamente si están en `process.env` o en archivos `.env` (busca `api/.env`, `.env`, etc.; o `KOMPLIAN_DOTENV` / `--dotenv ruta`). Nombres típicos: `API_KEY`, `ADMIN_API_KEY`, `KOMPLIAN_WORKSPACE_ID`. Los JSON exportados en `~/.komplian/postman-export/` (o `--out`) **no** incluyen secretos (para no commitearlos).
|
|
30
30
|
|
|
31
31
|
- Solo exportar archivos (sin subir por API): `npx komplian postman --yes --export-only`
|
|
32
32
|
- Otro workspace: `POSTMAN_WORKSPACE_ID=<id>`
|
package/komplian-db-all-dev.mjs
CHANGED
|
@@ -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
|
|
152
|
-
const admin = (await rl.question(`${c.bold}URL
|
|
153
|
-
const web = (await rl.question(`${c.bold}URL
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
206
|
+
console.error(`${c.red}✗${c.reset} Not a Komplian monorepo.`);
|
|
205
207
|
process.exit(1);
|
|
206
208
|
}
|
|
207
209
|
|
|
208
|
-
log(`${c.cyan}━━
|
|
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
|
|
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
|
-
|
|
229
|
-
`${c.red}✗${c.reset}
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
}
|
package/komplian-localhost.mjs
CHANGED
|
@@ -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
|
|
388
|
+
log(`${c.bold}Local${c.reset}`);
|
|
374
389
|
if (!minimal) {
|
|
375
|
-
log(` ${c.cyan}
|
|
390
|
+
log(` ${c.cyan}api${c.reset} http://localhost:4000`);
|
|
376
391
|
}
|
|
377
|
-
log(` ${c.cyan}
|
|
392
|
+
log(` ${c.cyan}app${c.reset} http://localhost:3001`);
|
|
378
393
|
if (!minimal) {
|
|
379
|
-
log(` ${c.cyan}
|
|
380
|
-
log(` ${c.cyan}
|
|
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}
|
|
397
|
+
log(` ${c.cyan}web${c.reset} http://localhost:3003`);
|
|
383
398
|
}
|
|
384
|
-
log(` ${c.cyan}
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
507
|
-
|
|
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
|
-
|
|
514
|
-
`${c.yellow}⚠${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
|
-
|
|
538
|
+
logAlways("");
|
|
517
539
|
}
|
|
518
540
|
|
|
519
541
|
if (opts.envOnly) {
|
|
520
|
-
|
|
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
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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
|
-
|
|
546
|
-
|
|
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:
|
|
582
|
+
shell: useShell,
|
|
558
583
|
windowsHide: true,
|
|
559
584
|
env: { ...process.env },
|
|
560
585
|
}
|
package/komplian-mcp-tools.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Komplian MCP —
|
|
4
|
-
*
|
|
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
|
|
6
|
+
* No secrets in repo: empty env; fill in Cursor or via KOMPLIAN_MCP_SECRETS.env (local, gitignored).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
71
|
+
const SETUP_MD = `# KOMPLIAN — MCP in Cursor
|
|
71
72
|
|
|
72
|
-
|
|
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.
|
|
75
|
+
## 1. Servers in \`.cursor/mcp.json\` (stdio / npx)
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
Enable each row in **Cursor → Settings → MCP**. Fill \`env\` per the table.
|
|
77
78
|
|
|
78
|
-
| ID |
|
|
79
|
-
|
|
80
|
-
| **KOMPLIAN-github** | \`@modelcontextprotocol/server-github\` | GitHub API | \`GITHUB_PERSONAL_ACCESS_TOKEN\` (PAT).
|
|
81
|
-
| **KOMPLIAN-atlassian** | \`mcp-atlassian\` | Jira + Confluence (Cloud) | \`ATLASSIAN_EMAIL\` + \`ATLASSIAN_API_TOKEN\` ([
|
|
82
|
-
| **KOMPLIAN-sentry** | \`@sentry/mcp-server\` | Sentry |
|
|
83
|
-
| **KOMPLIAN-stripe** | \`@stripe/mcp\` | Stripe API | \`STRIPE_SECRET_KEY\` (restricted
|
|
84
|
-
| **KOMPLIAN-chrome-devtools** | \`chrome-devtools-mcp\` | Chrome (
|
|
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.
|
|
87
|
+
## 2. Optional: Cursor native connectors
|
|
87
88
|
|
|
88
|
-
|
|
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.
|
|
91
|
+
## 3. Restart
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
After editing \`mcp.json\`, **restart Cursor** to load MCP.
|
|
93
94
|
|
|
94
|
-
## 4.
|
|
95
|
+
## 4. Internal reference
|
|
95
96
|
|
|
96
|
-
\`.cursor/rules/mcp-integrations.mdc\` (org
|
|
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
|
-
|
|
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(`
|
|
158
|
+
log(`Usage: npx komplian mcp-tools [options] [monorepo-root]`);
|
|
158
159
|
log(``);
|
|
159
|
-
log(`
|
|
160
|
-
log(`
|
|
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}
|
|
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
|
|
165
|
-
log(` --force
|
|
166
|
-
log(` --dry-run
|
|
167
|
-
log(` --global
|
|
168
|
-
log(` -w, --workspace
|
|
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}
|
|
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
|
|
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}
|
|
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}(
|
|
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}
|
|
246
|
-
log(` 1.
|
|
247
|
-
log(` 2.
|
|
248
|
-
log(` 3.
|
|
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}
|
|
255
|
+
log(`${c.dim}The komplian npm package only ships *.mjs — it never uploads your mcp.json.${c.reset}`);
|
|
251
256
|
}
|