komplian 0.7.2 → 0.7.3
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/komplian-localhost.mjs +15 -8
- package/komplian-mcp-tools.mjs +12 -1
- package/komplian-onboard.mjs +147 -136
- package/komplian-setup.mjs +0 -6
- package/package.json +1 -1
package/komplian-localhost.mjs
CHANGED
|
@@ -519,12 +519,15 @@ export async function runLocalhost(argv) {
|
|
|
519
519
|
if (!cliQuiet()) {
|
|
520
520
|
log(`${c.cyan}━━ .env.local ━━${c.reset}`);
|
|
521
521
|
}
|
|
522
|
-
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
522
|
+
if (cliQuiet()) {
|
|
523
|
+
const labels = written.map((w) => w.label || "?").join(`${c.dim}·${c.reset} `);
|
|
524
|
+
logAlways(
|
|
525
|
+
` ${c.green}✓${c.reset} ${c.dim}.env.local${c.reset} ${labels}`
|
|
526
|
+
);
|
|
527
|
+
} else {
|
|
528
|
+
for (const w of written) {
|
|
529
|
+
const st = w.skipped ? `${c.dim}skip${c.reset}` : `${c.green}ok${c.reset}`;
|
|
530
|
+
const name = w.label || "?";
|
|
528
531
|
log(` ${st} ${name}`);
|
|
529
532
|
}
|
|
530
533
|
}
|
|
@@ -565,7 +568,7 @@ export async function runLocalhost(argv) {
|
|
|
565
568
|
});
|
|
566
569
|
|
|
567
570
|
if (cliQuiet()) {
|
|
568
|
-
logAlways(`${c.
|
|
571
|
+
logAlways(`${c.dim}dev servers · Ctrl+C stop${c.reset}`);
|
|
569
572
|
} else {
|
|
570
573
|
log(`${c.cyan}━━ dev servers (${services.length}) ━━${c.reset} ${c.dim}Ctrl+C stop${c.reset}`);
|
|
571
574
|
log("");
|
|
@@ -573,9 +576,13 @@ export async function runLocalhost(argv) {
|
|
|
573
576
|
|
|
574
577
|
const npx = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
575
578
|
const useShell = process.platform === "win32";
|
|
579
|
+
/** --raw avoids concurrently prefix logger bugs (e.g. prev.replace on Windows / npx). */
|
|
580
|
+
const concArgs = cliQuiet()
|
|
581
|
+
? ["--yes", "concurrently@9", "--raw", ...scripts]
|
|
582
|
+
: ["--yes", "concurrently@9", "-c", colors, "-n", names, ...scripts];
|
|
576
583
|
const child = spawn(
|
|
577
584
|
npx,
|
|
578
|
-
|
|
585
|
+
concArgs,
|
|
579
586
|
{
|
|
580
587
|
cwd: workspaceRoot,
|
|
581
588
|
stdio: "inherit",
|
package/komplian-mcp-tools.mjs
CHANGED
|
@@ -65,6 +65,15 @@ const KOMPLIAN_MCP_PRESET = {
|
|
|
65
65
|
args: ["-y", "chrome-devtools-mcp@latest"],
|
|
66
66
|
env: {},
|
|
67
67
|
},
|
|
68
|
+
/** Remote MCP — OAuth in Cursor (“Needs login”). */
|
|
69
|
+
"KOMPLIAN-vercel": {
|
|
70
|
+
url: "https://mcp.vercel.com",
|
|
71
|
+
},
|
|
72
|
+
/** Remote MCP — OAuth via mcp-remote (Neon docs). */
|
|
73
|
+
"KOMPLIAN-neon": {
|
|
74
|
+
command: "npx",
|
|
75
|
+
args: ["-y", "mcp-remote", "https://mcp.neon.tech/mcp"],
|
|
76
|
+
},
|
|
68
77
|
},
|
|
69
78
|
};
|
|
70
79
|
|
|
@@ -83,10 +92,12 @@ Enable each row in **Cursor → Settings → MCP**. Fill \`env\` per the table.
|
|
|
83
92
|
| **KOMPLIAN-sentry** | \`@sentry/mcp-server\` | Sentry | First time: browser login. **Komplian:** org \`komplian\`, \`regionUrl\` \`https://de.sentry.io\`, projects \`komplian-api\` / \`komplian-app\`. |
|
|
84
93
|
| **KOMPLIAN-stripe** | \`@stripe/mcp\` | Stripe API | \`STRIPE_SECRET_KEY\` (restricted / test in dev). [Stripe MCP docs](https://docs.stripe.com/mcp). |
|
|
85
94
|
| **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). |
|
|
95
|
+
| **KOMPLIAN-vercel** | \`url\` → \`https://mcp.vercel.com\` | Vercel projects & deploys | **OAuth** in Cursor (see [Vercel MCP](https://mcp.vercel.com/)). No token in JSON. |
|
|
96
|
+
| **KOMPLIAN-neon** | \`npx -y mcp-remote https://mcp.neon.tech/mcp\` | Neon Postgres / API | **OAuth** when the client starts (see [Neon MCP](https://neon.tech/docs/ai/neon-mcp-server)). Alt: local \`@neondatabase/mcp-server-neon\` + API key. |
|
|
86
97
|
|
|
87
98
|
## 2. Optional: Cursor native connectors
|
|
88
99
|
|
|
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.
|
|
100
|
+
For Cursor OAuth/UI connectors: **Settings → MCP** → **Atlassian**, **Sentry**, **Stripe**, **Chrome DevTools**, **Vercel**, **Neon**. They can coexist with **KOMPLIAN-*** entries; avoid duplicating the same capability twice.
|
|
90
101
|
|
|
91
102
|
## 3. Restart
|
|
92
103
|
|
package/komplian-onboard.mjs
CHANGED
|
@@ -46,31 +46,38 @@ function ux(s = "") {
|
|
|
46
46
|
console.log(s);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/** Block-letter logo + box frame (OpenClaw-style table). */
|
|
49
50
|
function banner() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
);
|
|
51
|
+
const art = [
|
|
52
|
+
"██╗ ██╗ ██████╗ ███╗ ███╗ ██████╗ ██╗ ██╗ █████╗ ███╗ ██╗",
|
|
53
|
+
"██║ ██╔╝ ██╔═══██╗ ████╗ ████║ ██╔══██╗ ██║ ██║ ██╔══██╗ ████╗ ██║",
|
|
54
|
+
"█████╔╝ ██║ ██║ ██╔████╔██║ ██████╔╝ ██║ ██║ ███████║ ██╔██╗ ██║",
|
|
55
|
+
"██╔═██╗ ██║ ██║ ██║╚██╔╝██║ ██╔═══╝ ██║ ██║ ██╔══██║ ██║╚██╗██║",
|
|
56
|
+
"██║ ██╗ ╚██████╔╝ ██║ ╚═╝ ██║ ██║ ███████╗ ██║ ██║ ██║ ██║ ╚████║",
|
|
57
|
+
"╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝",
|
|
58
|
+
];
|
|
59
|
+
const w = Math.max(...art.map((line) => [...line].length));
|
|
60
|
+
const pad = (line) => line + " ".repeat(w - [...line].length);
|
|
61
|
+
const horiz = "─".repeat(w + 2);
|
|
62
|
+
const b = `${c.cyan}${c.bold}`;
|
|
63
|
+
const x = c.reset;
|
|
64
|
+
ux(`${b}┌${horiz}┐${x}`);
|
|
65
|
+
for (const line of art) {
|
|
66
|
+
ux(`${b}│ ${pad(line)} │${x}`);
|
|
67
|
+
}
|
|
68
|
+
ux(`${b}└${horiz}┘${x}`);
|
|
69
|
+
ux(`${c.dim} Secure setup · GitHub CLI · Monorepo${c.reset}`);
|
|
70
|
+
ux("");
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
function
|
|
73
|
+
function startBatchSpinner(message) {
|
|
67
74
|
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
68
75
|
const cloud = `${c.blue}☁${c.reset}`;
|
|
69
76
|
let i = 0;
|
|
70
77
|
const id = setInterval(() => {
|
|
71
78
|
const fr = frames[i++ % frames.length];
|
|
72
79
|
process.stdout.write(
|
|
73
|
-
`\r ${cloud}
|
|
80
|
+
`\r ${cloud} ${c.cyan}${fr}${c.reset} ${c.dim}${message}${c.reset} `
|
|
74
81
|
);
|
|
75
82
|
}, 90);
|
|
76
83
|
return {
|
|
@@ -280,55 +287,27 @@ function isSafeTargetDir(abs) {
|
|
|
280
287
|
return !bad.includes(n);
|
|
281
288
|
}
|
|
282
289
|
|
|
283
|
-
function
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
return
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
if (status === "fail") {
|
|
292
|
-
return ` ${cloud} ${c.red}✗${c.reset} ${org}/${name} ${c.dim}failed${c.reset}`;
|
|
293
|
-
}
|
|
294
|
-
return ` ${cloud} ${c.cyan}…${c.reset} ${org}/${name} ${c.dim}cloning…${c.reset}`;
|
|
290
|
+
function summarizeCloneLine(repos, outcomes) {
|
|
291
|
+
const parts = repos.map((name) => {
|
|
292
|
+
const st = outcomes.get(name) || "fail";
|
|
293
|
+
if (st === "fail") return `${c.red}✗${c.reset} ${name}`;
|
|
294
|
+
if (st === "skip") return `${c.green}✓${c.reset} ${c.dim}${name}${c.reset}`;
|
|
295
|
+
return `${c.green}✓${c.reset} ${name}`;
|
|
296
|
+
});
|
|
297
|
+
return ` ${c.blue}☁${c.reset} ${parts.join(` `)}`;
|
|
295
298
|
}
|
|
296
299
|
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
ux(cloudLine(org, name, "skip"));
|
|
302
|
-
return true;
|
|
300
|
+
function summarizeDepsLine(results) {
|
|
301
|
+
const ran = results.filter((r) => !r.skipped);
|
|
302
|
+
if (ran.length === 0) {
|
|
303
|
+
return ` ${c.blue}☁${c.reset} ${c.dim}dependencies — nothing to install${c.reset}`;
|
|
303
304
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const tty = process.stdout.isTTY;
|
|
311
|
-
const spin = tty ? startRepoSpinner(name) : null;
|
|
312
|
-
if (!tty) {
|
|
313
|
-
ux(
|
|
314
|
-
`${c.blue}☁${c.reset} ${c.cyan}…${c.reset} ${c.bold}${name}${c.reset} ${c.dim}cloning…${c.reset}`
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const r = await runSpawn(cmd, args, workspace);
|
|
319
|
-
if (spin) spin.stop();
|
|
320
|
-
|
|
321
|
-
if (r.status === 0) {
|
|
322
|
-
ux(cloudLine(org, name, "ok"));
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
ux(cloudLine(org, name, "fail"));
|
|
326
|
-
const err = (r.stderr || "").trim();
|
|
327
|
-
if (err) {
|
|
328
|
-
if (q) console.error(`${c.dim}${err.slice(0, 500)}${c.reset}`);
|
|
329
|
-
else log(`${c.dim}${err}${c.reset}`);
|
|
330
|
-
}
|
|
331
|
-
return false;
|
|
305
|
+
const parts = ran.map((r) =>
|
|
306
|
+
r.ok
|
|
307
|
+
? `${c.green}✓${c.reset} ${r.name}`
|
|
308
|
+
: `${c.yellow}○${c.reset} ${r.name}`
|
|
309
|
+
);
|
|
310
|
+
return ` ${c.blue}☁${c.reset} ${parts.join(` `)}`;
|
|
332
311
|
}
|
|
333
312
|
|
|
334
313
|
function copyCursorPack(workspace, cursorRepoUrl) {
|
|
@@ -371,12 +350,13 @@ function npmQuietFlags() {
|
|
|
371
350
|
return audit ? [] : ["--no-audit", "--no-fund"];
|
|
372
351
|
}
|
|
373
352
|
|
|
374
|
-
function npmInstallOneRepo(dir, name) {
|
|
353
|
+
function npmInstallOneRepo(dir, name, opts = {}) {
|
|
354
|
+
const silent = opts.silent === true;
|
|
375
355
|
const pkg = join(dir, "package.json");
|
|
376
356
|
if (!existsSync(pkg)) return { ok: true, skipped: true };
|
|
377
357
|
|
|
378
358
|
const q = process.env.KOMPLIAN_CLI_QUIET === "1";
|
|
379
|
-
const stdio = q ? "ignore" : "inherit";
|
|
359
|
+
const stdio = silent || q ? "ignore" : "inherit";
|
|
380
360
|
|
|
381
361
|
const yarnLock = join(dir, "yarn.lock");
|
|
382
362
|
const pnpmLock = join(dir, "pnpm-lock.yaml");
|
|
@@ -384,17 +364,21 @@ function npmInstallOneRepo(dir, name) {
|
|
|
384
364
|
|
|
385
365
|
if (existsSync(yarnLock)) {
|
|
386
366
|
if (!canRun("yarn", ["--version"])) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
367
|
+
if (!silent) {
|
|
368
|
+
log(
|
|
369
|
+
`${c.yellow}○${c.reset} ${name} ${c.dim}(yarn.lock; install yarn or run yarn install manually)${c.reset}`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
390
372
|
return { ok: true, skipped: true };
|
|
391
373
|
}
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
374
|
+
if (!silent) {
|
|
375
|
+
if (q) {
|
|
376
|
+
ux(
|
|
377
|
+
` ${c.blue}☁${c.reset} ${c.cyan}…${c.reset} ${c.bold}${name}${c.reset} ${c.dim}yarn…${c.reset}`
|
|
378
|
+
);
|
|
379
|
+
} else {
|
|
380
|
+
log(`${c.dim}→${c.reset} ${name} ${c.dim}(yarn)${c.reset}`);
|
|
381
|
+
}
|
|
398
382
|
}
|
|
399
383
|
const r = spawnSync(
|
|
400
384
|
"yarn",
|
|
@@ -406,17 +390,21 @@ function npmInstallOneRepo(dir, name) {
|
|
|
406
390
|
|
|
407
391
|
if (existsSync(pnpmLock)) {
|
|
408
392
|
if (!canRun("pnpm", ["--version"])) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
393
|
+
if (!silent) {
|
|
394
|
+
log(
|
|
395
|
+
`${c.yellow}○${c.reset} ${name} ${c.dim}(pnpm-lock; install pnpm or run pnpm install manually)${c.reset}`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
412
398
|
return { ok: true, skipped: true };
|
|
413
399
|
}
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
400
|
+
if (!silent) {
|
|
401
|
+
if (q) {
|
|
402
|
+
ux(
|
|
403
|
+
` ${c.blue}☁${c.reset} ${c.cyan}…${c.reset} ${c.bold}${name}${c.reset} ${c.dim}pnpm…${c.reset}`
|
|
404
|
+
);
|
|
405
|
+
} else {
|
|
406
|
+
log(`${c.dim}→${c.reset} ${name} ${c.dim}(pnpm)${c.reset}`);
|
|
407
|
+
}
|
|
420
408
|
}
|
|
421
409
|
const r = spawnSync(
|
|
422
410
|
"pnpm",
|
|
@@ -427,34 +415,42 @@ function npmInstallOneRepo(dir, name) {
|
|
|
427
415
|
}
|
|
428
416
|
|
|
429
417
|
if (!canRun("npm", ["--version"])) {
|
|
430
|
-
|
|
418
|
+
if (!silent) {
|
|
419
|
+
log(`${c.yellow}○${c.reset} npm not in PATH — skipping ${name}`);
|
|
420
|
+
}
|
|
431
421
|
return { ok: true, skipped: true };
|
|
432
422
|
}
|
|
433
423
|
|
|
434
424
|
const quiet = npmQuietFlags();
|
|
435
425
|
|
|
436
426
|
if (existsSync(npmLock)) {
|
|
437
|
-
if (
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
427
|
+
if (!silent) {
|
|
428
|
+
if (q) {
|
|
429
|
+
ux(
|
|
430
|
+
` ${c.blue}☁${c.reset} ${c.cyan}…${c.reset} ${c.bold}${name}${c.reset} ${c.dim}npm ci…${c.reset}`
|
|
431
|
+
);
|
|
432
|
+
} else {
|
|
433
|
+
log(`${c.dim}→${c.reset} ${name} ${c.dim}(npm ci)${c.reset}`);
|
|
434
|
+
}
|
|
443
435
|
}
|
|
444
436
|
const r = spawnSync("npm", ["ci", ...quiet], spawnWin({ cwd: dir, stdio }));
|
|
445
437
|
if (r.status === 0) return { ok: true, skipped: false };
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
438
|
+
if (!silent) {
|
|
439
|
+
log(
|
|
440
|
+
`${c.yellow}○${c.reset} ${name}: npm ci failed (lock out of sync?). ${c.dim}Try npm install in that repo.${c.reset}`
|
|
441
|
+
);
|
|
442
|
+
}
|
|
449
443
|
return { ok: false, skipped: false };
|
|
450
444
|
}
|
|
451
445
|
|
|
452
|
-
if (
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
446
|
+
if (!silent) {
|
|
447
|
+
if (q) {
|
|
448
|
+
ux(
|
|
449
|
+
` ${c.blue}☁${c.reset} ${c.cyan}…${c.reset} ${c.bold}${name}${c.reset} ${c.dim}npm install…${c.reset}`
|
|
450
|
+
);
|
|
451
|
+
} else {
|
|
452
|
+
log(`${c.dim}→${c.reset} ${name} ${c.dim}(npm install — no new lockfile)${c.reset}`);
|
|
453
|
+
}
|
|
458
454
|
}
|
|
459
455
|
const r = spawnSync(
|
|
460
456
|
"npm",
|
|
@@ -464,33 +460,16 @@ function npmInstallOneRepo(dir, name) {
|
|
|
464
460
|
return { ok: r.status === 0, skipped: false };
|
|
465
461
|
}
|
|
466
462
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
log("");
|
|
471
|
-
log(`${c.cyan}━━ dependencies ━━${c.reset}`);
|
|
472
|
-
} else {
|
|
473
|
-
ux("");
|
|
474
|
-
ux(`${c.cyan}Dependencies${c.reset}`);
|
|
475
|
-
}
|
|
463
|
+
/** Silent installs for batch UX (single spinner + one summary line). */
|
|
464
|
+
function npmInstallBatch(workspace) {
|
|
465
|
+
const results = [];
|
|
476
466
|
for (const ent of readdirSync(workspace)) {
|
|
477
467
|
const d = join(workspace, ent);
|
|
478
468
|
if (!statSync(d).isDirectory()) continue;
|
|
479
|
-
const { ok, skipped } = npmInstallOneRepo(d, ent);
|
|
480
|
-
|
|
481
|
-
if (q) {
|
|
482
|
-
const cloud = `${c.blue}☁${c.reset}`;
|
|
483
|
-
if (ok) {
|
|
484
|
-
ux(` ${cloud} ${c.green}✓${c.reset} ${c.bold}${ent}${c.reset} ${c.dim}deps${c.reset}`);
|
|
485
|
-
} else {
|
|
486
|
-
ux(` ${cloud} ${c.yellow}○${c.reset} ${c.bold}${ent}${c.reset} ${c.dim}deps${c.reset}`);
|
|
487
|
-
}
|
|
488
|
-
} else if (ok) {
|
|
489
|
-
log(`${c.green}✓${c.reset} ${ent}`);
|
|
490
|
-
} else {
|
|
491
|
-
log(`${c.yellow}○${c.reset} ${ent}`);
|
|
492
|
-
}
|
|
469
|
+
const { ok, skipped } = npmInstallOneRepo(d, ent, { silent: true });
|
|
470
|
+
results.push({ name: ent, ok, skipped });
|
|
493
471
|
}
|
|
472
|
+
return results;
|
|
494
473
|
}
|
|
495
474
|
|
|
496
475
|
function usage() {
|
|
@@ -721,36 +700,68 @@ async function main() {
|
|
|
721
700
|
mkdirSync(abs, { recursive: true });
|
|
722
701
|
const q = process.env.KOMPLIAN_CLI_QUIET === "1";
|
|
723
702
|
ux("");
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
if (team) log(`${c.cyan}━━ Team ━━${c.reset} ${c.bold}${team}${c.reset}`);
|
|
728
|
-
log(`${c.cyan}━━ Repos (${repos.length}) ━━${c.reset}`);
|
|
729
|
-
} else {
|
|
730
|
-
ux(`${c.dim}Workspace:${c.reset} ${abs}`);
|
|
731
|
-
if (team) ux(`${c.dim}Team:${c.reset} ${team}`);
|
|
732
|
-
ux(`${c.cyan}Repositories${c.reset} ${c.dim}(${repos.length})${c.reset}`);
|
|
733
|
-
}
|
|
703
|
+
ux(`${c.dim}${abs}${c.reset}`);
|
|
704
|
+
if (team) ux(`${c.dim}team · ${team}${c.reset}`);
|
|
705
|
+
ux(`${c.dim}${repos.join(" · ")}${c.reset}`);
|
|
734
706
|
ux("");
|
|
735
707
|
|
|
708
|
+
const outcomes = new Map();
|
|
709
|
+
let spin = process.stdout.isTTY ? startBatchSpinner("Cloning repositories…") : null;
|
|
710
|
+
if (!spin) {
|
|
711
|
+
ux(` ${c.blue}☁${c.reset} ${c.dim}Cloning repositories…${c.reset}`);
|
|
712
|
+
}
|
|
713
|
+
|
|
736
714
|
let failed = 0;
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
715
|
+
try {
|
|
716
|
+
for (const name of repos) {
|
|
717
|
+
const gitDir = join(abs, name, ".git");
|
|
718
|
+
if (existsSync(gitDir)) {
|
|
719
|
+
outcomes.set(name, "skip");
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
const cloneArgs = args.ssh
|
|
723
|
+
? ["clone", `git@github.com:${org}/${name}.git`, name]
|
|
724
|
+
: ["repo", "clone", `${org}/${name}`, name];
|
|
725
|
+
const cmd = args.ssh ? "git" : "gh";
|
|
726
|
+
const r = await runSpawn(cmd, cloneArgs, abs);
|
|
727
|
+
if (r.status === 0) {
|
|
728
|
+
outcomes.set(name, "ok");
|
|
729
|
+
} else {
|
|
730
|
+
outcomes.set(name, "fail");
|
|
731
|
+
failed += 1;
|
|
732
|
+
const err = (r.stderr || "").trim();
|
|
733
|
+
if (err) console.error(`${c.dim}${err.slice(0, 500)}${c.reset}`);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
} finally {
|
|
737
|
+
if (spin) spin.stop();
|
|
740
738
|
}
|
|
741
739
|
|
|
740
|
+
ux(summarizeCloneLine(repos, outcomes));
|
|
741
|
+
|
|
742
742
|
copyCursorPack(abs, process.env.KOMPLIAN_CURSOR_REPO);
|
|
743
743
|
|
|
744
744
|
if (args.install) {
|
|
745
|
-
|
|
745
|
+
spin = process.stdout.isTTY ? startBatchSpinner("Installing dependencies…") : null;
|
|
746
|
+
if (!spin) {
|
|
747
|
+
ux(` ${c.blue}☁${c.reset} ${c.dim}Installing dependencies…${c.reset}`);
|
|
748
|
+
}
|
|
749
|
+
let depResults = [];
|
|
750
|
+
try {
|
|
751
|
+
depResults = npmInstallBatch(abs);
|
|
752
|
+
} finally {
|
|
753
|
+
if (spin) spin.stop();
|
|
754
|
+
}
|
|
755
|
+
ux(summarizeDepsLine(depResults));
|
|
746
756
|
}
|
|
747
757
|
|
|
748
758
|
ux("");
|
|
749
|
-
ux(`${c.cyan}━━ Done ━━${c.reset}`);
|
|
750
759
|
if (failed > 0) {
|
|
751
760
|
ux(
|
|
752
761
|
`${c.yellow}○${c.reset} ${failed} repo(s) failed — check access and retry.`
|
|
753
762
|
);
|
|
763
|
+
} else {
|
|
764
|
+
ux(`${c.green}✓${c.reset} ${c.dim}Repositories ready${c.reset}`);
|
|
754
765
|
}
|
|
755
766
|
ux(`${c.green}✓${c.reset} Open in Cursor: ${c.bold}File → Open Folder → ${abs}${c.reset}`);
|
|
756
767
|
if (!q) {
|
package/komplian-setup.mjs
CHANGED
|
@@ -583,7 +583,6 @@ export async function runSetup(argv) {
|
|
|
583
583
|
|
|
584
584
|
mkdirSync(workspaceAbs, { recursive: true });
|
|
585
585
|
|
|
586
|
-
out(`${c.cyan}1/5${c.reset} repos`);
|
|
587
586
|
const onboardArgs = ["--yes"];
|
|
588
587
|
if (opts.team) onboardArgs.push("-t", opts.team);
|
|
589
588
|
if (opts.allRepos) onboardArgs.push("--all-repos");
|
|
@@ -629,7 +628,6 @@ export async function runSetup(argv) {
|
|
|
629
628
|
}
|
|
630
629
|
|
|
631
630
|
if (useBrowser && (needsPostmanKey || needsDbUrls)) {
|
|
632
|
-
out(`${c.cyan}browser${c.reset} local form`);
|
|
633
631
|
try {
|
|
634
632
|
const lp = neonOAuth && needsDbUrls ? parseListenFromRedirectUri() : null;
|
|
635
633
|
const form = await runSetupBrowserForm({
|
|
@@ -652,16 +650,12 @@ export async function runSetup(argv) {
|
|
|
652
650
|
}
|
|
653
651
|
}
|
|
654
652
|
|
|
655
|
-
out(`${c.cyan}2/5${c.reset} postman`);
|
|
656
653
|
await runPostman(["--yes"]);
|
|
657
654
|
|
|
658
|
-
out(`${c.cyan}3/5${c.reset} mcp`);
|
|
659
655
|
await runMcpTools(["--yes"]);
|
|
660
656
|
|
|
661
|
-
out(`${c.cyan}4/5${c.reset} databases`);
|
|
662
657
|
await runDbAllDev(["--yes", "-w", monorepoRoot]);
|
|
663
658
|
|
|
664
|
-
out(`${c.cyan}5/5${c.reset} dev`);
|
|
665
659
|
await runLocalhost(["--yes"]);
|
|
666
660
|
|
|
667
661
|
out(`${c.green}✓${c.reset} ready`);
|