@envpilot/cli 1.6.0 → 1.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.
|
@@ -7,7 +7,7 @@ function initSentry() {
|
|
|
7
7
|
Sentry.init({
|
|
8
8
|
dsn,
|
|
9
9
|
environment: "cli",
|
|
10
|
-
release: true ? "1.
|
|
10
|
+
release: true ? "1.11.0" : "0.0.0",
|
|
11
11
|
// Free tier: disable performance monitoring
|
|
12
12
|
tracesSampleRate: 0,
|
|
13
13
|
beforeSend(event) {
|
|
@@ -49,6 +49,26 @@ async function flushSentry() {
|
|
|
49
49
|
// src/lib/config.ts
|
|
50
50
|
import Conf from "conf";
|
|
51
51
|
var DEFAULT_API_URL = "https://www.envpilot.dev";
|
|
52
|
+
var HOST_CANONICALIZATION = {
|
|
53
|
+
"envpilot.dev": "www.envpilot.dev"
|
|
54
|
+
};
|
|
55
|
+
function normalizeApiUrl(raw) {
|
|
56
|
+
let value = raw.trim();
|
|
57
|
+
if (!/^https?:\/\//i.test(value)) {
|
|
58
|
+
value = `https://${value}`;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const parsed = new URL(value);
|
|
62
|
+
const canonicalHost = HOST_CANONICALIZATION[parsed.hostname.toLowerCase()];
|
|
63
|
+
if (canonicalHost) {
|
|
64
|
+
parsed.hostname = canonicalHost;
|
|
65
|
+
}
|
|
66
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "");
|
|
67
|
+
return parsed.toString().replace(/\/$/, "");
|
|
68
|
+
} catch {
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
52
72
|
var config = new Conf({
|
|
53
73
|
projectName: "envpilot",
|
|
54
74
|
defaults: {
|
|
@@ -57,7 +77,7 @@ var config = new Conf({
|
|
|
57
77
|
});
|
|
58
78
|
function getConfig() {
|
|
59
79
|
return {
|
|
60
|
-
apiUrl: config.get("apiUrl") ?? DEFAULT_API_URL,
|
|
80
|
+
apiUrl: normalizeApiUrl(config.get("apiUrl") ?? DEFAULT_API_URL),
|
|
61
81
|
accessToken: config.get("accessToken"),
|
|
62
82
|
refreshToken: config.get("refreshToken"),
|
|
63
83
|
activeProjectId: config.get("activeProjectId"),
|
|
@@ -67,10 +87,12 @@ function getConfig() {
|
|
|
67
87
|
};
|
|
68
88
|
}
|
|
69
89
|
function getApiUrl() {
|
|
70
|
-
|
|
90
|
+
const stored = config.get("apiUrl");
|
|
91
|
+
const raw = stored ?? DEFAULT_API_URL;
|
|
92
|
+
return normalizeApiUrl(raw);
|
|
71
93
|
}
|
|
72
94
|
function setApiUrl(url) {
|
|
73
|
-
config.set("apiUrl", url);
|
|
95
|
+
config.set("apiUrl", normalizeApiUrl(url));
|
|
74
96
|
}
|
|
75
97
|
function getAccessToken() {
|
|
76
98
|
return config.get("accessToken");
|
|
@@ -121,9 +143,6 @@ function getConfigPath() {
|
|
|
121
143
|
return config.path;
|
|
122
144
|
}
|
|
123
145
|
|
|
124
|
-
// src/ui/render-tui.tsx
|
|
125
|
-
import chalk from "chalk";
|
|
126
|
-
|
|
127
146
|
// src/ui/execute-command.ts
|
|
128
147
|
import { spawn } from "child_process";
|
|
129
148
|
import { dirname, resolve } from "path";
|
|
@@ -155,9 +174,10 @@ async function executeCommand(argv) {
|
|
|
155
174
|
// src/ui/render-tui.tsx
|
|
156
175
|
import { jsx } from "react/jsx-runtime";
|
|
157
176
|
async function openTUI() {
|
|
158
|
-
const [{ render }, { CLIApp }] = await Promise.all([
|
|
177
|
+
const [{ render }, { CLIApp }, { PressAnyKey }] = await Promise.all([
|
|
159
178
|
import("ink"),
|
|
160
|
-
import("./app-
|
|
179
|
+
import("./app-QG4JFCWP.js"),
|
|
180
|
+
import("./press-any-key-64XFP4O2.js")
|
|
161
181
|
]);
|
|
162
182
|
while (true) {
|
|
163
183
|
let selectedArgv = null;
|
|
@@ -179,24 +199,18 @@ async function openTUI() {
|
|
|
179
199
|
if (code !== 0) {
|
|
180
200
|
process.exitCode = code;
|
|
181
201
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
process.stdin.resume();
|
|
191
|
-
process.stdin.once("data", (data) => {
|
|
192
|
-
const ch = data.toString();
|
|
193
|
-
if (process.stdin.isTTY) {
|
|
194
|
-
process.stdin.setRawMode(false);
|
|
202
|
+
let quit = false;
|
|
203
|
+
const prompt = render(
|
|
204
|
+
/* @__PURE__ */ jsx(
|
|
205
|
+
PressAnyKey,
|
|
206
|
+
{
|
|
207
|
+
onResolve: (q) => {
|
|
208
|
+
quit = q;
|
|
209
|
+
}
|
|
195
210
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
});
|
|
211
|
+
)
|
|
212
|
+
);
|
|
213
|
+
await prompt.waitUntilExit();
|
|
200
214
|
if (quit) {
|
|
201
215
|
break;
|
|
202
216
|
}
|
|
@@ -207,7 +221,7 @@ async function openTUI() {
|
|
|
207
221
|
import { Command } from "commander";
|
|
208
222
|
|
|
209
223
|
// src/lib/ui.ts
|
|
210
|
-
import
|
|
224
|
+
import chalk from "chalk";
|
|
211
225
|
import ora from "ora";
|
|
212
226
|
function createSpinner(text) {
|
|
213
227
|
return ora({
|
|
@@ -228,25 +242,25 @@ async function withSpinner(text, operation, options) {
|
|
|
228
242
|
}
|
|
229
243
|
}
|
|
230
244
|
function success(message) {
|
|
231
|
-
console.log(
|
|
245
|
+
console.log(chalk.green("\u2713"), message);
|
|
232
246
|
}
|
|
233
247
|
function info(message) {
|
|
234
|
-
console.log(
|
|
248
|
+
console.log(chalk.blue("\u2139"), message);
|
|
235
249
|
}
|
|
236
250
|
function warning(message) {
|
|
237
|
-
console.log(
|
|
251
|
+
console.log(chalk.yellow("\u26A0"), message);
|
|
238
252
|
}
|
|
239
253
|
function error(message) {
|
|
240
|
-
console.log(
|
|
254
|
+
console.log(chalk.red("\u2717"), message);
|
|
241
255
|
}
|
|
242
256
|
function header(text) {
|
|
243
257
|
console.log();
|
|
244
|
-
console.log(
|
|
245
|
-
console.log(
|
|
258
|
+
console.log(chalk.bold(text));
|
|
259
|
+
console.log(chalk.dim("\u2500".repeat(text.length)));
|
|
246
260
|
}
|
|
247
261
|
function table(data, columns) {
|
|
248
262
|
if (data.length === 0) {
|
|
249
|
-
console.log(
|
|
263
|
+
console.log(chalk.dim("No data to display"));
|
|
250
264
|
return;
|
|
251
265
|
}
|
|
252
266
|
const widths = columns.map((col) => {
|
|
@@ -257,8 +271,8 @@ function table(data, columns) {
|
|
|
257
271
|
return col.width ?? Math.max(headerWidth, maxDataWidth);
|
|
258
272
|
});
|
|
259
273
|
const headerLine = columns.map((col, i) => col.header.padEnd(widths[i])).join(" ");
|
|
260
|
-
console.log(
|
|
261
|
-
console.log(
|
|
274
|
+
console.log(chalk.bold(headerLine));
|
|
275
|
+
console.log(chalk.dim("\u2500".repeat(headerLine.length)));
|
|
262
276
|
for (const row of data) {
|
|
263
277
|
const line2 = columns.map((col, i) => String(row[col.key] ?? "").padEnd(widths[i])).join(" ");
|
|
264
278
|
console.log(line2);
|
|
@@ -268,23 +282,23 @@ function keyValue(pairs) {
|
|
|
268
282
|
const maxKeyLength = Math.max(...pairs.map(([key]) => key.length));
|
|
269
283
|
for (const [key, value] of pairs) {
|
|
270
284
|
const paddedKey = key.padEnd(maxKeyLength);
|
|
271
|
-
console.log(`${
|
|
285
|
+
console.log(`${chalk.dim(paddedKey)} ${value ?? chalk.dim("(not set)")}`);
|
|
272
286
|
}
|
|
273
287
|
}
|
|
274
288
|
function diff(added, removed, changed) {
|
|
275
289
|
if (Object.keys(added).length === 0 && Object.keys(removed).length === 0 && Object.keys(changed).length === 0) {
|
|
276
|
-
console.log(
|
|
290
|
+
console.log(chalk.dim("No changes"));
|
|
277
291
|
return;
|
|
278
292
|
}
|
|
279
293
|
for (const [key, value] of Object.entries(added)) {
|
|
280
|
-
console.log(
|
|
294
|
+
console.log(chalk.green(`+ ${key}=${maskValue(value)}`));
|
|
281
295
|
}
|
|
282
296
|
for (const [key, value] of Object.entries(removed)) {
|
|
283
|
-
console.log(
|
|
297
|
+
console.log(chalk.red(`- ${key}=${maskValue(value)}`));
|
|
284
298
|
}
|
|
285
299
|
for (const [key, { local, remote }] of Object.entries(changed)) {
|
|
286
|
-
console.log(
|
|
287
|
-
console.log(
|
|
300
|
+
console.log(chalk.red(`- ${key}=${maskValue(remote)}`));
|
|
301
|
+
console.log(chalk.green(`+ ${key}=${maskValue(local)}`));
|
|
288
302
|
}
|
|
289
303
|
}
|
|
290
304
|
function maskValue(value, showChars = 4) {
|
|
@@ -294,7 +308,7 @@ function maskValue(value, showChars = 4) {
|
|
|
294
308
|
return value.slice(0, showChars) + "****" + value.slice(-showChars);
|
|
295
309
|
}
|
|
296
310
|
function line() {
|
|
297
|
-
console.log(
|
|
311
|
+
console.log(chalk.dim("\u2500".repeat(50)));
|
|
298
312
|
}
|
|
299
313
|
function blank() {
|
|
300
314
|
console.log();
|
|
@@ -302,19 +316,19 @@ function blank() {
|
|
|
302
316
|
function formatRole(role) {
|
|
303
317
|
switch (role) {
|
|
304
318
|
case "admin":
|
|
305
|
-
return
|
|
319
|
+
return chalk.green("Admin");
|
|
306
320
|
case "team_lead":
|
|
307
|
-
return
|
|
321
|
+
return chalk.blue("Team Lead");
|
|
308
322
|
case "member":
|
|
309
|
-
return
|
|
323
|
+
return chalk.yellow("Member");
|
|
310
324
|
default:
|
|
311
|
-
return
|
|
325
|
+
return chalk.dim("Unknown");
|
|
312
326
|
}
|
|
313
327
|
}
|
|
314
328
|
function roleNotice(role) {
|
|
315
329
|
if (role === "member") {
|
|
316
330
|
console.log(
|
|
317
|
-
|
|
331
|
+
chalk.yellow(
|
|
318
332
|
" You have Member access. Write operations will create pending requests for approval."
|
|
319
333
|
)
|
|
320
334
|
);
|
|
@@ -323,19 +337,19 @@ function roleNotice(role) {
|
|
|
323
337
|
function formatProjectRole(role) {
|
|
324
338
|
switch (role) {
|
|
325
339
|
case "manager":
|
|
326
|
-
return
|
|
340
|
+
return chalk.green("Manager");
|
|
327
341
|
case "developer":
|
|
328
|
-
return
|
|
342
|
+
return chalk.blue("Developer");
|
|
329
343
|
case "viewer":
|
|
330
|
-
return
|
|
344
|
+
return chalk.yellow("Viewer");
|
|
331
345
|
default:
|
|
332
|
-
return
|
|
346
|
+
return chalk.dim("-");
|
|
333
347
|
}
|
|
334
348
|
}
|
|
335
349
|
function projectRoleNotice(projectRole) {
|
|
336
350
|
if (projectRole === "viewer") {
|
|
337
351
|
console.log(
|
|
338
|
-
|
|
352
|
+
chalk.yellow(
|
|
339
353
|
" You have Viewer access to this project. You can only view variables you have been explicitly granted access to."
|
|
340
354
|
)
|
|
341
355
|
);
|
|
@@ -343,7 +357,7 @@ function projectRoleNotice(projectRole) {
|
|
|
343
357
|
}
|
|
344
358
|
|
|
345
359
|
// src/lib/errors.ts
|
|
346
|
-
import
|
|
360
|
+
import chalk2 from "chalk";
|
|
347
361
|
var CLIError = class extends Error {
|
|
348
362
|
constructor(message, code, suggestion) {
|
|
349
363
|
super(message);
|
|
@@ -368,17 +382,17 @@ var ErrorCodes = {
|
|
|
368
382
|
};
|
|
369
383
|
function formatError(error2) {
|
|
370
384
|
if (error2 instanceof CLIError) {
|
|
371
|
-
let message =
|
|
385
|
+
let message = chalk2.red(`Error: ${error2.message}`);
|
|
372
386
|
if (error2.suggestion) {
|
|
373
387
|
message += `
|
|
374
|
-
${
|
|
388
|
+
${chalk2.yellow("Suggestion:")} ${error2.suggestion}`;
|
|
375
389
|
}
|
|
376
390
|
return message;
|
|
377
391
|
}
|
|
378
392
|
if (error2 instanceof Error) {
|
|
379
|
-
return
|
|
393
|
+
return chalk2.red(`Error: ${error2.message}`);
|
|
380
394
|
}
|
|
381
|
-
return
|
|
395
|
+
return chalk2.red(`Error: ${String(error2)}`);
|
|
382
396
|
}
|
|
383
397
|
async function handleError(error2) {
|
|
384
398
|
console.error(formatError(error2));
|
|
@@ -435,10 +449,16 @@ function invalidInput(message) {
|
|
|
435
449
|
|
|
436
450
|
// src/lib/auth-flow.ts
|
|
437
451
|
import open from "open";
|
|
438
|
-
import
|
|
452
|
+
import chalk3 from "chalk";
|
|
439
453
|
import { hostname } from "os";
|
|
440
454
|
|
|
441
455
|
// src/lib/api.ts
|
|
456
|
+
function registrableDomain(hostname2) {
|
|
457
|
+
const parts = hostname2.toLowerCase().split(".").filter(Boolean);
|
|
458
|
+
if (parts.length <= 2) return parts.join(".");
|
|
459
|
+
return parts.slice(-2).join(".");
|
|
460
|
+
}
|
|
461
|
+
var MAX_MANUAL_REDIRECTS = 5;
|
|
442
462
|
var APIError = class extends Error {
|
|
443
463
|
constructor(message, statusCode, code) {
|
|
444
464
|
super(message);
|
|
@@ -474,7 +494,59 @@ var APIClient = class {
|
|
|
474
494
|
const finalUrl = response.url || "";
|
|
475
495
|
const contentType = response.headers.get("content-type") || "";
|
|
476
496
|
const preview = (bodyText || "").slice(0, 512).toLowerCase();
|
|
477
|
-
return
|
|
497
|
+
return location.includes("authkit") || finalUrl.includes("authkit") || contentType.includes("text/html") && (preview.includes("authorization_session_id") || preview.includes("client_id=") || preview.includes("<!doctype html"));
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Perform a fetch that follows 3xx redirects manually, re-attaching the
|
|
501
|
+
* Authorization header when the redirect stays inside the same registrable
|
|
502
|
+
* domain (eTLD+1). This defends against the apex→www redirect case where
|
|
503
|
+
* Node's default redirect follower drops the Authorization header on any
|
|
504
|
+
* hostname change and the resulting request comes back as a bogus 401 —
|
|
505
|
+
* which used to wipe the user's credentials.
|
|
506
|
+
*
|
|
507
|
+
* Cross-site redirects (different registrable domain) are followed without
|
|
508
|
+
* the Authorization header, matching browser/fetch security semantics.
|
|
509
|
+
*/
|
|
510
|
+
async fetchWithSafeRedirects(initialUrl, init2) {
|
|
511
|
+
let currentUrl = initialUrl;
|
|
512
|
+
let currentInit = { ...init2, redirect: "manual" };
|
|
513
|
+
for (let hop = 0; hop < MAX_MANUAL_REDIRECTS; hop++) {
|
|
514
|
+
const response = await fetch(currentUrl, currentInit);
|
|
515
|
+
if (response.status < 300 || response.status >= 400) {
|
|
516
|
+
return response;
|
|
517
|
+
}
|
|
518
|
+
const location = response.headers.get("location");
|
|
519
|
+
if (!location) return response;
|
|
520
|
+
const nextUrl = new URL(location, currentUrl);
|
|
521
|
+
const prevHost = new URL(currentUrl).hostname;
|
|
522
|
+
const sameSite = registrableDomain(nextUrl.hostname) === registrableDomain(prevHost);
|
|
523
|
+
const headers = new Headers(currentInit.headers);
|
|
524
|
+
if (!sameSite) {
|
|
525
|
+
headers.delete("Authorization");
|
|
526
|
+
}
|
|
527
|
+
let nextMethod = (currentInit.method || "GET").toUpperCase();
|
|
528
|
+
let nextBody = currentInit.body;
|
|
529
|
+
if (response.status === 301 || response.status === 302 || response.status === 303) {
|
|
530
|
+
if (nextMethod !== "GET" && nextMethod !== "HEAD") {
|
|
531
|
+
nextMethod = "GET";
|
|
532
|
+
nextBody = void 0;
|
|
533
|
+
headers.delete("Content-Type");
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
currentUrl = nextUrl.toString();
|
|
537
|
+
currentInit = {
|
|
538
|
+
...currentInit,
|
|
539
|
+
method: nextMethod,
|
|
540
|
+
headers,
|
|
541
|
+
body: nextBody,
|
|
542
|
+
redirect: "manual"
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
throw new APIError(
|
|
546
|
+
`Too many redirects while calling ${initialUrl}`,
|
|
547
|
+
0,
|
|
548
|
+
"TOO_MANY_REDIRECTS"
|
|
549
|
+
);
|
|
478
550
|
}
|
|
479
551
|
/**
|
|
480
552
|
* Make a GET request
|
|
@@ -486,10 +558,9 @@ var APIClient = class {
|
|
|
486
558
|
url.searchParams.set(key, value);
|
|
487
559
|
}
|
|
488
560
|
}
|
|
489
|
-
const response = await
|
|
561
|
+
const response = await this.fetchWithSafeRedirects(url.toString(), {
|
|
490
562
|
method: "GET",
|
|
491
|
-
headers: this.getHeaders()
|
|
492
|
-
redirect: "follow"
|
|
563
|
+
headers: this.getHeaders()
|
|
493
564
|
});
|
|
494
565
|
return this.handleResponse(response);
|
|
495
566
|
}
|
|
@@ -498,11 +569,10 @@ var APIClient = class {
|
|
|
498
569
|
*/
|
|
499
570
|
async post(path, body) {
|
|
500
571
|
const url = new URL(path, this.baseUrl);
|
|
501
|
-
const response = await
|
|
572
|
+
const response = await this.fetchWithSafeRedirects(url.toString(), {
|
|
502
573
|
method: "POST",
|
|
503
574
|
headers: this.getHeaders(),
|
|
504
|
-
body: body ? JSON.stringify(body) : void 0
|
|
505
|
-
redirect: "follow"
|
|
575
|
+
body: body ? JSON.stringify(body) : void 0
|
|
506
576
|
});
|
|
507
577
|
return this.handleResponse(response);
|
|
508
578
|
}
|
|
@@ -511,11 +581,10 @@ var APIClient = class {
|
|
|
511
581
|
*/
|
|
512
582
|
async put(path, body) {
|
|
513
583
|
const url = new URL(path, this.baseUrl);
|
|
514
|
-
const response = await
|
|
584
|
+
const response = await this.fetchWithSafeRedirects(url.toString(), {
|
|
515
585
|
method: "PUT",
|
|
516
586
|
headers: this.getHeaders(),
|
|
517
|
-
body: body ? JSON.stringify(body) : void 0
|
|
518
|
-
redirect: "follow"
|
|
587
|
+
body: body ? JSON.stringify(body) : void 0
|
|
519
588
|
});
|
|
520
589
|
return this.handleResponse(response);
|
|
521
590
|
}
|
|
@@ -524,11 +593,10 @@ var APIClient = class {
|
|
|
524
593
|
*/
|
|
525
594
|
async patch(path, body) {
|
|
526
595
|
const url = new URL(path, this.baseUrl);
|
|
527
|
-
const response = await
|
|
596
|
+
const response = await this.fetchWithSafeRedirects(url.toString(), {
|
|
528
597
|
method: "PATCH",
|
|
529
598
|
headers: this.getHeaders(),
|
|
530
|
-
body: body ? JSON.stringify(body) : void 0
|
|
531
|
-
redirect: "follow"
|
|
599
|
+
body: body ? JSON.stringify(body) : void 0
|
|
532
600
|
});
|
|
533
601
|
return this.handleResponse(response);
|
|
534
602
|
}
|
|
@@ -537,10 +605,9 @@ var APIClient = class {
|
|
|
537
605
|
*/
|
|
538
606
|
async delete(path) {
|
|
539
607
|
const url = new URL(path, this.baseUrl);
|
|
540
|
-
const response = await
|
|
608
|
+
const response = await this.fetchWithSafeRedirects(url.toString(), {
|
|
541
609
|
method: "DELETE",
|
|
542
|
-
headers: this.getHeaders()
|
|
543
|
-
redirect: "follow"
|
|
610
|
+
headers: this.getHeaders()
|
|
544
611
|
});
|
|
545
612
|
if (!response.ok) {
|
|
546
613
|
await this.handleError(response);
|
|
@@ -557,7 +624,6 @@ var APIClient = class {
|
|
|
557
624
|
if (!contentType.includes("application/json")) {
|
|
558
625
|
const body2 = await response.text();
|
|
559
626
|
if (this.isAuthRedirect(response, body2)) {
|
|
560
|
-
clearAuth();
|
|
561
627
|
throw new APIError(
|
|
562
628
|
"Your CLI session is not authorized for this endpoint. Please run `envpilot login` and try again.",
|
|
563
629
|
401,
|
|
@@ -594,20 +660,12 @@ var APIClient = class {
|
|
|
594
660
|
code = data.code;
|
|
595
661
|
} catch {
|
|
596
662
|
}
|
|
597
|
-
if (response.status >= 300 && response.status < 400 && this.isAuthRedirect(response)) {
|
|
598
|
-
clearAuth();
|
|
599
|
-
throw new APIError(
|
|
600
|
-
"Your CLI session expired or the server redirected this request to browser sign-in. Please run `envpilot login`.",
|
|
601
|
-
401,
|
|
602
|
-
"AUTH_REDIRECT"
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
663
|
if (response.status === 401) {
|
|
606
664
|
clearAuth();
|
|
607
665
|
throw new APIError(
|
|
608
|
-
"Authentication
|
|
666
|
+
"Authentication failed. Please run `envpilot login`.",
|
|
609
667
|
401,
|
|
610
|
-
"UNAUTHORIZED"
|
|
668
|
+
code || "UNAUTHORIZED"
|
|
611
669
|
);
|
|
612
670
|
}
|
|
613
671
|
if (response.status === 403 && code === "TIER_LIMIT_REACHED") {
|
|
@@ -636,7 +694,7 @@ var APIClient = class {
|
|
|
636
694
|
* Get current user info
|
|
637
695
|
*/
|
|
638
696
|
async getCurrentUser() {
|
|
639
|
-
return this.get("/api/cli/auth
|
|
697
|
+
return this.get("/api/cli/auth", { action: "me" });
|
|
640
698
|
}
|
|
641
699
|
/**
|
|
642
700
|
* Get tier info for the active organization
|
|
@@ -752,25 +810,25 @@ var APIClient = class {
|
|
|
752
810
|
* Initiate CLI authentication flow
|
|
753
811
|
*/
|
|
754
812
|
async initiateAuth(deviceName) {
|
|
755
|
-
return this.post("/api/cli/auth
|
|
813
|
+
return this.post("/api/cli/auth?action=initiate", { deviceName });
|
|
756
814
|
}
|
|
757
815
|
/**
|
|
758
816
|
* Poll for authentication status
|
|
759
817
|
*/
|
|
760
818
|
async pollAuth(code) {
|
|
761
|
-
return this.get("/api/cli/auth
|
|
819
|
+
return this.get("/api/cli/auth", { action: "poll", code });
|
|
762
820
|
}
|
|
763
821
|
/**
|
|
764
822
|
* Refresh access token
|
|
765
823
|
*/
|
|
766
824
|
async refreshToken(refreshToken) {
|
|
767
|
-
return this.post("/api/cli/auth
|
|
825
|
+
return this.post("/api/cli/auth?action=refresh", { refreshToken });
|
|
768
826
|
}
|
|
769
827
|
/**
|
|
770
828
|
* Revoke access token (logout)
|
|
771
829
|
*/
|
|
772
830
|
async revokeToken() {
|
|
773
|
-
return this.post("/api/cli/auth
|
|
831
|
+
return this.post("/api/cli/auth?action=revoke", {});
|
|
774
832
|
}
|
|
775
833
|
};
|
|
776
834
|
function createAPIClient() {
|
|
@@ -792,19 +850,19 @@ async function performLogin(options) {
|
|
|
792
850
|
spinner.start();
|
|
793
851
|
let initResponse;
|
|
794
852
|
try {
|
|
795
|
-
initResponse = await api.
|
|
853
|
+
initResponse = await api.initiateAuth(deviceName);
|
|
796
854
|
} catch (error2) {
|
|
797
855
|
spinner.stop();
|
|
798
856
|
throw error2;
|
|
799
857
|
}
|
|
800
858
|
spinner.stop();
|
|
801
859
|
console.log();
|
|
802
|
-
console.log(
|
|
860
|
+
console.log(chalk3.bold("Your authentication code:"));
|
|
803
861
|
console.log();
|
|
804
|
-
console.log(
|
|
862
|
+
console.log(chalk3.cyan.bold(` ${initResponse.code}`));
|
|
805
863
|
console.log();
|
|
806
864
|
console.log(`Open this URL to authenticate:`);
|
|
807
|
-
console.log(
|
|
865
|
+
console.log(chalk3.dim(initResponse.url));
|
|
808
866
|
console.log();
|
|
809
867
|
if (options?.browser !== false) {
|
|
810
868
|
info("Opening browser...");
|
|
@@ -818,10 +876,7 @@ async function performLogin(options) {
|
|
|
818
876
|
await sleep(POLL_INTERVAL_MS);
|
|
819
877
|
let pollResponse;
|
|
820
878
|
try {
|
|
821
|
-
pollResponse = await api.
|
|
822
|
-
action: "poll",
|
|
823
|
-
code: initResponse.code
|
|
824
|
-
});
|
|
879
|
+
pollResponse = await api.pollAuth(initResponse.code);
|
|
825
880
|
consecutiveErrors = 0;
|
|
826
881
|
} catch {
|
|
827
882
|
consecutiveErrors++;
|
|
@@ -834,12 +889,13 @@ async function performLogin(options) {
|
|
|
834
889
|
}
|
|
835
890
|
if (pollResponse.status === "authenticated") {
|
|
836
891
|
pollSpinner.stop();
|
|
837
|
-
if (pollResponse.accessToken) {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
setRefreshToken(pollResponse.refreshToken);
|
|
892
|
+
if (!pollResponse.accessToken || !pollResponse.refreshToken) {
|
|
893
|
+
throw new Error(
|
|
894
|
+
"Authentication succeeded but the server did not return session tokens. This is likely a server-side issue. Please try again or contact support."
|
|
895
|
+
);
|
|
842
896
|
}
|
|
897
|
+
setAccessToken(pollResponse.accessToken);
|
|
898
|
+
setRefreshToken(pollResponse.refreshToken);
|
|
843
899
|
if (pollResponse.user) {
|
|
844
900
|
setUser({
|
|
845
901
|
id: pollResponse.user.id,
|
|
@@ -848,7 +904,7 @@ async function performLogin(options) {
|
|
|
848
904
|
});
|
|
849
905
|
}
|
|
850
906
|
console.log();
|
|
851
|
-
success(`Logged in as ${
|
|
907
|
+
success(`Logged in as ${chalk3.bold(pollResponse.user?.email)}`);
|
|
852
908
|
return { email: pollResponse.user?.email || "" };
|
|
853
909
|
}
|
|
854
910
|
if (pollResponse.status === "expired" || pollResponse.status === "not_found") {
|
|
@@ -862,7 +918,7 @@ async function performLogin(options) {
|
|
|
862
918
|
}
|
|
863
919
|
|
|
864
920
|
// src/commands/login.ts
|
|
865
|
-
var loginCommand = new Command("login").description("Authenticate with Envpilot").option("--api-url <url>", "API URL (default:
|
|
921
|
+
var loginCommand = new Command("login").description("Authenticate with Envpilot").option("--api-url <url>", "API URL (default: https://www.envpilot.dev)").option("--no-browser", "Do not automatically open the browser").action(async (options) => {
|
|
866
922
|
try {
|
|
867
923
|
if (options.apiUrl) {
|
|
868
924
|
setApiUrl(options.apiUrl);
|
|
@@ -883,7 +939,7 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
|
|
|
883
939
|
|
|
884
940
|
// src/commands/init.ts
|
|
885
941
|
import { Command as Command2 } from "commander";
|
|
886
|
-
import
|
|
942
|
+
import chalk4 from "chalk";
|
|
887
943
|
import inquirer from "inquirer";
|
|
888
944
|
|
|
889
945
|
// src/lib/project-config.ts
|
|
@@ -1388,18 +1444,18 @@ async function addProject(existingConfig, options) {
|
|
|
1388
1444
|
console.log();
|
|
1389
1445
|
success(`Added "${selectedProject.name}" to linked projects!`);
|
|
1390
1446
|
console.log(
|
|
1391
|
-
|
|
1447
|
+
chalk4.dim(` ${existingConfig.projects.length + 1} projects now linked`)
|
|
1392
1448
|
);
|
|
1393
1449
|
console.log();
|
|
1394
1450
|
console.log("Next steps:");
|
|
1395
1451
|
console.log(
|
|
1396
|
-
` ${
|
|
1452
|
+
` ${chalk4.cyan("envpilot pull --all")} Pull all projects`
|
|
1397
1453
|
);
|
|
1398
1454
|
console.log(
|
|
1399
|
-
` ${
|
|
1455
|
+
` ${chalk4.cyan(`envpilot pull --project "${selectedProject.name}"`)} Pull this project`
|
|
1400
1456
|
);
|
|
1401
1457
|
console.log(
|
|
1402
|
-
` ${
|
|
1458
|
+
` ${chalk4.cyan("envpilot list linked")} See all linked projects`
|
|
1403
1459
|
);
|
|
1404
1460
|
console.log();
|
|
1405
1461
|
}
|
|
@@ -1428,7 +1484,7 @@ async function selectOrgProjectEnv(options) {
|
|
|
1428
1484
|
selectedOrg = org;
|
|
1429
1485
|
} else if (organizations.length === 1) {
|
|
1430
1486
|
selectedOrg = organizations[0];
|
|
1431
|
-
info(`Using organization: ${
|
|
1487
|
+
info(`Using organization: ${chalk4.bold(selectedOrg.name)}`);
|
|
1432
1488
|
} else {
|
|
1433
1489
|
const { orgId } = await inquirer.prompt([
|
|
1434
1490
|
{
|
|
@@ -1436,7 +1492,7 @@ async function selectOrgProjectEnv(options) {
|
|
|
1436
1492
|
name: "orgId",
|
|
1437
1493
|
message: "Select an organization:",
|
|
1438
1494
|
choices: organizations.map((org) => ({
|
|
1439
|
-
name: `${org.name} ${org.tier === "pro" ?
|
|
1495
|
+
name: `${org.name} ${org.tier === "pro" ? chalk4.green("(Pro)") : chalk4.dim("(Free)")}`,
|
|
1440
1496
|
value: org._id
|
|
1441
1497
|
}))
|
|
1442
1498
|
}
|
|
@@ -1466,7 +1522,7 @@ async function selectOrgProjectEnv(options) {
|
|
|
1466
1522
|
selectedProject = project;
|
|
1467
1523
|
} else if (projects.length === 1) {
|
|
1468
1524
|
selectedProject = projects[0];
|
|
1469
|
-
info(`Using project: ${
|
|
1525
|
+
info(`Using project: ${chalk4.bold(selectedProject.name)}`);
|
|
1470
1526
|
} else {
|
|
1471
1527
|
const { projectId } = await inquirer.prompt([
|
|
1472
1528
|
{
|
|
@@ -1517,29 +1573,29 @@ function warnTrackedFiles() {
|
|
|
1517
1573
|
console.log();
|
|
1518
1574
|
warning("Security risk: .env files are tracked by git!");
|
|
1519
1575
|
for (const file of trackedFiles) {
|
|
1520
|
-
console.log(
|
|
1576
|
+
console.log(chalk4.red(` tracked: ${file}`));
|
|
1521
1577
|
}
|
|
1522
1578
|
console.log();
|
|
1523
1579
|
console.log(
|
|
1524
|
-
|
|
1580
|
+
chalk4.yellow(
|
|
1525
1581
|
" Run the following to untrack them (without deleting the files):"
|
|
1526
1582
|
)
|
|
1527
1583
|
);
|
|
1528
1584
|
for (const file of trackedFiles) {
|
|
1529
|
-
console.log(
|
|
1585
|
+
console.log(chalk4.cyan(` git rm --cached ${file}`));
|
|
1530
1586
|
}
|
|
1531
1587
|
}
|
|
1532
1588
|
}
|
|
1533
1589
|
function printPostInit(selectedOrg, selectedProject) {
|
|
1534
1590
|
console.log();
|
|
1535
|
-
console.log(
|
|
1591
|
+
console.log(chalk4.dim("Configuration saved to .envpilot"));
|
|
1536
1592
|
if (selectedOrg.role) {
|
|
1537
|
-
console.log(
|
|
1593
|
+
console.log(chalk4.dim(` Org role: ${formatRole(selectedOrg.role)}`));
|
|
1538
1594
|
roleNotice(selectedOrg.role);
|
|
1539
1595
|
}
|
|
1540
1596
|
if (selectedProject.projectRole) {
|
|
1541
1597
|
console.log(
|
|
1542
|
-
|
|
1598
|
+
chalk4.dim(
|
|
1543
1599
|
` Project role: ${formatProjectRole(selectedProject.projectRole)}`
|
|
1544
1600
|
)
|
|
1545
1601
|
);
|
|
@@ -1548,17 +1604,17 @@ function printPostInit(selectedOrg, selectedProject) {
|
|
|
1548
1604
|
console.log();
|
|
1549
1605
|
console.log("Next steps:");
|
|
1550
1606
|
console.log(
|
|
1551
|
-
` ${
|
|
1607
|
+
` ${chalk4.cyan("envpilot pull")} Download environment variables`
|
|
1552
1608
|
);
|
|
1553
1609
|
console.log(
|
|
1554
|
-
` ${
|
|
1610
|
+
` ${chalk4.cyan("envpilot push")} Upload local .env to cloud`
|
|
1555
1611
|
);
|
|
1556
1612
|
console.log();
|
|
1557
1613
|
}
|
|
1558
1614
|
|
|
1559
1615
|
// src/commands/pull.ts
|
|
1560
1616
|
import { Command as Command3 } from "commander";
|
|
1561
|
-
import
|
|
1617
|
+
import chalk5 from "chalk";
|
|
1562
1618
|
import inquirer2 from "inquirer";
|
|
1563
1619
|
|
|
1564
1620
|
// src/lib/format-converter.ts
|
|
@@ -1972,7 +2028,7 @@ async function pullAllProjects(options) {
|
|
|
1972
2028
|
const displayName = project.projectName || project.projectId;
|
|
1973
2029
|
console.log();
|
|
1974
2030
|
console.log(
|
|
1975
|
-
|
|
2031
|
+
chalk5.bold(
|
|
1976
2032
|
`Pulling "${displayName}" (${project.environment}) \u2192 ${outputPath}`
|
|
1977
2033
|
)
|
|
1978
2034
|
);
|
|
@@ -2022,7 +2078,7 @@ async function pullProject(project, outputPath, options) {
|
|
|
2022
2078
|
const api = createAPIClient();
|
|
2023
2079
|
let metaProjectRole;
|
|
2024
2080
|
const variables = await withSpinner(
|
|
2025
|
-
`Fetching ${
|
|
2081
|
+
`Fetching ${chalk5.bold(project.environment)} variables...`,
|
|
2026
2082
|
async () => {
|
|
2027
2083
|
const response = await api.get("/api/cli/variables", {
|
|
2028
2084
|
projectId: project.projectId,
|
|
@@ -2051,7 +2107,7 @@ async function pullProject(project, outputPath, options) {
|
|
|
2051
2107
|
return;
|
|
2052
2108
|
}
|
|
2053
2109
|
console.log();
|
|
2054
|
-
console.log(
|
|
2110
|
+
console.log(chalk5.bold("Changes:"));
|
|
2055
2111
|
console.log();
|
|
2056
2112
|
diff(diffResult.added, diffResult.removed, diffResult.changed);
|
|
2057
2113
|
console.log();
|
|
@@ -2101,7 +2157,7 @@ async function pullProject(project, outputPath, options) {
|
|
|
2101
2157
|
const role = getRole();
|
|
2102
2158
|
applyFileProtection(outputPath, role, metaProjectRole);
|
|
2103
2159
|
success(
|
|
2104
|
-
`Downloaded ${variables.length} variables to ${
|
|
2160
|
+
`Downloaded ${variables.length} variables to ${chalk5.bold(outputPath)}`
|
|
2105
2161
|
);
|
|
2106
2162
|
if (metaProjectRole === "viewer") {
|
|
2107
2163
|
info(
|
|
@@ -2115,12 +2171,12 @@ async function pullProject(project, outputPath, options) {
|
|
|
2115
2171
|
);
|
|
2116
2172
|
}
|
|
2117
2173
|
console.log();
|
|
2118
|
-
console.log(
|
|
2174
|
+
console.log(chalk5.dim(` Added: ${Object.keys(diffResult.added).length}`));
|
|
2119
2175
|
console.log(
|
|
2120
|
-
|
|
2176
|
+
chalk5.dim(` Changed: ${Object.keys(diffResult.changed).length}`)
|
|
2121
2177
|
);
|
|
2122
2178
|
console.log(
|
|
2123
|
-
|
|
2179
|
+
chalk5.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
|
|
2124
2180
|
);
|
|
2125
2181
|
}
|
|
2126
2182
|
function checkTrackedFiles() {
|
|
@@ -2129,16 +2185,16 @@ function checkTrackedFiles() {
|
|
|
2129
2185
|
error("Security risk: .env files are tracked by git!");
|
|
2130
2186
|
console.log();
|
|
2131
2187
|
for (const file of trackedFiles) {
|
|
2132
|
-
console.log(
|
|
2188
|
+
console.log(chalk5.red(` tracked: ${file}`));
|
|
2133
2189
|
}
|
|
2134
2190
|
console.log();
|
|
2135
2191
|
console.log(
|
|
2136
|
-
|
|
2192
|
+
chalk5.yellow(
|
|
2137
2193
|
" Run the following to untrack them (without deleting the files):"
|
|
2138
2194
|
)
|
|
2139
2195
|
);
|
|
2140
2196
|
for (const file of trackedFiles) {
|
|
2141
|
-
console.log(
|
|
2197
|
+
console.log(chalk5.cyan(` git rm --cached ${file}`));
|
|
2142
2198
|
}
|
|
2143
2199
|
console.log();
|
|
2144
2200
|
process.exit(1);
|
|
@@ -2147,7 +2203,7 @@ function checkTrackedFiles() {
|
|
|
2147
2203
|
|
|
2148
2204
|
// src/commands/push.ts
|
|
2149
2205
|
import { Command as Command4 } from "commander";
|
|
2150
|
-
import
|
|
2206
|
+
import chalk6 from "chalk";
|
|
2151
2207
|
import inquirer3 from "inquirer";
|
|
2152
2208
|
|
|
2153
2209
|
// src/lib/validators.ts
|
|
@@ -2235,16 +2291,16 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
2235
2291
|
error("Security risk: .env files are tracked by git!");
|
|
2236
2292
|
console.log();
|
|
2237
2293
|
for (const file of trackedFiles) {
|
|
2238
|
-
console.log(
|
|
2294
|
+
console.log(chalk6.red(` tracked: ${file}`));
|
|
2239
2295
|
}
|
|
2240
2296
|
console.log();
|
|
2241
2297
|
console.log(
|
|
2242
|
-
|
|
2298
|
+
chalk6.yellow(
|
|
2243
2299
|
" Run the following to untrack them (without deleting the files):"
|
|
2244
2300
|
)
|
|
2245
2301
|
);
|
|
2246
2302
|
for (const file of trackedFiles) {
|
|
2247
|
-
console.log(
|
|
2303
|
+
console.log(chalk6.cyan(` git rm --cached ${file}`));
|
|
2248
2304
|
}
|
|
2249
2305
|
console.log();
|
|
2250
2306
|
process.exit(1);
|
|
@@ -2311,7 +2367,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
2311
2367
|
if (invalid.length > 0) {
|
|
2312
2368
|
warning("Some variables have invalid keys and will be skipped:");
|
|
2313
2369
|
for (const { key, error: err } of invalid) {
|
|
2314
|
-
console.log(
|
|
2370
|
+
console.log(chalk6.red(` ${key}: ${err}`));
|
|
2315
2371
|
}
|
|
2316
2372
|
console.log();
|
|
2317
2373
|
}
|
|
@@ -2344,14 +2400,14 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
2344
2400
|
return;
|
|
2345
2401
|
}
|
|
2346
2402
|
console.log();
|
|
2347
|
-
console.log(
|
|
2403
|
+
console.log(chalk6.bold("Changes to push:"));
|
|
2348
2404
|
console.log();
|
|
2349
2405
|
const removedToShow = mode === "replace" ? diffResult.removed : {};
|
|
2350
2406
|
diff(diffResult.added, removedToShow, diffResult.changed);
|
|
2351
2407
|
if (mode === "merge" && Object.keys(diffResult.removed).length > 0) {
|
|
2352
2408
|
console.log();
|
|
2353
2409
|
console.log(
|
|
2354
|
-
|
|
2410
|
+
chalk6.dim(
|
|
2355
2411
|
`Note: ${Object.keys(diffResult.removed).length} remote variables not in local file will be preserved (use --replace to remove them)`
|
|
2356
2412
|
)
|
|
2357
2413
|
);
|
|
@@ -2388,7 +2444,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
2388
2444
|
}
|
|
2389
2445
|
}
|
|
2390
2446
|
const result = await withSpinner(
|
|
2391
|
-
`Pushing variables to ${
|
|
2447
|
+
`Pushing variables to ${chalk6.bold(environment)}...`,
|
|
2392
2448
|
async () => {
|
|
2393
2449
|
const response = await api.post("/api/cli/variables/bulk", {
|
|
2394
2450
|
projectId,
|
|
@@ -2405,28 +2461,28 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
2405
2461
|
);
|
|
2406
2462
|
if (result?.requested && result.requested > 0) {
|
|
2407
2463
|
success(
|
|
2408
|
-
`Created ${result.requested} pending request(s) for ${
|
|
2464
|
+
`Created ${result.requested} pending request(s) for ${chalk6.bold(environment)}`
|
|
2409
2465
|
);
|
|
2410
2466
|
console.log();
|
|
2411
2467
|
console.log(
|
|
2412
|
-
|
|
2468
|
+
chalk6.yellow(
|
|
2413
2469
|
" These changes require approval from an Admin or Team Lead."
|
|
2414
2470
|
)
|
|
2415
2471
|
);
|
|
2416
2472
|
console.log();
|
|
2417
|
-
console.log(
|
|
2473
|
+
console.log(chalk6.dim(` Requested: ${result.requested}`));
|
|
2418
2474
|
if (result?.skipped && result.skipped > 0) {
|
|
2419
|
-
console.log(
|
|
2475
|
+
console.log(chalk6.dim(` Skipped: ${result.skipped}`));
|
|
2420
2476
|
}
|
|
2421
2477
|
} else {
|
|
2422
2478
|
success(
|
|
2423
|
-
`Pushed ${result?.total || Object.keys(valid).length} variables to ${
|
|
2479
|
+
`Pushed ${result?.total || Object.keys(valid).length} variables to ${chalk6.bold(environment)}`
|
|
2424
2480
|
);
|
|
2425
2481
|
console.log();
|
|
2426
|
-
console.log(
|
|
2427
|
-
console.log(
|
|
2482
|
+
console.log(chalk6.dim(` Created: ${result?.created || 0}`));
|
|
2483
|
+
console.log(chalk6.dim(` Updated: ${result?.updated || 0}`));
|
|
2428
2484
|
if (mode === "replace") {
|
|
2429
|
-
console.log(
|
|
2485
|
+
console.log(chalk6.dim(` Deleted: ${result?.deleted || 0}`));
|
|
2430
2486
|
}
|
|
2431
2487
|
}
|
|
2432
2488
|
} catch (err) {
|
|
@@ -2436,7 +2492,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
2436
2492
|
|
|
2437
2493
|
// src/commands/switch.ts
|
|
2438
2494
|
import { Command as Command5 } from "commander";
|
|
2439
|
-
import
|
|
2495
|
+
import chalk7 from "chalk";
|
|
2440
2496
|
import inquirer4 from "inquirer";
|
|
2441
2497
|
var switchCommand = new Command5("switch").description("Switch project, environment, or active linked project").argument("[target]", "project slug or environment name").option("-o, --organization <id>", "Switch organization").option("-p, --project <id>", "Switch project").option(
|
|
2442
2498
|
"-e, --env <environment>",
|
|
@@ -2464,7 +2520,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2464
2520
|
console.log();
|
|
2465
2521
|
console.log("Linked projects:");
|
|
2466
2522
|
for (const p of configV2.projects) {
|
|
2467
|
-
const mark = p.projectId === configV2.activeProjectId ?
|
|
2523
|
+
const mark = p.projectId === configV2.activeProjectId ? chalk7.green(" *") : "";
|
|
2468
2524
|
console.log(
|
|
2469
2525
|
` ${p.projectName || p.projectId} (${p.environment})${mark}`
|
|
2470
2526
|
);
|
|
@@ -2476,7 +2532,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2476
2532
|
setActiveProjectId(target2.projectId);
|
|
2477
2533
|
setActiveOrganizationId(target2.organizationId);
|
|
2478
2534
|
success(
|
|
2479
|
-
`Active project: ${
|
|
2535
|
+
`Active project: ${chalk7.bold(target2.projectName || target2.projectId)}`
|
|
2480
2536
|
);
|
|
2481
2537
|
return;
|
|
2482
2538
|
}
|
|
@@ -2487,7 +2543,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2487
2543
|
process.exit(1);
|
|
2488
2544
|
}
|
|
2489
2545
|
updateProjectConfig({ environment });
|
|
2490
|
-
success(`Switched to ${
|
|
2546
|
+
success(`Switched to ${chalk7.bold(environment)} environment`);
|
|
2491
2547
|
return;
|
|
2492
2548
|
}
|
|
2493
2549
|
if (options.organization) {
|
|
@@ -2512,9 +2568,9 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2512
2568
|
if (projectConfig) {
|
|
2513
2569
|
updateProjectConfig({ organizationId: org._id });
|
|
2514
2570
|
}
|
|
2515
|
-
success(`Switched to organization: ${
|
|
2571
|
+
success(`Switched to organization: ${chalk7.bold(org.name)}`);
|
|
2516
2572
|
if (org.role) {
|
|
2517
|
-
console.log(
|
|
2573
|
+
console.log(chalk7.dim(` Role: ${formatRole(org.role)}`));
|
|
2518
2574
|
roleNotice(org.role);
|
|
2519
2575
|
}
|
|
2520
2576
|
return;
|
|
@@ -2535,7 +2591,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2535
2591
|
setActiveProjectId(linked.projectId);
|
|
2536
2592
|
setActiveOrganizationId(linked.organizationId);
|
|
2537
2593
|
success(
|
|
2538
|
-
`Switched to project: ${
|
|
2594
|
+
`Switched to project: ${chalk7.bold(linked.projectName || linked.projectId)}`
|
|
2539
2595
|
);
|
|
2540
2596
|
return;
|
|
2541
2597
|
}
|
|
@@ -2565,7 +2621,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2565
2621
|
name: "orgId",
|
|
2566
2622
|
message: "Select an organization:",
|
|
2567
2623
|
choices: organizations.map((org) => ({
|
|
2568
|
-
name: `${org.name} ${org.tier === "pro" ?
|
|
2624
|
+
name: `${org.name} ${org.tier === "pro" ? chalk7.green("(Pro)") : chalk7.dim("(Free)")}`,
|
|
2569
2625
|
value: org._id
|
|
2570
2626
|
}))
|
|
2571
2627
|
}
|
|
@@ -2601,10 +2657,10 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2601
2657
|
organizationId,
|
|
2602
2658
|
environment
|
|
2603
2659
|
});
|
|
2604
|
-
success(`Switched to project: ${
|
|
2660
|
+
success(`Switched to project: ${chalk7.bold(project.name)}`);
|
|
2605
2661
|
if (project.projectRole) {
|
|
2606
2662
|
console.log(
|
|
2607
|
-
|
|
2663
|
+
chalk7.dim(
|
|
2608
2664
|
` Project role: ${formatProjectRole(project.projectRole)}`
|
|
2609
2665
|
)
|
|
2610
2666
|
);
|
|
@@ -2644,7 +2700,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2644
2700
|
choices: configV2.projects.map((p) => {
|
|
2645
2701
|
const isActive = p.projectId === configV2.activeProjectId;
|
|
2646
2702
|
return {
|
|
2647
|
-
name: `${p.projectName || p.projectId} (${p.environment})${isActive ?
|
|
2703
|
+
name: `${p.projectName || p.projectId} (${p.environment})${isActive ? chalk7.green(" *current") : ""}`,
|
|
2648
2704
|
value: p.projectId
|
|
2649
2705
|
};
|
|
2650
2706
|
}),
|
|
@@ -2659,7 +2715,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2659
2715
|
setActiveProjectId(projectId);
|
|
2660
2716
|
setActiveOrganizationId(selected.organizationId);
|
|
2661
2717
|
success(
|
|
2662
|
-
`Active project: ${
|
|
2718
|
+
`Active project: ${chalk7.bold(selected.projectName || selected.projectId)}`
|
|
2663
2719
|
);
|
|
2664
2720
|
return;
|
|
2665
2721
|
}
|
|
@@ -2682,7 +2738,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2682
2738
|
}
|
|
2683
2739
|
]);
|
|
2684
2740
|
updateProjectConfig({ environment });
|
|
2685
|
-
success(`Switched to ${
|
|
2741
|
+
success(`Switched to ${chalk7.bold(environment)} environment`);
|
|
2686
2742
|
return;
|
|
2687
2743
|
}
|
|
2688
2744
|
if (switchType === "organization" || switchType === "project") {
|
|
@@ -2703,7 +2759,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2703
2759
|
name: "orgId",
|
|
2704
2760
|
message: "Select an organization:",
|
|
2705
2761
|
choices: organizations.map((org) => ({
|
|
2706
|
-
name: `${org.name} ${org.tier === "pro" ?
|
|
2762
|
+
name: `${org.name} ${org.tier === "pro" ? chalk7.green("(Pro)") : chalk7.dim("(Free)")}`,
|
|
2707
2763
|
value: org._id
|
|
2708
2764
|
})),
|
|
2709
2765
|
default: projectConfig?.organizationId
|
|
@@ -2715,9 +2771,9 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2715
2771
|
if (org.role) {
|
|
2716
2772
|
setRole(org.role);
|
|
2717
2773
|
}
|
|
2718
|
-
success(`Switched to organization: ${
|
|
2774
|
+
success(`Switched to organization: ${chalk7.bold(org.name)}`);
|
|
2719
2775
|
if (org.role) {
|
|
2720
|
-
console.log(
|
|
2776
|
+
console.log(chalk7.dim(` Role: ${formatRole(org.role)}`));
|
|
2721
2777
|
roleNotice(org.role);
|
|
2722
2778
|
}
|
|
2723
2779
|
return;
|
|
@@ -2758,10 +2814,10 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2758
2814
|
organizationId: orgId,
|
|
2759
2815
|
environment
|
|
2760
2816
|
});
|
|
2761
|
-
success(`Switched to project: ${
|
|
2817
|
+
success(`Switched to project: ${chalk7.bold(project.name)}`);
|
|
2762
2818
|
if (project.projectRole) {
|
|
2763
2819
|
console.log(
|
|
2764
|
-
|
|
2820
|
+
chalk7.dim(
|
|
2765
2821
|
` Project role: ${formatProjectRole(project.projectRole)}`
|
|
2766
2822
|
)
|
|
2767
2823
|
);
|
|
@@ -2776,7 +2832,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
|
|
|
2776
2832
|
|
|
2777
2833
|
// src/commands/list.ts
|
|
2778
2834
|
import { Command as Command6 } from "commander";
|
|
2779
|
-
import
|
|
2835
|
+
import chalk8 from "chalk";
|
|
2780
2836
|
var listCommand = new Command6("list").description("List resources").argument(
|
|
2781
2837
|
"[resource]",
|
|
2782
2838
|
"Resource type: projects, organizations, variables, linked",
|
|
@@ -2831,19 +2887,19 @@ function listLinked() {
|
|
|
2831
2887
|
console.log();
|
|
2832
2888
|
for (const project of configV2.projects) {
|
|
2833
2889
|
const isActive = project.projectId === configV2.activeProjectId;
|
|
2834
|
-
const marker = isActive ?
|
|
2890
|
+
const marker = isActive ? chalk8.green("*") : " ";
|
|
2835
2891
|
const envFile = getEnvPathForEnvironment(project.environment);
|
|
2836
2892
|
console.log(
|
|
2837
|
-
` ${marker} ${
|
|
2893
|
+
` ${marker} ${chalk8.bold(project.projectName || project.projectId)} ${chalk8.dim(`(${project.organizationName || project.organizationId})`)}`
|
|
2838
2894
|
);
|
|
2839
|
-
console.log(` ${project.environment} ${
|
|
2895
|
+
console.log(` ${project.environment} ${chalk8.dim("\u2192")} ${envFile}`);
|
|
2840
2896
|
console.log();
|
|
2841
2897
|
}
|
|
2842
2898
|
if (configV2.projects.length > 1) {
|
|
2843
|
-
console.log(
|
|
2899
|
+
console.log(chalk8.dim(" (* = active project)"));
|
|
2844
2900
|
console.log();
|
|
2845
2901
|
console.log(
|
|
2846
|
-
|
|
2902
|
+
chalk8.dim(
|
|
2847
2903
|
' Use `envpilot switch --active "<name>"` to change the active project'
|
|
2848
2904
|
)
|
|
2849
2905
|
);
|
|
@@ -2871,7 +2927,7 @@ async function listOrganizations(api, options) {
|
|
|
2871
2927
|
organizations.map((org) => ({
|
|
2872
2928
|
name: org.name,
|
|
2873
2929
|
slug: org.slug,
|
|
2874
|
-
tier: org.tier === "pro" ?
|
|
2930
|
+
tier: org.tier === "pro" ? chalk8.green("Pro") : chalk8.dim("Free"),
|
|
2875
2931
|
role: org.role
|
|
2876
2932
|
})),
|
|
2877
2933
|
[
|
|
@@ -2929,9 +2985,9 @@ async function listProjects(api, projectConfig, options) {
|
|
|
2929
2985
|
icon: project.icon || "\u{1F4E6}",
|
|
2930
2986
|
name: project.name,
|
|
2931
2987
|
slug: project.slug,
|
|
2932
|
-
description: project.description ||
|
|
2988
|
+
description: project.description || chalk8.dim("-"),
|
|
2933
2989
|
role: project.userRole === "admin" ? formatRole("admin") : formatProjectRole(project.projectRole),
|
|
2934
|
-
active: projectConfig?.projectId === project._id ?
|
|
2990
|
+
active: projectConfig?.projectId === project._id ? chalk8.green("\u2713") : ""
|
|
2935
2991
|
})),
|
|
2936
2992
|
[
|
|
2937
2993
|
{ key: "icon", header: "" },
|
|
@@ -2945,7 +3001,7 @@ async function listProjects(api, projectConfig, options) {
|
|
|
2945
3001
|
const role = getRole();
|
|
2946
3002
|
if (role) {
|
|
2947
3003
|
console.log();
|
|
2948
|
-
console.log(
|
|
3004
|
+
console.log(chalk8.dim(`Your org role: ${formatRole(role)}`));
|
|
2949
3005
|
}
|
|
2950
3006
|
}
|
|
2951
3007
|
async function listVariables(api, projectConfig, options) {
|
|
@@ -2992,8 +3048,8 @@ async function listVariables(api, projectConfig, options) {
|
|
|
2992
3048
|
filtered.map((variable) => ({
|
|
2993
3049
|
key: variable.key,
|
|
2994
3050
|
value: options.showValues ? variable.value : maskValue(variable.value),
|
|
2995
|
-
sensitive: variable.isSensitive ?
|
|
2996
|
-
tags: hasTags ? variable.tags?.map((t) => t.name).join(", ") ||
|
|
3051
|
+
sensitive: variable.isSensitive ? chalk8.yellow("\u25CF") : "",
|
|
3052
|
+
tags: hasTags ? variable.tags?.map((t) => t.name).join(", ") || chalk8.dim("-") : "",
|
|
2997
3053
|
version: `v${variable.version}`
|
|
2998
3054
|
})),
|
|
2999
3055
|
[
|
|
@@ -3005,29 +3061,29 @@ async function listVariables(api, projectConfig, options) {
|
|
|
3005
3061
|
]
|
|
3006
3062
|
);
|
|
3007
3063
|
console.log();
|
|
3008
|
-
console.log(
|
|
3064
|
+
console.log(chalk8.dim(`Total: ${filtered.length} variables`));
|
|
3009
3065
|
const role = getRole();
|
|
3010
3066
|
if (role) {
|
|
3011
|
-
console.log(
|
|
3067
|
+
console.log(chalk8.dim(`Your org role: ${formatRole(role)}`));
|
|
3012
3068
|
}
|
|
3013
3069
|
if (metaProjectRole) {
|
|
3014
3070
|
console.log(
|
|
3015
|
-
|
|
3071
|
+
chalk8.dim(`Your project role: ${formatProjectRole(metaProjectRole)}`)
|
|
3016
3072
|
);
|
|
3017
3073
|
}
|
|
3018
3074
|
if (role === "member" || metaProjectRole === "viewer") {
|
|
3019
3075
|
console.log(
|
|
3020
|
-
|
|
3076
|
+
chalk8.dim("You may only see variables you have been granted access to.")
|
|
3021
3077
|
);
|
|
3022
3078
|
}
|
|
3023
3079
|
if (!options.showValues) {
|
|
3024
|
-
console.log(
|
|
3080
|
+
console.log(chalk8.dim("Use --show-values to see actual values"));
|
|
3025
3081
|
}
|
|
3026
3082
|
}
|
|
3027
3083
|
|
|
3028
3084
|
// src/commands/config.ts
|
|
3029
3085
|
import { Command as Command7 } from "commander";
|
|
3030
|
-
import
|
|
3086
|
+
import chalk9 from "chalk";
|
|
3031
3087
|
var configCommand = new Command7("config").description("Manage CLI configuration").argument("[action]", "Action: get, set, list, path, reset").argument("[key]", "Config key (for get/set)").argument("[value]", "Config value (for set)").action(async (action, key, value) => {
|
|
3032
3088
|
try {
|
|
3033
3089
|
switch (action) {
|
|
@@ -3082,14 +3138,14 @@ async function handleGet(key) {
|
|
|
3082
3138
|
if (config2.user) {
|
|
3083
3139
|
console.log(JSON.stringify(config2.user, null, 2));
|
|
3084
3140
|
} else {
|
|
3085
|
-
console.log(
|
|
3141
|
+
console.log(chalk9.dim("(not set)"));
|
|
3086
3142
|
}
|
|
3087
3143
|
break;
|
|
3088
3144
|
case "activeProjectId":
|
|
3089
|
-
console.log(config2.activeProjectId ||
|
|
3145
|
+
console.log(config2.activeProjectId || chalk9.dim("(not set)"));
|
|
3090
3146
|
break;
|
|
3091
3147
|
case "activeOrganizationId":
|
|
3092
|
-
console.log(config2.activeOrganizationId ||
|
|
3148
|
+
console.log(config2.activeOrganizationId || chalk9.dim("(not set)"));
|
|
3093
3149
|
break;
|
|
3094
3150
|
default:
|
|
3095
3151
|
error(`Unknown key: ${key}`);
|
|
@@ -3105,16 +3161,18 @@ async function handleSet(key, value) {
|
|
|
3105
3161
|
process.exit(1);
|
|
3106
3162
|
}
|
|
3107
3163
|
switch (key) {
|
|
3108
|
-
case "apiUrl":
|
|
3164
|
+
case "apiUrl": {
|
|
3165
|
+
const normalized = normalizeApiUrl(value);
|
|
3109
3166
|
try {
|
|
3110
|
-
new URL(
|
|
3167
|
+
new URL(normalized);
|
|
3111
3168
|
} catch {
|
|
3112
3169
|
error("Invalid URL format");
|
|
3113
3170
|
process.exit(1);
|
|
3114
3171
|
}
|
|
3115
3172
|
setApiUrl(value);
|
|
3116
|
-
success(`Set apiUrl to ${
|
|
3173
|
+
success(`Set apiUrl to ${normalized}`);
|
|
3117
3174
|
break;
|
|
3175
|
+
}
|
|
3118
3176
|
default:
|
|
3119
3177
|
error(`Cannot set key: ${key}`);
|
|
3120
3178
|
console.log();
|
|
@@ -3130,7 +3188,7 @@ async function handleList() {
|
|
|
3130
3188
|
console.log();
|
|
3131
3189
|
keyValue([
|
|
3132
3190
|
["API URL", config2.apiUrl],
|
|
3133
|
-
["Authenticated", isAuthenticated() ?
|
|
3191
|
+
["Authenticated", isAuthenticated() ? chalk9.green("Yes") : chalk9.red("No")],
|
|
3134
3192
|
["User", config2.user?.email],
|
|
3135
3193
|
["Active Organization", config2.activeOrganizationId],
|
|
3136
3194
|
["Active Project", config2.activeProjectId]
|
|
@@ -3199,7 +3257,7 @@ var logoutCommand = new Command8("logout").description("Log out from Envpilot").
|
|
|
3199
3257
|
|
|
3200
3258
|
// src/commands/unlink.ts
|
|
3201
3259
|
import { Command as Command9 } from "commander";
|
|
3202
|
-
import
|
|
3260
|
+
import chalk10 from "chalk";
|
|
3203
3261
|
import inquirer5 from "inquirer";
|
|
3204
3262
|
var unlinkCommand = new Command9("unlink").description("Remove a linked project from this directory").argument("[project]", "Project name or ID to unlink").option("--force", "Skip confirmation").action(async (projectArg, options) => {
|
|
3205
3263
|
try {
|
|
@@ -3234,7 +3292,7 @@ var unlinkCommand = new Command9("unlink").description("Remove a linked project
|
|
|
3234
3292
|
choices: config2.projects.map((p) => {
|
|
3235
3293
|
const isActive = p.projectId === config2.activeProjectId;
|
|
3236
3294
|
return {
|
|
3237
|
-
name: `${p.projectName || p.projectId} (${p.organizationName || p.organizationId})${isActive ?
|
|
3295
|
+
name: `${p.projectName || p.projectId} (${p.organizationName || p.organizationId})${isActive ? chalk10.green(" *active") : ""}`,
|
|
3238
3296
|
value: p.projectId
|
|
3239
3297
|
};
|
|
3240
3298
|
})
|
|
@@ -3277,7 +3335,7 @@ var unlinkCommand = new Command9("unlink").description("Remove a linked project
|
|
|
3277
3335
|
);
|
|
3278
3336
|
}
|
|
3279
3337
|
console.log(
|
|
3280
|
-
|
|
3338
|
+
chalk10.dim(
|
|
3281
3339
|
` ${updated.projects.length} project${updated.projects.length !== 1 ? "s" : ""} remaining`
|
|
3282
3340
|
)
|
|
3283
3341
|
);
|
|
@@ -3289,7 +3347,7 @@ var unlinkCommand = new Command9("unlink").description("Remove a linked project
|
|
|
3289
3347
|
|
|
3290
3348
|
// src/commands/sync.ts
|
|
3291
3349
|
import { Command as Command10 } from "commander";
|
|
3292
|
-
import
|
|
3350
|
+
import chalk11 from "chalk";
|
|
3293
3351
|
|
|
3294
3352
|
// src/lib/commit-guard.ts
|
|
3295
3353
|
import {
|
|
@@ -3467,7 +3525,7 @@ var syncCommand = new Command10("sync").description(
|
|
|
3467
3525
|
projectName = active.projectName;
|
|
3468
3526
|
organizationName = active.organizationName;
|
|
3469
3527
|
info(
|
|
3470
|
-
`Using project ${
|
|
3528
|
+
`Using project ${chalk11.bold(projectName || projectId)} (${environment})`
|
|
3471
3529
|
);
|
|
3472
3530
|
} else {
|
|
3473
3531
|
const selection = await selectOrgProjectEnv(options);
|
|
@@ -3521,7 +3579,7 @@ var syncCommand = new Command10("sync").description(
|
|
|
3521
3579
|
console.log();
|
|
3522
3580
|
let metaProjectRole;
|
|
3523
3581
|
const variables = await withSpinner(
|
|
3524
|
-
`Fetching ${
|
|
3582
|
+
`Fetching ${chalk11.bold(environment)} variables...`,
|
|
3525
3583
|
async () => {
|
|
3526
3584
|
const api = createAPIClient();
|
|
3527
3585
|
const response = await api.get("/api/cli/variables", {
|
|
@@ -3547,12 +3605,12 @@ var syncCommand = new Command10("sync").description(
|
|
|
3547
3605
|
const diffResult = diffEnvVars(remoteVars, localVars);
|
|
3548
3606
|
const hasChanges = Object.keys(diffResult.added).length > 0 || Object.keys(diffResult.removed).length > 0 || Object.keys(diffResult.changed).length > 0;
|
|
3549
3607
|
if (!hasChanges) {
|
|
3550
|
-
success(`${
|
|
3608
|
+
success(`${chalk11.bold(outputPath)} is up to date.`);
|
|
3551
3609
|
console.log();
|
|
3552
3610
|
return;
|
|
3553
3611
|
}
|
|
3554
3612
|
console.log();
|
|
3555
|
-
console.log(
|
|
3613
|
+
console.log(chalk11.bold("Changes:"));
|
|
3556
3614
|
console.log();
|
|
3557
3615
|
diff(diffResult.added, diffResult.removed, diffResult.changed);
|
|
3558
3616
|
console.log();
|
|
@@ -3573,7 +3631,7 @@ var syncCommand = new Command10("sync").description(
|
|
|
3573
3631
|
const role = getRole();
|
|
3574
3632
|
applyFileProtection(outputPath, role, metaProjectRole);
|
|
3575
3633
|
success(
|
|
3576
|
-
`Synced ${variables.length} variables to ${
|
|
3634
|
+
`Synced ${variables.length} variables to ${chalk11.bold(outputPath)}`
|
|
3577
3635
|
);
|
|
3578
3636
|
const isProtected = role !== "admin" && role !== "team_lead" && metaProjectRole !== "manager";
|
|
3579
3637
|
if (isProtected) {
|
|
@@ -3583,13 +3641,13 @@ var syncCommand = new Command10("sync").description(
|
|
|
3583
3641
|
}
|
|
3584
3642
|
console.log();
|
|
3585
3643
|
console.log(
|
|
3586
|
-
|
|
3644
|
+
chalk11.dim(` Added: ${Object.keys(diffResult.added).length}`)
|
|
3587
3645
|
);
|
|
3588
3646
|
console.log(
|
|
3589
|
-
|
|
3647
|
+
chalk11.dim(` Changed: ${Object.keys(diffResult.changed).length}`)
|
|
3590
3648
|
);
|
|
3591
3649
|
console.log(
|
|
3592
|
-
|
|
3650
|
+
chalk11.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
|
|
3593
3651
|
);
|
|
3594
3652
|
console.log();
|
|
3595
3653
|
} catch (err) {
|
|
@@ -3599,17 +3657,17 @@ var syncCommand = new Command10("sync").description(
|
|
|
3599
3657
|
|
|
3600
3658
|
// src/commands/usage.ts
|
|
3601
3659
|
import { Command as Command11 } from "commander";
|
|
3602
|
-
import
|
|
3660
|
+
import chalk12 from "chalk";
|
|
3603
3661
|
function formatUsage(current, limit) {
|
|
3604
3662
|
const limitStr = limit === null ? "unlimited" : String(limit);
|
|
3605
3663
|
const ratio = `${current}/${limitStr}`;
|
|
3606
|
-
if (limit === null) return
|
|
3607
|
-
if (current >= limit) return
|
|
3608
|
-
if (current >= limit * 0.8) return
|
|
3609
|
-
return
|
|
3664
|
+
if (limit === null) return chalk12.green(ratio);
|
|
3665
|
+
if (current >= limit) return chalk12.red(ratio);
|
|
3666
|
+
if (current >= limit * 0.8) return chalk12.yellow(ratio);
|
|
3667
|
+
return chalk12.green(ratio);
|
|
3610
3668
|
}
|
|
3611
3669
|
function featureStatus(enabled) {
|
|
3612
|
-
return enabled ?
|
|
3670
|
+
return enabled ? chalk12.green("Enabled") : chalk12.dim("Disabled (Pro)");
|
|
3613
3671
|
}
|
|
3614
3672
|
var usageCommand = new Command11("usage").description("Show plan usage and limits for the active organization").option("-o, --organization <id>", "Organization ID").option("--json", "Output as JSON").action(async (options) => {
|
|
3615
3673
|
try {
|
|
@@ -3654,7 +3712,7 @@ var usageCommand = new Command11("usage").description("Show plan usage and limit
|
|
|
3654
3712
|
console.log(JSON.stringify(usage, null, 2));
|
|
3655
3713
|
return;
|
|
3656
3714
|
}
|
|
3657
|
-
const tierLabel = usage.tier === "pro" ?
|
|
3715
|
+
const tierLabel = usage.tier === "pro" ? chalk12.green("Pro") : chalk12.white("Free");
|
|
3658
3716
|
header(`Plan: ${tierLabel}`);
|
|
3659
3717
|
blank();
|
|
3660
3718
|
if (!usage.enforcementEnabled) {
|
|
@@ -3708,7 +3766,7 @@ var usageCommand = new Command11("usage").description("Show plan usage and limit
|
|
|
3708
3766
|
|
|
3709
3767
|
// src/commands/whoami.ts
|
|
3710
3768
|
import { Command as Command12 } from "commander";
|
|
3711
|
-
import
|
|
3769
|
+
import chalk13 from "chalk";
|
|
3712
3770
|
var whoamiCommand = new Command12("whoami").description("Show the current authenticated user and active CLI context").action(async () => {
|
|
3713
3771
|
try {
|
|
3714
3772
|
if (!isAuthenticated()) {
|
|
@@ -3734,7 +3792,7 @@ var whoamiCommand = new Command12("whoami").description("Show the current authen
|
|
|
3734
3792
|
["Environment", activeProject?.environment]
|
|
3735
3793
|
]);
|
|
3736
3794
|
blank();
|
|
3737
|
-
console.log(
|
|
3795
|
+
console.log(chalk13.dim("Token verified against the CLI auth endpoint."));
|
|
3738
3796
|
} catch (err) {
|
|
3739
3797
|
await handleError(err);
|
|
3740
3798
|
}
|
|
@@ -3743,7 +3801,7 @@ var whoamiCommand = new Command12("whoami").description("Show the current authen
|
|
|
3743
3801
|
// src/commands/run.ts
|
|
3744
3802
|
import { Command as Command13 } from "commander";
|
|
3745
3803
|
import { spawn as spawn2 } from "child_process";
|
|
3746
|
-
import
|
|
3804
|
+
import chalk14 from "chalk";
|
|
3747
3805
|
|
|
3748
3806
|
// src/lib/variables-cache.ts
|
|
3749
3807
|
import { createHash } from "crypto";
|
|
@@ -3991,9 +4049,9 @@ var runCommand = new Command13("run").description(
|
|
|
3991
4049
|
}
|
|
3992
4050
|
if (!options.quiet) {
|
|
3993
4051
|
const injectedCount = Object.keys(secrets).length;
|
|
3994
|
-
const cacheTag = cacheHit ?
|
|
4052
|
+
const cacheTag = cacheHit ? chalk14.dim(` \u26A1 cache (${cacheAge})`) : "";
|
|
3995
4053
|
info(
|
|
3996
|
-
`Injected ${
|
|
4054
|
+
`Injected ${chalk14.bold(injectedCount)} ${injectedCount === 1 ? "variable" : "variables"} from ${chalk14.bold(`${project.projectName || project.projectId}/${environment}`)}${cacheTag}`
|
|
3997
4055
|
);
|
|
3998
4056
|
if (overridden.length > 0) {
|
|
3999
4057
|
warning(
|
|
@@ -4009,7 +4067,7 @@ var runCommand = new Command13("run").description(
|
|
|
4009
4067
|
}
|
|
4010
4068
|
});
|
|
4011
4069
|
async function doFetch(project, environment, organizationId, quiet, labelPrefix = "Loading") {
|
|
4012
|
-
const label = `${labelPrefix} ${
|
|
4070
|
+
const label = `${labelPrefix} ${chalk14.bold(environment)} secrets for ${chalk14.bold(project.projectName || project.projectId)}...`;
|
|
4013
4071
|
const api = createAPIClient();
|
|
4014
4072
|
const { variables, decryptionFailures } = quiet ? await api.listVariables(project.projectId, environment, organizationId) : await withSpinner(
|
|
4015
4073
|
label,
|
|
@@ -4018,7 +4076,7 @@ async function doFetch(project, environment, organizationId, quiet, labelPrefix
|
|
|
4018
4076
|
if (decryptionFailures.length > 0) {
|
|
4019
4077
|
for (const key of decryptionFailures) {
|
|
4020
4078
|
warning(
|
|
4021
|
-
`Could not decrypt ${
|
|
4079
|
+
`Could not decrypt ${chalk14.bold(key)} \u2014 skipped (vault error, check server logs)`
|
|
4022
4080
|
);
|
|
4023
4081
|
}
|
|
4024
4082
|
}
|
|
@@ -4028,18 +4086,18 @@ function printInjectionPreview(secrets, project, environment) {
|
|
|
4028
4086
|
const keys = Object.keys(secrets).sort();
|
|
4029
4087
|
console.log();
|
|
4030
4088
|
console.log(
|
|
4031
|
-
|
|
4032
|
-
`Would inject ${keys.length} ${keys.length === 1 ? "variable" : "variables"} from ${
|
|
4089
|
+
chalk14.bold(
|
|
4090
|
+
`Would inject ${keys.length} ${keys.length === 1 ? "variable" : "variables"} from ${chalk14.cyan(`${project.projectName || project.projectId}/${environment}`)}:`
|
|
4033
4091
|
)
|
|
4034
4092
|
);
|
|
4035
4093
|
console.log();
|
|
4036
4094
|
if (keys.length === 0) {
|
|
4037
|
-
console.log(
|
|
4095
|
+
console.log(chalk14.dim(" (no variables)"));
|
|
4038
4096
|
} else {
|
|
4039
4097
|
for (const key of keys) {
|
|
4040
4098
|
const value = secrets[key];
|
|
4041
4099
|
const masked = maskForPreview(value);
|
|
4042
|
-
console.log(` ${
|
|
4100
|
+
console.log(` ${chalk14.cyan(key)}=${chalk14.dim(masked)}`);
|
|
4043
4101
|
}
|
|
4044
4102
|
}
|
|
4045
4103
|
console.log();
|
|
@@ -4119,38 +4177,38 @@ function runChild(commandArgs, env, options) {
|
|
|
4119
4177
|
|
|
4120
4178
|
// src/commands/man.ts
|
|
4121
4179
|
import { Command as Command14 } from "commander";
|
|
4122
|
-
import
|
|
4180
|
+
import chalk15 from "chalk";
|
|
4123
4181
|
function printCommandManual(commandName) {
|
|
4124
4182
|
const command = findCommandDefinition(commandName);
|
|
4125
4183
|
if (!command) {
|
|
4126
|
-
console.log(
|
|
4184
|
+
console.log(chalk15.red(`Unknown command reference: ${commandName}`));
|
|
4127
4185
|
console.log();
|
|
4128
4186
|
console.log("Run `envpilot man` to see all supported commands.");
|
|
4129
4187
|
process.exit(1);
|
|
4130
4188
|
}
|
|
4131
|
-
console.log(
|
|
4189
|
+
console.log(chalk15.bold(formatArgv(command.argv)));
|
|
4132
4190
|
if (command.args) {
|
|
4133
|
-
console.log(
|
|
4191
|
+
console.log(chalk15.dim(command.args));
|
|
4134
4192
|
}
|
|
4135
4193
|
blank();
|
|
4136
4194
|
console.log(command.description);
|
|
4137
4195
|
blank();
|
|
4138
|
-
console.log(
|
|
4196
|
+
console.log(chalk15.green("Examples"));
|
|
4139
4197
|
for (const example of command.examples) {
|
|
4140
|
-
console.log(` ${
|
|
4198
|
+
console.log(` ${chalk15.cyan(formatArgv(example))}`);
|
|
4141
4199
|
}
|
|
4142
4200
|
blank();
|
|
4143
|
-
console.log(
|
|
4201
|
+
console.log(chalk15.green("Notes"));
|
|
4144
4202
|
for (const note of command.notes) {
|
|
4145
4203
|
console.log(` - ${note}`);
|
|
4146
4204
|
}
|
|
4147
4205
|
}
|
|
4148
4206
|
function printManualIndex(commands) {
|
|
4149
|
-
console.log(
|
|
4207
|
+
console.log(chalk15.bold("ENVPILOT(1)"));
|
|
4150
4208
|
console.log("TypeScript CLI manual");
|
|
4151
4209
|
blank();
|
|
4152
4210
|
console.log(
|
|
4153
|
-
`Total supported top-level commands: ${
|
|
4211
|
+
`Total supported top-level commands: ${chalk15.green(String(CLI_COMMAND_COUNT))}`
|
|
4154
4212
|
);
|
|
4155
4213
|
blank();
|
|
4156
4214
|
console.log(
|
|
@@ -4158,15 +4216,15 @@ function printManualIndex(commands) {
|
|
|
4158
4216
|
);
|
|
4159
4217
|
blank();
|
|
4160
4218
|
line();
|
|
4161
|
-
console.log(
|
|
4219
|
+
console.log(chalk15.green("Commands"));
|
|
4162
4220
|
for (const command of commands) {
|
|
4163
4221
|
console.log(
|
|
4164
|
-
` ${
|
|
4222
|
+
` ${chalk15.cyan(formatArgv(command.argv).padEnd(24))} ${chalk15.dim(command.description)}`
|
|
4165
4223
|
);
|
|
4166
4224
|
}
|
|
4167
4225
|
blank();
|
|
4168
4226
|
line();
|
|
4169
|
-
console.log(
|
|
4227
|
+
console.log(chalk15.green("Security"));
|
|
4170
4228
|
console.log(" - `.env*` is ignored by the repository `.gitignore`.");
|
|
4171
4229
|
console.log(
|
|
4172
4230
|
" - `envpilot init` and `envpilot sync` ensure env files are added to `.gitignore` locally."
|
|
@@ -4179,7 +4237,7 @@ function printManualIndex(commands) {
|
|
|
4179
4237
|
);
|
|
4180
4238
|
blank();
|
|
4181
4239
|
line();
|
|
4182
|
-
console.log(
|
|
4240
|
+
console.log(chalk15.green("Usage"));
|
|
4183
4241
|
console.log(
|
|
4184
4242
|
" - `envpilot` or `envpilot ui` opens the interactive terminal UI."
|
|
4185
4243
|
);
|