@envpilot/cli 1.1.0 → 1.3.0
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/dist/index.js +282 -69
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,11 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/lib/sentry.ts
|
|
4
|
+
import * as Sentry from "@sentry/node";
|
|
5
|
+
var initialized = false;
|
|
6
|
+
function initSentry() {
|
|
7
|
+
const dsn = true ? "" : "";
|
|
8
|
+
if (initialized || !dsn) return;
|
|
9
|
+
Sentry.init({
|
|
10
|
+
dsn,
|
|
11
|
+
environment: "cli",
|
|
12
|
+
release: true ? "1.3.0" : "0.0.0",
|
|
13
|
+
// Free tier: disable performance monitoring
|
|
14
|
+
tracesSampleRate: 0,
|
|
15
|
+
beforeSend(event) {
|
|
16
|
+
if (event.exception?.values) {
|
|
17
|
+
for (const exc of event.exception.values) {
|
|
18
|
+
if (exc.stacktrace?.frames) {
|
|
19
|
+
for (const frame of exc.stacktrace.frames) {
|
|
20
|
+
if (frame.filename) {
|
|
21
|
+
frame.filename = frame.filename.replace(
|
|
22
|
+
/\/Users\/[^/]+/g,
|
|
23
|
+
"/~"
|
|
24
|
+
);
|
|
25
|
+
frame.filename = frame.filename.replace(
|
|
26
|
+
/C:\\Users\\[^\\]+/g,
|
|
27
|
+
"C:\\~"
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (event.request?.data) {
|
|
35
|
+
event.request.data = "[REDACTED]";
|
|
36
|
+
}
|
|
37
|
+
return event;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
initialized = true;
|
|
41
|
+
}
|
|
42
|
+
function captureError(error2, context) {
|
|
43
|
+
if (!initialized) return;
|
|
44
|
+
Sentry.captureException(error2, { tags: context });
|
|
45
|
+
}
|
|
46
|
+
async function flushSentry() {
|
|
47
|
+
if (!initialized) return;
|
|
48
|
+
await Sentry.flush(2e3);
|
|
49
|
+
}
|
|
50
|
+
|
|
3
51
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
52
|
+
import { Command as Command10 } from "commander";
|
|
5
53
|
|
|
6
54
|
// src/commands/login.ts
|
|
7
55
|
import { Command } from "commander";
|
|
8
|
-
import
|
|
56
|
+
import chalk3 from "chalk";
|
|
9
57
|
import open from "open";
|
|
10
58
|
|
|
11
59
|
// src/lib/ui.ts
|
|
@@ -95,6 +143,9 @@ function maskValue(value, showChars = 4) {
|
|
|
95
143
|
}
|
|
96
144
|
return value.slice(0, showChars) + "****" + value.slice(-showChars);
|
|
97
145
|
}
|
|
146
|
+
function blank() {
|
|
147
|
+
console.log();
|
|
148
|
+
}
|
|
98
149
|
function formatRole(role) {
|
|
99
150
|
switch (role) {
|
|
100
151
|
case "admin":
|
|
@@ -176,6 +227,9 @@ function setRefreshToken(token) {
|
|
|
176
227
|
function setActiveProjectId(projectId) {
|
|
177
228
|
config.set("activeProjectId", projectId);
|
|
178
229
|
}
|
|
230
|
+
function getActiveOrganizationId() {
|
|
231
|
+
return config.get("activeOrganizationId");
|
|
232
|
+
}
|
|
179
233
|
function setActiveOrganizationId(organizationId) {
|
|
180
234
|
config.set("activeOrganizationId", organizationId);
|
|
181
235
|
}
|
|
@@ -348,12 +402,19 @@ var APIClient = class {
|
|
|
348
402
|
"UNAUTHORIZED"
|
|
349
403
|
);
|
|
350
404
|
}
|
|
405
|
+
if (response.status === 403 && code === "TIER_LIMIT_REACHED") {
|
|
406
|
+
throw new APIError(
|
|
407
|
+
message || "Tier limit reached. Run `envpilot usage` to see your plan limits.",
|
|
408
|
+
403,
|
|
409
|
+
"TIER_LIMIT_REACHED"
|
|
410
|
+
);
|
|
411
|
+
}
|
|
351
412
|
if (response.status === 403) {
|
|
352
413
|
throw new APIError(message || "Access denied.", 403, code || "FORBIDDEN");
|
|
353
414
|
}
|
|
354
415
|
if (response.status === 402) {
|
|
355
416
|
throw new APIError(
|
|
356
|
-
message || "
|
|
417
|
+
message || "Tier limit reached. Run `envpilot usage` to see your plan limits.",
|
|
357
418
|
402,
|
|
358
419
|
"PAYMENT_REQUIRED"
|
|
359
420
|
);
|
|
@@ -375,6 +436,12 @@ var APIClient = class {
|
|
|
375
436
|
async getTierInfo(organizationId) {
|
|
376
437
|
return this.get("/api/cli/tier", { organizationId });
|
|
377
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* Get usage info for the active organization
|
|
441
|
+
*/
|
|
442
|
+
async getUsage(organizationId) {
|
|
443
|
+
return this.get("/api/cli/usage", { organizationId });
|
|
444
|
+
}
|
|
378
445
|
/**
|
|
379
446
|
* List organizations the user has access to
|
|
380
447
|
*/
|
|
@@ -479,6 +546,91 @@ function createAPIClient() {
|
|
|
479
546
|
return new APIClient();
|
|
480
547
|
}
|
|
481
548
|
|
|
549
|
+
// src/lib/errors.ts
|
|
550
|
+
import chalk2 from "chalk";
|
|
551
|
+
var CLIError = class extends Error {
|
|
552
|
+
constructor(message, code, suggestion) {
|
|
553
|
+
super(message);
|
|
554
|
+
this.code = code;
|
|
555
|
+
this.suggestion = suggestion;
|
|
556
|
+
this.name = "CLIError";
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
var ErrorCodes = {
|
|
560
|
+
NOT_AUTHENTICATED: "NOT_AUTHENTICATED",
|
|
561
|
+
NOT_INITIALIZED: "NOT_INITIALIZED",
|
|
562
|
+
PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
|
|
563
|
+
ORGANIZATION_NOT_FOUND: "ORGANIZATION_NOT_FOUND",
|
|
564
|
+
VARIABLE_NOT_FOUND: "VARIABLE_NOT_FOUND",
|
|
565
|
+
INVALID_CONFIG: "INVALID_CONFIG",
|
|
566
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
567
|
+
PERMISSION_DENIED: "PERMISSION_DENIED",
|
|
568
|
+
TIER_LIMIT_EXCEEDED: "TIER_LIMIT_EXCEEDED",
|
|
569
|
+
FILE_NOT_FOUND: "FILE_NOT_FOUND",
|
|
570
|
+
INVALID_INPUT: "INVALID_INPUT",
|
|
571
|
+
UNKNOWN_ERROR: "UNKNOWN_ERROR"
|
|
572
|
+
};
|
|
573
|
+
function formatError(error2) {
|
|
574
|
+
if (error2 instanceof CLIError) {
|
|
575
|
+
let message = chalk2.red(`Error: ${error2.message}`);
|
|
576
|
+
if (error2.suggestion) {
|
|
577
|
+
message += `
|
|
578
|
+
${chalk2.yellow("Suggestion:")} ${error2.suggestion}`;
|
|
579
|
+
}
|
|
580
|
+
return message;
|
|
581
|
+
}
|
|
582
|
+
if (error2 instanceof Error) {
|
|
583
|
+
return chalk2.red(`Error: ${error2.message}`);
|
|
584
|
+
}
|
|
585
|
+
return chalk2.red(`Error: ${String(error2)}`);
|
|
586
|
+
}
|
|
587
|
+
async function handleError(error2) {
|
|
588
|
+
console.error(formatError(error2));
|
|
589
|
+
const skipCodes = /* @__PURE__ */ new Set([
|
|
590
|
+
ErrorCodes.NOT_AUTHENTICATED,
|
|
591
|
+
ErrorCodes.INVALID_INPUT,
|
|
592
|
+
ErrorCodes.NOT_INITIALIZED
|
|
593
|
+
]);
|
|
594
|
+
if (error2 instanceof CLIError) {
|
|
595
|
+
if (!skipCodes.has(error2.code)) {
|
|
596
|
+
captureError(error2, { errorCode: error2.code });
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
captureError(error2);
|
|
600
|
+
}
|
|
601
|
+
await flushSentry();
|
|
602
|
+
if (error2 instanceof CLIError) {
|
|
603
|
+
switch (error2.code) {
|
|
604
|
+
case ErrorCodes.NOT_AUTHENTICATED:
|
|
605
|
+
process.exit(2);
|
|
606
|
+
case ErrorCodes.PERMISSION_DENIED:
|
|
607
|
+
process.exit(3);
|
|
608
|
+
case ErrorCodes.TIER_LIMIT_EXCEEDED:
|
|
609
|
+
process.exit(4);
|
|
610
|
+
default:
|
|
611
|
+
process.exit(1);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
process.exit(1);
|
|
615
|
+
}
|
|
616
|
+
function notAuthenticated() {
|
|
617
|
+
return new CLIError(
|
|
618
|
+
"You are not authenticated.",
|
|
619
|
+
ErrorCodes.NOT_AUTHENTICATED,
|
|
620
|
+
"Run `envpilot login` to authenticate."
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function notInitialized() {
|
|
624
|
+
return new CLIError(
|
|
625
|
+
"This directory is not initialized with Envpilot.",
|
|
626
|
+
ErrorCodes.NOT_INITIALIZED,
|
|
627
|
+
"Run `envpilot init` to initialize."
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
function fileNotFound(path) {
|
|
631
|
+
return new CLIError(`File not found: ${path}`, ErrorCodes.FILE_NOT_FOUND);
|
|
632
|
+
}
|
|
633
|
+
|
|
482
634
|
// src/commands/login.ts
|
|
483
635
|
import { hostname } from "os";
|
|
484
636
|
var POLL_INTERVAL_MS = 2e3;
|
|
@@ -496,12 +648,12 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
|
|
|
496
648
|
const initResponse = await api.post("/api/cli/auth?action=initiate", { deviceName });
|
|
497
649
|
spinner.stop();
|
|
498
650
|
console.log();
|
|
499
|
-
console.log(
|
|
651
|
+
console.log(chalk3.bold("Your authentication code:"));
|
|
500
652
|
console.log();
|
|
501
|
-
console.log(
|
|
653
|
+
console.log(chalk3.cyan.bold(` ${initResponse.code}`));
|
|
502
654
|
console.log();
|
|
503
655
|
console.log(`Open this URL to authenticate:`);
|
|
504
|
-
console.log(
|
|
656
|
+
console.log(chalk3.dim(initResponse.url));
|
|
505
657
|
console.log();
|
|
506
658
|
if (options.browser !== false) {
|
|
507
659
|
info("Opening browser...");
|
|
@@ -531,14 +683,14 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
|
|
|
531
683
|
}
|
|
532
684
|
authenticated = true;
|
|
533
685
|
console.log();
|
|
534
|
-
success(`Logged in as ${
|
|
686
|
+
success(`Logged in as ${chalk3.bold(pollResponse.user?.email)}`);
|
|
535
687
|
console.log();
|
|
536
688
|
console.log("Next steps:");
|
|
537
689
|
console.log(
|
|
538
|
-
` ${
|
|
690
|
+
` ${chalk3.cyan("envpilot init")} Initialize a project in the current directory`
|
|
539
691
|
);
|
|
540
692
|
console.log(
|
|
541
|
-
` ${
|
|
693
|
+
` ${chalk3.cyan("envpilot list")} List your projects and organizations`
|
|
542
694
|
);
|
|
543
695
|
console.log();
|
|
544
696
|
break;
|
|
@@ -556,8 +708,7 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
|
|
|
556
708
|
process.exit(1);
|
|
557
709
|
}
|
|
558
710
|
} catch (err) {
|
|
559
|
-
|
|
560
|
-
process.exit(1);
|
|
711
|
+
await handleError(err);
|
|
561
712
|
}
|
|
562
713
|
});
|
|
563
714
|
function sleep(ms) {
|
|
@@ -690,48 +841,6 @@ function getTrackedEnvFiles(directory = process.cwd()) {
|
|
|
690
841
|
}
|
|
691
842
|
}
|
|
692
843
|
|
|
693
|
-
// src/lib/errors.ts
|
|
694
|
-
import chalk3 from "chalk";
|
|
695
|
-
var CLIError = class extends Error {
|
|
696
|
-
constructor(message, code, suggestion) {
|
|
697
|
-
super(message);
|
|
698
|
-
this.code = code;
|
|
699
|
-
this.suggestion = suggestion;
|
|
700
|
-
this.name = "CLIError";
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
var ErrorCodes = {
|
|
704
|
-
NOT_AUTHENTICATED: "NOT_AUTHENTICATED",
|
|
705
|
-
NOT_INITIALIZED: "NOT_INITIALIZED",
|
|
706
|
-
PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
|
|
707
|
-
ORGANIZATION_NOT_FOUND: "ORGANIZATION_NOT_FOUND",
|
|
708
|
-
VARIABLE_NOT_FOUND: "VARIABLE_NOT_FOUND",
|
|
709
|
-
INVALID_CONFIG: "INVALID_CONFIG",
|
|
710
|
-
NETWORK_ERROR: "NETWORK_ERROR",
|
|
711
|
-
PERMISSION_DENIED: "PERMISSION_DENIED",
|
|
712
|
-
TIER_LIMIT_EXCEEDED: "TIER_LIMIT_EXCEEDED",
|
|
713
|
-
FILE_NOT_FOUND: "FILE_NOT_FOUND",
|
|
714
|
-
INVALID_INPUT: "INVALID_INPUT",
|
|
715
|
-
UNKNOWN_ERROR: "UNKNOWN_ERROR"
|
|
716
|
-
};
|
|
717
|
-
function notAuthenticated() {
|
|
718
|
-
return new CLIError(
|
|
719
|
-
"You are not authenticated.",
|
|
720
|
-
ErrorCodes.NOT_AUTHENTICATED,
|
|
721
|
-
"Run `envpilot login` to authenticate."
|
|
722
|
-
);
|
|
723
|
-
}
|
|
724
|
-
function notInitialized() {
|
|
725
|
-
return new CLIError(
|
|
726
|
-
"This directory is not initialized with Envpilot.",
|
|
727
|
-
ErrorCodes.NOT_INITIALIZED,
|
|
728
|
-
"Run `envpilot init` to initialize."
|
|
729
|
-
);
|
|
730
|
-
}
|
|
731
|
-
function fileNotFound(path) {
|
|
732
|
-
return new CLIError(`File not found: ${path}`, ErrorCodes.FILE_NOT_FOUND);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
844
|
// src/commands/init.ts
|
|
736
845
|
var initCommand = new Command2("init").description("Initialize Envpilot in the current directory").option("-o, --organization <id>", "Organization ID").option("-p, --project <id>", "Project ID").option(
|
|
737
846
|
"-e, --environment <env>",
|
|
@@ -914,8 +1023,7 @@ var initCommand = new Command2("init").description("Initialize Envpilot in the c
|
|
|
914
1023
|
);
|
|
915
1024
|
console.log();
|
|
916
1025
|
} catch (err) {
|
|
917
|
-
|
|
918
|
-
process.exit(1);
|
|
1026
|
+
await handleError(err);
|
|
919
1027
|
}
|
|
920
1028
|
});
|
|
921
1029
|
|
|
@@ -1151,8 +1259,7 @@ var pullCommand = new Command3("pull").description("Download environment variabl
|
|
|
1151
1259
|
chalk5.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
|
|
1152
1260
|
);
|
|
1153
1261
|
} catch (err) {
|
|
1154
|
-
|
|
1155
|
-
process.exit(1);
|
|
1262
|
+
await handleError(err);
|
|
1156
1263
|
}
|
|
1157
1264
|
});
|
|
1158
1265
|
|
|
@@ -1400,8 +1507,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
1400
1507
|
}
|
|
1401
1508
|
}
|
|
1402
1509
|
} catch (err) {
|
|
1403
|
-
|
|
1404
|
-
process.exit(1);
|
|
1510
|
+
await handleError(err);
|
|
1405
1511
|
}
|
|
1406
1512
|
});
|
|
1407
1513
|
|
|
@@ -1655,8 +1761,7 @@ var switchCommand = new Command5("switch").description("Switch project or enviro
|
|
|
1655
1761
|
}
|
|
1656
1762
|
}
|
|
1657
1763
|
} catch (err) {
|
|
1658
|
-
|
|
1659
|
-
process.exit(1);
|
|
1764
|
+
await handleError(err);
|
|
1660
1765
|
}
|
|
1661
1766
|
});
|
|
1662
1767
|
|
|
@@ -1698,8 +1803,7 @@ var listCommand = new Command6("list").description("List resources").argument(
|
|
|
1698
1803
|
process.exit(1);
|
|
1699
1804
|
}
|
|
1700
1805
|
} catch (err) {
|
|
1701
|
-
|
|
1702
|
-
process.exit(1);
|
|
1806
|
+
await handleError(err);
|
|
1703
1807
|
}
|
|
1704
1808
|
});
|
|
1705
1809
|
async function listOrganizations(api, options) {
|
|
@@ -1901,8 +2005,7 @@ var configCommand = new Command7("config").description("Manage CLI configuration
|
|
|
1901
2005
|
process.exit(1);
|
|
1902
2006
|
}
|
|
1903
2007
|
} catch (err) {
|
|
1904
|
-
|
|
1905
|
-
process.exit(1);
|
|
2008
|
+
await handleError(err);
|
|
1906
2009
|
}
|
|
1907
2010
|
});
|
|
1908
2011
|
async function handleGet(key) {
|
|
@@ -2036,14 +2139,123 @@ var logoutCommand = new Command8("logout").description("Log out from Envpilot").
|
|
|
2036
2139
|
clearAuth();
|
|
2037
2140
|
success(`Logged out${user?.email ? ` from ${user.email}` : ""}`);
|
|
2038
2141
|
} catch (err) {
|
|
2039
|
-
|
|
2040
|
-
|
|
2142
|
+
await handleError(err);
|
|
2143
|
+
}
|
|
2144
|
+
});
|
|
2145
|
+
|
|
2146
|
+
// src/commands/usage.ts
|
|
2147
|
+
import { Command as Command9 } from "commander";
|
|
2148
|
+
import chalk10 from "chalk";
|
|
2149
|
+
function formatUsage(current, limit) {
|
|
2150
|
+
const limitStr = limit === null ? "unlimited" : String(limit);
|
|
2151
|
+
const ratio = `${current}/${limitStr}`;
|
|
2152
|
+
if (limit === null) return chalk10.green(ratio);
|
|
2153
|
+
if (current >= limit) return chalk10.red(ratio);
|
|
2154
|
+
if (current >= limit * 0.8) return chalk10.yellow(ratio);
|
|
2155
|
+
return chalk10.green(ratio);
|
|
2156
|
+
}
|
|
2157
|
+
function featureStatus(enabled) {
|
|
2158
|
+
return enabled ? chalk10.green("Enabled") : chalk10.dim("Disabled (Pro)");
|
|
2159
|
+
}
|
|
2160
|
+
var usageCommand = new Command9("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) => {
|
|
2161
|
+
try {
|
|
2162
|
+
if (!isAuthenticated()) {
|
|
2163
|
+
throw notAuthenticated();
|
|
2164
|
+
}
|
|
2165
|
+
const api = createAPIClient();
|
|
2166
|
+
const projectConfig = readProjectConfig();
|
|
2167
|
+
let organizationId = options.organization || projectConfig?.organizationId || getActiveOrganizationId();
|
|
2168
|
+
if (!organizationId) {
|
|
2169
|
+
const orgs = await withSpinner(
|
|
2170
|
+
"Fetching organizations...",
|
|
2171
|
+
async () => {
|
|
2172
|
+
const response = await api.get("/api/cli/organizations");
|
|
2173
|
+
return response.data || [];
|
|
2174
|
+
}
|
|
2175
|
+
);
|
|
2176
|
+
if (orgs.length === 0) {
|
|
2177
|
+
error("No organizations found.");
|
|
2178
|
+
process.exit(1);
|
|
2179
|
+
}
|
|
2180
|
+
if (orgs.length === 1) {
|
|
2181
|
+
organizationId = orgs[0]._id;
|
|
2182
|
+
} else {
|
|
2183
|
+
error(
|
|
2184
|
+
"Multiple organizations found. Use --organization to specify one."
|
|
2185
|
+
);
|
|
2186
|
+
console.log();
|
|
2187
|
+
for (const org of orgs) {
|
|
2188
|
+
console.log(
|
|
2189
|
+
` ${org.name} (${org.slug}): --organization ${org._id}`
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2192
|
+
process.exit(1);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
const usage = await withSpinner(
|
|
2196
|
+
"Fetching usage...",
|
|
2197
|
+
() => api.getUsage(organizationId)
|
|
2198
|
+
);
|
|
2199
|
+
if (options.json) {
|
|
2200
|
+
console.log(JSON.stringify(usage, null, 2));
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
const tierLabel = usage.tier === "pro" ? chalk10.green("Pro") : chalk10.white("Free");
|
|
2204
|
+
header(`Plan: ${tierLabel}`);
|
|
2205
|
+
blank();
|
|
2206
|
+
if (!usage.enforcementEnabled) {
|
|
2207
|
+
info("Pre-alpha mode \u2014 all limits are bypassed. Billing coming soon.");
|
|
2208
|
+
blank();
|
|
2209
|
+
}
|
|
2210
|
+
header("Resource Usage");
|
|
2211
|
+
blank();
|
|
2212
|
+
keyValue([
|
|
2213
|
+
["Projects", formatUsage(usage.usage.projects, usage.limits.projects)],
|
|
2214
|
+
[
|
|
2215
|
+
"Team Members",
|
|
2216
|
+
formatUsage(usage.usage.teamMembers, usage.limits.teamMembers)
|
|
2217
|
+
],
|
|
2218
|
+
["Pending Invitations", String(usage.usage.pendingInvitations)],
|
|
2219
|
+
["Total Variables", String(usage.usage.totalVariables)]
|
|
2220
|
+
]);
|
|
2221
|
+
blank();
|
|
2222
|
+
if (usage.usage.variablesPerProject.length > 0) {
|
|
2223
|
+
header("Variables per Project");
|
|
2224
|
+
blank();
|
|
2225
|
+
table(
|
|
2226
|
+
usage.usage.variablesPerProject.map((p) => ({
|
|
2227
|
+
project: p.projectName,
|
|
2228
|
+
variables: formatUsage(p.count, usage.limits.variablesPerProject)
|
|
2229
|
+
})),
|
|
2230
|
+
[
|
|
2231
|
+
{ key: "project", header: "Project" },
|
|
2232
|
+
{ key: "variables", header: "Variables" }
|
|
2233
|
+
]
|
|
2234
|
+
);
|
|
2235
|
+
blank();
|
|
2236
|
+
}
|
|
2237
|
+
header("Features");
|
|
2238
|
+
blank();
|
|
2239
|
+
keyValue([
|
|
2240
|
+
["Version History", featureStatus(usage.features.versionHistory)],
|
|
2241
|
+
["Bulk Import", featureStatus(usage.features.bulkImport)],
|
|
2242
|
+
[
|
|
2243
|
+
"Granular Permissions",
|
|
2244
|
+
featureStatus(usage.features.granularPermissions)
|
|
2245
|
+
],
|
|
2246
|
+
["Extension Access", featureStatus(usage.features.extensionAccess)],
|
|
2247
|
+
["Audit Log Retention", `${usage.features.auditLogRetentionDays} days`]
|
|
2248
|
+
]);
|
|
2249
|
+
blank();
|
|
2250
|
+
} catch (err) {
|
|
2251
|
+
await handleError(err);
|
|
2041
2252
|
}
|
|
2042
2253
|
});
|
|
2043
2254
|
|
|
2044
2255
|
// src/index.ts
|
|
2045
|
-
|
|
2046
|
-
program
|
|
2256
|
+
initSentry();
|
|
2257
|
+
var program = new Command10();
|
|
2258
|
+
program.name("envpilot").description("Envpilot CLI - Sync, secure, and share environment variables").version("1.3.0");
|
|
2047
2259
|
program.addCommand(loginCommand);
|
|
2048
2260
|
program.addCommand(logoutCommand);
|
|
2049
2261
|
program.addCommand(initCommand);
|
|
@@ -2052,4 +2264,5 @@ program.addCommand(pushCommand);
|
|
|
2052
2264
|
program.addCommand(switchCommand);
|
|
2053
2265
|
program.addCommand(listCommand);
|
|
2054
2266
|
program.addCommand(configCommand);
|
|
2267
|
+
program.addCommand(usageCommand);
|
|
2055
2268
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@envpilot/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Envpilot CLI — sync and manage environment variables from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"build": "tsup
|
|
16
|
-
"dev": "tsup
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"dev": "tsup --watch",
|
|
17
17
|
"lint": "eslint \"src/**/*.ts\"",
|
|
18
18
|
"typecheck": "tsc --noEmit",
|
|
19
19
|
"test": "vitest run",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"prepublishOnly": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@sentry/node": "^10.43.0",
|
|
24
25
|
"chalk": "^5.3.0",
|
|
25
26
|
"commander": "^12.1.0",
|
|
26
27
|
"conf": "^13.0.1",
|