komplian 0.7.1 → 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/README.md +1 -1
- package/komplian-localhost.mjs +15 -8
- package/komplian-mcp-tools.mjs +12 -1
- package/komplian-onboard.mjs +289 -174
- package/komplian-postman.mjs +20 -9
- package/komplian-setup.mjs +0 -6
- package/package.json +1 -1
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-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
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* npx komplian onboard --yes
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { spawnSync, spawn } from "node:child_process";
|
|
12
12
|
import { existsSync, readFileSync, mkdirSync, cpSync, rmSync, readdirSync, statSync } from "node:fs";
|
|
13
13
|
import { dirname, join, resolve, normalize } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
@@ -41,21 +41,73 @@ function log(s = "") {
|
|
|
41
41
|
console.log(s);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/** Branding and repo progress: always visible (even when KOMPLIAN_CLI_QUIET=1). */
|
|
45
|
+
function ux(s = "") {
|
|
46
|
+
console.log(s);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Block-letter logo + box frame (OpenClaw-style table). */
|
|
44
50
|
function banner() {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
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("");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function startBatchSpinner(message) {
|
|
74
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
75
|
+
const cloud = `${c.blue}☁${c.reset}`;
|
|
76
|
+
let i = 0;
|
|
77
|
+
const id = setInterval(() => {
|
|
78
|
+
const fr = frames[i++ % frames.length];
|
|
79
|
+
process.stdout.write(
|
|
80
|
+
`\r ${cloud} ${c.cyan}${fr}${c.reset} ${c.dim}${message}${c.reset} `
|
|
81
|
+
);
|
|
82
|
+
}, 90);
|
|
83
|
+
return {
|
|
84
|
+
stop() {
|
|
85
|
+
clearInterval(id);
|
|
86
|
+
process.stdout.write("\r\x1b[K");
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function runSpawn(cmd, args, cwd) {
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
const child = spawn(cmd, args, {
|
|
94
|
+
...spawnWin({
|
|
95
|
+
cwd,
|
|
96
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
97
|
+
}),
|
|
98
|
+
});
|
|
99
|
+
let stderr = "";
|
|
100
|
+
child.stderr?.setEncoding?.("utf8");
|
|
101
|
+
child.stderr?.on("data", (d) => {
|
|
102
|
+
stderr += String(d);
|
|
103
|
+
});
|
|
104
|
+
child.on("close", (code) => {
|
|
105
|
+
resolve({ status: code === 0 ? 0 : code ?? 1, stderr });
|
|
106
|
+
});
|
|
107
|
+
child.on("error", (err) => {
|
|
108
|
+
resolve({ status: 1, stderr: String(err?.message || err) });
|
|
109
|
+
});
|
|
110
|
+
});
|
|
59
111
|
}
|
|
60
112
|
|
|
61
113
|
function ghOk() {
|
|
@@ -71,8 +123,8 @@ function ghOk() {
|
|
|
71
123
|
}
|
|
72
124
|
|
|
73
125
|
function runGhAuth() {
|
|
74
|
-
|
|
75
|
-
`${c.yellow}→${c.reset}
|
|
126
|
+
ux(
|
|
127
|
+
`${c.yellow}→${c.reset} Opening ${c.bold}GitHub${c.reset} in your browser (OAuth). Your password is not shown here.`
|
|
76
128
|
);
|
|
77
129
|
const r = spawnSync(
|
|
78
130
|
"gh",
|
|
@@ -102,32 +154,32 @@ function verifyOrgMembership(org) {
|
|
|
102
154
|
try {
|
|
103
155
|
const j = JSON.parse(mem.stdout);
|
|
104
156
|
if (j.state === "active") return;
|
|
105
|
-
|
|
106
|
-
`${c.red}✗${c.reset}
|
|
157
|
+
console.error(
|
|
158
|
+
`${c.red}✗${c.reset} Org ${c.bold}${org}${c.reset} membership not active (state: ${j.state || "?"}).`
|
|
107
159
|
);
|
|
108
160
|
process.exit(1);
|
|
109
161
|
} catch {
|
|
110
|
-
|
|
162
|
+
console.error(`${c.red}✗${c.reset} Invalid response while verifying org membership.`);
|
|
111
163
|
process.exit(1);
|
|
112
164
|
}
|
|
113
165
|
}
|
|
114
166
|
const hint = (mem.stderr + mem.stdout).toLowerCase();
|
|
115
167
|
if (hint.includes("404") || hint.includes("not found")) {
|
|
116
|
-
|
|
117
|
-
`${c.red}✗${c.reset}
|
|
168
|
+
console.error(
|
|
169
|
+
`${c.red}✗${c.reset} This account is ${c.bold}not a member${c.reset} of org ${c.bold}${org}${c.reset}.`
|
|
118
170
|
);
|
|
119
|
-
|
|
120
|
-
`${c.dim}
|
|
171
|
+
console.error(
|
|
172
|
+
`${c.dim} Wrong account? gh auth logout && gh auth login -h github.com -s repo -s read:org -w${c.reset}`
|
|
121
173
|
);
|
|
122
174
|
process.exit(1);
|
|
123
175
|
}
|
|
124
176
|
if (hint.includes("403") || hint.includes("read:org") || hint.includes("scope")) {
|
|
125
|
-
|
|
126
|
-
|
|
177
|
+
console.error(`${c.red}✗${c.reset} GitHub CLI needs ${c.bold}read:org${c.reset} scope.`);
|
|
178
|
+
console.error(`${c.dim} gh auth refresh -h github.com -s repo -s read:org${c.reset}`);
|
|
127
179
|
process.exit(1);
|
|
128
180
|
}
|
|
129
|
-
|
|
130
|
-
`${c.red}✗${c.reset}
|
|
181
|
+
console.error(
|
|
182
|
+
`${c.red}✗${c.reset} Could not verify org (exit ${mem.status}):\n${c.dim}${(mem.stderr || mem.stdout).trim()}${c.reset}`
|
|
131
183
|
);
|
|
132
184
|
process.exit(1);
|
|
133
185
|
}
|
|
@@ -159,10 +211,12 @@ function needCmd(name, hint = "") {
|
|
|
159
211
|
? canRun("git", ["--version"])
|
|
160
212
|
: canRun(name, ["--version"]);
|
|
161
213
|
if (!ok) {
|
|
162
|
-
|
|
214
|
+
console.error(
|
|
215
|
+
`${c.red}✗${c.reset} Cannot run ${c.bold}${name}${c.reset} (PATH or install?).${hint ? ` ${hint}` : ""}`
|
|
216
|
+
);
|
|
163
217
|
if (IS_WIN) {
|
|
164
|
-
|
|
165
|
-
`${c.dim} Windows:
|
|
218
|
+
console.error(
|
|
219
|
+
`${c.dim} Windows: restart the terminal after installing gh/git, or reboot to refresh PATH.${c.reset}`
|
|
166
220
|
);
|
|
167
221
|
}
|
|
168
222
|
process.exit(1);
|
|
@@ -180,7 +234,7 @@ function ghRepoList(org) {
|
|
|
180
234
|
spawnWin({ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] })
|
|
181
235
|
);
|
|
182
236
|
if (r.status !== 0) {
|
|
183
|
-
|
|
237
|
+
console.error(`${c.red}✗${c.reset} gh repo list failed:\n${r.stderr || r.stdout}`);
|
|
184
238
|
process.exit(1);
|
|
185
239
|
}
|
|
186
240
|
const rows = JSON.parse(r.stdout || "[]");
|
|
@@ -209,8 +263,8 @@ function resolveRepos(cfg, org, teamArg, allRepos) {
|
|
|
209
263
|
|
|
210
264
|
const teams = cfg.teams || {};
|
|
211
265
|
if (!teams[team]) {
|
|
212
|
-
|
|
213
|
-
`${c.red}✗${c.reset}
|
|
266
|
+
console.error(
|
|
267
|
+
`${c.red}✗${c.reset} Unknown team ${c.bold}${team}${c.reset}. Valid: ${Object.keys(teams).sort().join(", ")}`
|
|
214
268
|
);
|
|
215
269
|
process.exit(2);
|
|
216
270
|
}
|
|
@@ -233,52 +287,27 @@ function isSafeTargetDir(abs) {
|
|
|
233
287
|
return !bad.includes(n);
|
|
234
288
|
}
|
|
235
289
|
|
|
236
|
-
function
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
return
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
if (status === "fail") {
|
|
245
|
-
return ` ${cloud} ${c.red}✗${c.reset} ${org}/${name} ${c.dim}falló${c.reset}`;
|
|
246
|
-
}
|
|
247
|
-
return ` ${cloud} ${c.cyan}…${c.reset} ${org}/${name} ${c.dim}clonando…${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(` `)}`;
|
|
248
298
|
}
|
|
249
299
|
|
|
250
|
-
function
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
: ["repo", "clone", `${org}/${name}`, name];
|
|
262
|
-
const cmd = useSsh ? "git" : "gh";
|
|
263
|
-
const r = spawnSync(cmd, args, {
|
|
264
|
-
...spawnWin({
|
|
265
|
-
cwd: workspace,
|
|
266
|
-
encoding: "utf8",
|
|
267
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
268
|
-
}),
|
|
269
|
-
});
|
|
270
|
-
if (!q) process.stdout.write("\r\x1b[K");
|
|
271
|
-
if (r.status === 0) {
|
|
272
|
-
if (q) console.log(`${c.green}✓${c.reset} ${name}`);
|
|
273
|
-
else log(cloudLine(org, name, "ok"));
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
if (q) console.error(`${c.red}✗${c.reset} ${name}`);
|
|
277
|
-
else {
|
|
278
|
-
log(cloudLine(org, name, "fail"));
|
|
279
|
-
if (r.stderr) log(`${c.dim}${r.stderr.trim()}${c.reset}`);
|
|
280
|
-
}
|
|
281
|
-
return false;
|
|
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}`;
|
|
304
|
+
}
|
|
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(` `)}`;
|
|
282
311
|
}
|
|
283
312
|
|
|
284
313
|
function copyCursorPack(workspace, cursorRepoUrl) {
|
|
@@ -286,7 +315,7 @@ function copyCursorPack(workspace, cursorRepoUrl) {
|
|
|
286
315
|
if (cursorRepoUrl && String(cursorRepoUrl).trim()) {
|
|
287
316
|
const tmp = join(workspace, ".cursor-bootstrap-tmp");
|
|
288
317
|
rmSync(tmp, { recursive: true, force: true });
|
|
289
|
-
|
|
318
|
+
ux(`${c.dim}→${c.reset} Cursor rules pack…`);
|
|
290
319
|
const r = spawnSync(
|
|
291
320
|
"git",
|
|
292
321
|
["clone", "--depth", "1", String(cursorRepoUrl).trim(), tmp],
|
|
@@ -300,15 +329,18 @@ function copyCursorPack(workspace, cursorRepoUrl) {
|
|
|
300
329
|
rmSync(rootCursor, { recursive: true, force: true });
|
|
301
330
|
cpSync(join(tmp, ".cursor"), rootCursor, { recursive: true });
|
|
302
331
|
rmSync(tmp, { recursive: true, force: true });
|
|
303
|
-
|
|
332
|
+
ux(`${c.green}✓${c.reset} ${c.bold}.cursor${c.reset} ${c.dim}(KOMPLIAN_CURSOR_REPO)${c.reset}`);
|
|
304
333
|
return;
|
|
305
334
|
}
|
|
306
335
|
rmSync(tmp, { recursive: true, force: true });
|
|
307
|
-
|
|
336
|
+
ux(
|
|
337
|
+
`${c.yellow}○${c.reset} KOMPLIAN_CURSOR_REPO: clone failed or no .cursor/ at repo root`
|
|
338
|
+
);
|
|
339
|
+
} else if (!process.env.KOMPLIAN_CLI_QUIET) {
|
|
340
|
+
log(
|
|
341
|
+
`${c.dim}○ No .cursor/ (optional: KOMPLIAN_CURSOR_REPO=<git url>).${c.reset}`
|
|
342
|
+
);
|
|
308
343
|
}
|
|
309
|
-
log(
|
|
310
|
-
`${c.dim}○ Sin .cursor/ en el workspace (opcional: KOMPLIAN_CURSOR_REPO=<url git>).${c.reset}`
|
|
311
|
-
);
|
|
312
344
|
}
|
|
313
345
|
|
|
314
346
|
/** Sin esto, `npm install` crea o retoca package-lock.json y git muestra cambios sin querer. */
|
|
@@ -318,12 +350,13 @@ function npmQuietFlags() {
|
|
|
318
350
|
return audit ? [] : ["--no-audit", "--no-fund"];
|
|
319
351
|
}
|
|
320
352
|
|
|
321
|
-
function npmInstallOneRepo(dir, name) {
|
|
353
|
+
function npmInstallOneRepo(dir, name, opts = {}) {
|
|
354
|
+
const silent = opts.silent === true;
|
|
322
355
|
const pkg = join(dir, "package.json");
|
|
323
356
|
if (!existsSync(pkg)) return { ok: true, skipped: true };
|
|
324
357
|
|
|
325
|
-
const
|
|
326
|
-
|
|
358
|
+
const q = process.env.KOMPLIAN_CLI_QUIET === "1";
|
|
359
|
+
const stdio = silent || q ? "ignore" : "inherit";
|
|
327
360
|
|
|
328
361
|
const yarnLock = join(dir, "yarn.lock");
|
|
329
362
|
const pnpmLock = join(dir, "pnpm-lock.yaml");
|
|
@@ -331,12 +364,22 @@ function npmInstallOneRepo(dir, name) {
|
|
|
331
364
|
|
|
332
365
|
if (existsSync(yarnLock)) {
|
|
333
366
|
if (!canRun("yarn", ["--version"])) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
+
}
|
|
337
372
|
return { ok: true, skipped: true };
|
|
338
373
|
}
|
|
339
|
-
|
|
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
|
+
}
|
|
382
|
+
}
|
|
340
383
|
const r = spawnSync(
|
|
341
384
|
"yarn",
|
|
342
385
|
["install", "--frozen-lockfile"],
|
|
@@ -347,12 +390,22 @@ function npmInstallOneRepo(dir, name) {
|
|
|
347
390
|
|
|
348
391
|
if (existsSync(pnpmLock)) {
|
|
349
392
|
if (!canRun("pnpm", ["--version"])) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
+
}
|
|
353
398
|
return { ok: true, skipped: true };
|
|
354
399
|
}
|
|
355
|
-
|
|
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
|
+
}
|
|
408
|
+
}
|
|
356
409
|
const r = spawnSync(
|
|
357
410
|
"pnpm",
|
|
358
411
|
["install", "--frozen-lockfile"],
|
|
@@ -362,23 +415,43 @@ function npmInstallOneRepo(dir, name) {
|
|
|
362
415
|
}
|
|
363
416
|
|
|
364
417
|
if (!canRun("npm", ["--version"])) {
|
|
365
|
-
|
|
418
|
+
if (!silent) {
|
|
419
|
+
log(`${c.yellow}○${c.reset} npm not in PATH — skipping ${name}`);
|
|
420
|
+
}
|
|
366
421
|
return { ok: true, skipped: true };
|
|
367
422
|
}
|
|
368
423
|
|
|
369
424
|
const quiet = npmQuietFlags();
|
|
370
425
|
|
|
371
426
|
if (existsSync(npmLock)) {
|
|
372
|
-
|
|
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
|
+
}
|
|
435
|
+
}
|
|
373
436
|
const r = spawnSync("npm", ["ci", ...quiet], spawnWin({ cwd: dir, stdio }));
|
|
374
437
|
if (r.status === 0) return { ok: true, skipped: false };
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
+
}
|
|
378
443
|
return { ok: false, skipped: false };
|
|
379
444
|
}
|
|
380
445
|
|
|
381
|
-
|
|
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
|
+
}
|
|
454
|
+
}
|
|
382
455
|
const r = spawnSync(
|
|
383
456
|
"npm",
|
|
384
457
|
["install", ...quiet, "--no-package-lock"],
|
|
@@ -387,52 +460,47 @@ function npmInstallOneRepo(dir, name) {
|
|
|
387
460
|
return { ok: r.status === 0, skipped: false };
|
|
388
461
|
}
|
|
389
462
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
log("");
|
|
394
|
-
log(`${c.cyan}━━ dependencies ━━${c.reset}`);
|
|
395
|
-
}
|
|
463
|
+
/** Silent installs for batch UX (single spinner + one summary line). */
|
|
464
|
+
function npmInstallBatch(workspace) {
|
|
465
|
+
const results = [];
|
|
396
466
|
for (const ent of readdirSync(workspace)) {
|
|
397
467
|
const d = join(workspace, ent);
|
|
398
468
|
if (!statSync(d).isDirectory()) continue;
|
|
399
|
-
const { ok, skipped } = npmInstallOneRepo(d, ent);
|
|
400
|
-
|
|
401
|
-
if (q) {
|
|
402
|
-
console.log(`${ok ? c.green + "✓" + c.reset : c.yellow + "○" + c.reset} ${ent}`);
|
|
403
|
-
} else if (ok) {
|
|
404
|
-
log(`${c.green}✓${c.reset} ${ent}`);
|
|
405
|
-
} else {
|
|
406
|
-
log(`${c.yellow}○${c.reset} ${ent}`);
|
|
407
|
-
}
|
|
469
|
+
const { ok, skipped } = npmInstallOneRepo(d, ent, { silent: true });
|
|
470
|
+
results.push({ name: ent, ok, skipped });
|
|
408
471
|
}
|
|
472
|
+
return results;
|
|
409
473
|
}
|
|
410
474
|
|
|
411
475
|
function usage() {
|
|
412
|
-
log(`
|
|
413
|
-
log(
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
log(`
|
|
417
|
-
log(`
|
|
418
|
-
log(`
|
|
419
|
-
log(`
|
|
420
|
-
log(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
log(`
|
|
424
|
-
log(
|
|
425
|
-
log(
|
|
426
|
-
log(
|
|
427
|
-
log(`
|
|
428
|
-
log(`
|
|
429
|
-
log(
|
|
430
|
-
log(`
|
|
431
|
-
log(`
|
|
432
|
-
log(` --
|
|
433
|
-
log(` --
|
|
434
|
-
log(`
|
|
435
|
-
log(` -
|
|
476
|
+
console.log(`Usage: komplian setup | onboard | postman | mcp-tools | db:all:dev | localhost | db …`);
|
|
477
|
+
console.log(
|
|
478
|
+
` ${c.bold}All-in-one:${c.reset} ${c.cyan}npx komplian setup${c.reset} ${c.dim}(onboard+postman+mcp+db+localhost; browser form if needed)${c.reset}`
|
|
479
|
+
);
|
|
480
|
+
console.log(` ${c.bold}Step by step:${c.reset}`);
|
|
481
|
+
console.log(` 1. npx komplian onboard --yes`);
|
|
482
|
+
console.log(` 2. npx komplian postman --yes ${c.dim}(@komplian.com)${c.reset}`);
|
|
483
|
+
console.log(` 3. npx komplian mcp-tools --yes`);
|
|
484
|
+
console.log(
|
|
485
|
+
` 4. npx komplian db:all:dev ${c.dim}(Postman + 3 dev URLs → ~/.komplian + .env.local)${c.reset}`
|
|
486
|
+
);
|
|
487
|
+
console.log(` 5. npx komplian localhost --yes`);
|
|
488
|
+
console.log(``);
|
|
489
|
+
console.log(` npx komplian db:app:development ${c.dim}(psql one DB)${c.reset}`);
|
|
490
|
+
console.log(``);
|
|
491
|
+
console.log(` Once: gh auth login -h github.com -s repo -s read:org -w`);
|
|
492
|
+
console.log(` Requires: Node 18+, git, GitHub CLI (gh)`);
|
|
493
|
+
console.log(``);
|
|
494
|
+
console.log(` onboard implies --install unless --no-install`);
|
|
495
|
+
console.log(` [folder] Target (default: cwd, not ~/komplian)`);
|
|
496
|
+
console.log(` -y, --yes Non-interactive (default team from JSON)`);
|
|
497
|
+
console.log(` -t, --team <slug> Team in komplian-team-repos.json`);
|
|
498
|
+
console.log(` -i, --install npm install in each repo with package.json`);
|
|
499
|
+
console.log(` --no-install Skip npm install`);
|
|
500
|
+
console.log(` --all-repos All visible repos (minus exclude_from_all)`);
|
|
501
|
+
console.log(` --ssh Clone with git@github.com:…`);
|
|
502
|
+
console.log(` --list-teams Print team slugs (JSON only) and exit`);
|
|
503
|
+
console.log(` -h, --help`);
|
|
436
504
|
}
|
|
437
505
|
|
|
438
506
|
function parseArgs(argv) {
|
|
@@ -459,8 +527,8 @@ function parseArgs(argv) {
|
|
|
459
527
|
else if (a === "-h" || a === "--help") out.help = true;
|
|
460
528
|
else if (a === "-t" || a === "--team") {
|
|
461
529
|
out.team = argv[++i] || "";
|
|
462
|
-
}
|
|
463
|
-
|
|
530
|
+
} else if (a.startsWith("-")) {
|
|
531
|
+
console.error(`${c.red}✗${c.reset} Unknown option: ${a}`);
|
|
464
532
|
usage();
|
|
465
533
|
process.exit(1);
|
|
466
534
|
} else rest.push(a);
|
|
@@ -560,20 +628,22 @@ async function main() {
|
|
|
560
628
|
}
|
|
561
629
|
|
|
562
630
|
if (!existsSync(configPath)) {
|
|
563
|
-
|
|
631
|
+
console.error(`${c.red}✗${c.reset} Missing config: ${configPath}`);
|
|
564
632
|
process.exit(1);
|
|
565
633
|
}
|
|
566
634
|
|
|
567
635
|
const cfg = loadConfig(configPath);
|
|
568
636
|
|
|
569
637
|
if (args.listTeams) {
|
|
570
|
-
log(Object.keys(cfg.teams || {}).sort().join("\n"));
|
|
638
|
+
console.log(Object.keys(cfg.teams || {}).sort().join("\n"));
|
|
571
639
|
return;
|
|
572
640
|
}
|
|
573
641
|
|
|
574
642
|
const nodeMajor = Number(process.versions.node.split(".")[0], 10);
|
|
575
643
|
if (nodeMajor < 18) {
|
|
576
|
-
|
|
644
|
+
console.error(
|
|
645
|
+
`${c.red}✗${c.reset} Node 18+ required. You have ${process.versions.node}.`
|
|
646
|
+
);
|
|
577
647
|
process.exit(1);
|
|
578
648
|
}
|
|
579
649
|
|
|
@@ -593,18 +663,16 @@ async function main() {
|
|
|
593
663
|
process.exit(1);
|
|
594
664
|
}
|
|
595
665
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
666
|
+
|
|
667
|
+
banner();
|
|
668
|
+
ux(`${c.green}✓${c.reset} GitHub CLI`);
|
|
599
669
|
|
|
600
670
|
const org = process.env.KOMPLIAN_ORG || cfg.org || "Komplian";
|
|
601
671
|
verifyOrgMembership(org);
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
);
|
|
606
|
-
|
|
607
|
-
banner();
|
|
672
|
+
if (!process.env.KOMPLIAN_CLI_QUIET) {
|
|
673
|
+
logGhIdentity();
|
|
674
|
+
}
|
|
675
|
+
ux(`${c.green}✓${c.reset} Org ${c.bold}${org}${c.reset}`);
|
|
608
676
|
|
|
609
677
|
let team = args.team;
|
|
610
678
|
if (!team && !args.yes && !args.allRepos) {
|
|
@@ -613,7 +681,9 @@ async function main() {
|
|
|
613
681
|
|
|
614
682
|
const repos = resolveRepos(cfg, org, team, args.allRepos);
|
|
615
683
|
if (repos.length === 0) {
|
|
616
|
-
|
|
684
|
+
console.error(
|
|
685
|
+
`${c.red}✗${c.reset} No repositories to clone (permissions / team / org).`
|
|
686
|
+
);
|
|
617
687
|
process.exit(1);
|
|
618
688
|
}
|
|
619
689
|
|
|
@@ -623,40 +693,85 @@ async function main() {
|
|
|
623
693
|
}
|
|
624
694
|
const abs = resolve(workspace.replace(/^~(?=$|[/\\])/, homedir()));
|
|
625
695
|
if (!isSafeTargetDir(abs)) {
|
|
626
|
-
|
|
696
|
+
console.error(`${c.red}✗${c.reset} Unsafe destination folder: ${abs}`);
|
|
627
697
|
process.exit(1);
|
|
628
698
|
}
|
|
629
699
|
|
|
630
700
|
mkdirSync(abs, { recursive: true });
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (team)
|
|
635
|
-
|
|
636
|
-
|
|
701
|
+
const q = process.env.KOMPLIAN_CLI_QUIET === "1";
|
|
702
|
+
ux("");
|
|
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}`);
|
|
706
|
+
ux("");
|
|
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
|
+
}
|
|
637
713
|
|
|
638
714
|
let failed = 0;
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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();
|
|
642
738
|
}
|
|
643
739
|
|
|
740
|
+
ux(summarizeCloneLine(repos, outcomes));
|
|
741
|
+
|
|
644
742
|
copyCursorPack(abs, process.env.KOMPLIAN_CURSOR_REPO);
|
|
645
743
|
|
|
646
744
|
if (args.install) {
|
|
647
|
-
|
|
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));
|
|
648
756
|
}
|
|
649
757
|
|
|
650
|
-
|
|
651
|
-
log(`${c.cyan}━━ Listo ━━${c.reset}`);
|
|
758
|
+
ux("");
|
|
652
759
|
if (failed > 0) {
|
|
653
|
-
|
|
760
|
+
ux(
|
|
761
|
+
`${c.yellow}○${c.reset} ${failed} repo(s) failed — check access and retry.`
|
|
762
|
+
);
|
|
763
|
+
} else {
|
|
764
|
+
ux(`${c.green}✓${c.reset} ${c.dim}Repositories ready${c.reset}`);
|
|
765
|
+
}
|
|
766
|
+
ux(`${c.green}✓${c.reset} Open in Cursor: ${c.bold}File → Open Folder → ${abs}${c.reset}`);
|
|
767
|
+
if (!q) {
|
|
768
|
+
log(
|
|
769
|
+
`${c.dim} package-lock: npm ci. No lock: npm install --no-package-lock. yarn/pnpm: frozen lockfile. KOMPLIAN_NPM_AUDIT=1 enables npm audit.${c.reset}`
|
|
770
|
+
);
|
|
771
|
+
log(
|
|
772
|
+
`${c.dim} Copy .env.example → .env per project; secrets in 1Password — never commit.${c.reset}`
|
|
773
|
+
);
|
|
654
774
|
}
|
|
655
|
-
log(`${c.green}✓${c.reset} Cursor: ${c.bold}File → Open Folder → ${abs}${c.reset}`);
|
|
656
|
-
log(
|
|
657
|
-
`${c.dim} Con package-lock.json: npm ci (no retoca el lock). Sin lock: npm install --no-package-lock. yarn/pnpm: lock congelado. KOMPLIAN_NPM_AUDIT=1 activa auditoría en npm.${c.reset}`
|
|
658
|
-
);
|
|
659
|
-
log(`${c.dim} .env.example → .env por proyecto; secretos en 1Password — nunca commit.${c.reset}`);
|
|
660
775
|
}
|
|
661
776
|
|
|
662
777
|
main().catch((e) => {
|
package/komplian-postman.mjs
CHANGED
|
@@ -46,6 +46,11 @@ function formatHomePath(absPath) {
|
|
|
46
46
|
return absPath;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/** JSON exports never go into the monorepo root (avoids accidental commits). */
|
|
50
|
+
function defaultPostmanExportDir() {
|
|
51
|
+
return join(homedir(), ".komplian", "postman-export");
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
function maskEmail(email) {
|
|
50
55
|
if (!email || typeof email !== "string" || !email.includes("@")) {
|
|
51
56
|
return "[sin email]";
|
|
@@ -855,7 +860,7 @@ function usage() {
|
|
|
855
860
|
log(``);
|
|
856
861
|
log(` -y, --yes Sin prompts extra (si falta API key y hay TTY, pide la clave una vez y guarda)`);
|
|
857
862
|
log(` --export-only Solo escribe JSON en disco (no llama a la API de Postman)`);
|
|
858
|
-
log(` --out <dir>
|
|
863
|
+
log(` --out <dir> Export folder (default: ~/.komplian/postman-export)`);
|
|
859
864
|
log(` --dotenv <ruta> .env extra (además de api/.env, .env, KOMPLIAN_DOTENV)`);
|
|
860
865
|
log(` -h, --help`);
|
|
861
866
|
log(``);
|
|
@@ -965,23 +970,29 @@ export async function runPostman(argv) {
|
|
|
965
970
|
apiKey,
|
|
966
971
|
process.env.POSTMAN_WORKSPACE_ID
|
|
967
972
|
);
|
|
968
|
-
|
|
969
|
-
`${c.green}✓${c.reset}
|
|
970
|
-
|
|
973
|
+
if (!process.env.KOMPLIAN_CLI_QUIET) {
|
|
974
|
+
log(`${c.green}✓${c.reset} Postman workspace: ${c.bold}${workspaceId}${c.reset}`);
|
|
975
|
+
}
|
|
971
976
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
: resolve(process.cwd(), "komplian-postman");
|
|
977
|
+
ensureSecureKomplianDir();
|
|
978
|
+
const outBase = args.outDir ? resolve(args.outDir) : defaultPostmanExportDir();
|
|
975
979
|
mkdirSync(outBase, { recursive: true });
|
|
976
980
|
|
|
977
981
|
const collPath = join(outBase, "Komplian-API.postman_collection.json");
|
|
978
982
|
writeFileSync(collPath, JSON.stringify(collection, null, 2), "utf8");
|
|
979
|
-
|
|
983
|
+
const quiet = process.env.KOMPLIAN_CLI_QUIET === "1";
|
|
984
|
+
if (!quiet) {
|
|
985
|
+
log(`${c.green}✓${c.reset} Export: ${c.dim}${collPath}${c.reset}`);
|
|
986
|
+
}
|
|
980
987
|
|
|
981
988
|
for (const env of envsForExport) {
|
|
982
989
|
const safe = env.name.replace(/[\\/]/g, "-") + ".postman_environment.json";
|
|
983
990
|
writeFileSync(join(outBase, safe), JSON.stringify({ ...env }, null, 2), "utf8");
|
|
984
|
-
|
|
991
|
+
if (!quiet) {
|
|
992
|
+
log(
|
|
993
|
+
`${c.green}✓${c.reset} Export: ${c.dim}${join(outBase, safe)}${c.reset} ${c.dim}(no secrets)${c.reset}`
|
|
994
|
+
);
|
|
995
|
+
}
|
|
985
996
|
}
|
|
986
997
|
|
|
987
998
|
if (args.exportOnly) {
|
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`);
|