@envpilot/cli 0.1.1 → 1.2.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/README.md +13 -13
- package/dist/index.js +152 -9
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -40,19 +40,19 @@ envpilot push
|
|
|
40
40
|
|
|
41
41
|
## Commands
|
|
42
42
|
|
|
43
|
-
| Command
|
|
44
|
-
|
|
45
|
-
| `envpilot login`
|
|
46
|
-
| `envpilot logout`
|
|
47
|
-
| `envpilot init`
|
|
48
|
-
| `envpilot pull`
|
|
49
|
-
| `envpilot push`
|
|
50
|
-
| `envpilot list orgs`
|
|
51
|
-
| `envpilot list projects`
|
|
52
|
-
| `envpilot list variables` | List variables in the active project
|
|
53
|
-
| `envpilot switch`
|
|
54
|
-
| `envpilot config`
|
|
55
|
-
| `envpilot whoami`
|
|
43
|
+
| Command | Description |
|
|
44
|
+
| ------------------------- | --------------------------------------------------- |
|
|
45
|
+
| `envpilot login` | Authenticate with your Envpilot account |
|
|
46
|
+
| `envpilot logout` | Log out and clear stored credentials |
|
|
47
|
+
| `envpilot init` | Link the current directory to an Envpilot project |
|
|
48
|
+
| `envpilot pull` | Pull environment variables into a local `.env` file |
|
|
49
|
+
| `envpilot push` | Push local `.env` changes to Envpilot |
|
|
50
|
+
| `envpilot list orgs` | List your organizations |
|
|
51
|
+
| `envpilot list projects` | List projects in the active organization |
|
|
52
|
+
| `envpilot list variables` | List variables in the active project |
|
|
53
|
+
| `envpilot switch` | Switch the active project |
|
|
54
|
+
| `envpilot config` | View or update CLI configuration |
|
|
55
|
+
| `envpilot whoami` | Show the currently authenticated user |
|
|
56
56
|
|
|
57
57
|
## Role-Based Access
|
|
58
58
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command10 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/login.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -95,6 +95,9 @@ function maskValue(value, showChars = 4) {
|
|
|
95
95
|
}
|
|
96
96
|
return value.slice(0, showChars) + "****" + value.slice(-showChars);
|
|
97
97
|
}
|
|
98
|
+
function blank() {
|
|
99
|
+
console.log();
|
|
100
|
+
}
|
|
98
101
|
function formatRole(role) {
|
|
99
102
|
switch (role) {
|
|
100
103
|
case "admin":
|
|
@@ -176,6 +179,9 @@ function setRefreshToken(token) {
|
|
|
176
179
|
function setActiveProjectId(projectId) {
|
|
177
180
|
config.set("activeProjectId", projectId);
|
|
178
181
|
}
|
|
182
|
+
function getActiveOrganizationId() {
|
|
183
|
+
return config.get("activeOrganizationId");
|
|
184
|
+
}
|
|
179
185
|
function setActiveOrganizationId(organizationId) {
|
|
180
186
|
config.set("activeOrganizationId", organizationId);
|
|
181
187
|
}
|
|
@@ -348,12 +354,19 @@ var APIClient = class {
|
|
|
348
354
|
"UNAUTHORIZED"
|
|
349
355
|
);
|
|
350
356
|
}
|
|
357
|
+
if (response.status === 403 && code === "TIER_LIMIT_REACHED") {
|
|
358
|
+
throw new APIError(
|
|
359
|
+
message || "Tier limit reached. Run `envpilot usage` to see your plan limits.",
|
|
360
|
+
403,
|
|
361
|
+
"TIER_LIMIT_REACHED"
|
|
362
|
+
);
|
|
363
|
+
}
|
|
351
364
|
if (response.status === 403) {
|
|
352
365
|
throw new APIError(message || "Access denied.", 403, code || "FORBIDDEN");
|
|
353
366
|
}
|
|
354
367
|
if (response.status === 402) {
|
|
355
368
|
throw new APIError(
|
|
356
|
-
message || "
|
|
369
|
+
message || "Tier limit reached. Run `envpilot usage` to see your plan limits.",
|
|
357
370
|
402,
|
|
358
371
|
"PAYMENT_REQUIRED"
|
|
359
372
|
);
|
|
@@ -375,6 +388,12 @@ var APIClient = class {
|
|
|
375
388
|
async getTierInfo(organizationId) {
|
|
376
389
|
return this.get("/api/cli/tier", { organizationId });
|
|
377
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Get usage info for the active organization
|
|
393
|
+
*/
|
|
394
|
+
async getUsage(organizationId) {
|
|
395
|
+
return this.get("/api/cli/usage", { organizationId });
|
|
396
|
+
}
|
|
378
397
|
/**
|
|
379
398
|
* List organizations the user has access to
|
|
380
399
|
*/
|
|
@@ -403,11 +422,14 @@ var APIClient = class {
|
|
|
403
422
|
/**
|
|
404
423
|
* List variables in a project
|
|
405
424
|
*/
|
|
406
|
-
async listVariables(projectId, environment) {
|
|
425
|
+
async listVariables(projectId, environment, organizationId) {
|
|
407
426
|
const params = { projectId };
|
|
408
427
|
if (environment) {
|
|
409
428
|
params.environment = environment;
|
|
410
429
|
}
|
|
430
|
+
if (organizationId) {
|
|
431
|
+
params.organizationId = organizationId;
|
|
432
|
+
}
|
|
411
433
|
const response = await this.get(
|
|
412
434
|
"/api/cli/variables",
|
|
413
435
|
params
|
|
@@ -1067,7 +1089,10 @@ var pullCommand = new Command3("pull").description("Download environment variabl
|
|
|
1067
1089
|
async () => {
|
|
1068
1090
|
const response = await api.get("/api/cli/variables", {
|
|
1069
1091
|
projectId: projectConfig.projectId,
|
|
1070
|
-
environment
|
|
1092
|
+
environment,
|
|
1093
|
+
...projectConfig.organizationId && {
|
|
1094
|
+
organizationId: projectConfig.organizationId
|
|
1095
|
+
}
|
|
1071
1096
|
});
|
|
1072
1097
|
metaProjectRole = response.meta?.projectRole;
|
|
1073
1098
|
return response.data || [];
|
|
@@ -1284,10 +1309,14 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
1284
1309
|
const remoteVariables = await withSpinner(
|
|
1285
1310
|
"Fetching current variables...",
|
|
1286
1311
|
async () => {
|
|
1287
|
-
const
|
|
1312
|
+
const params = {
|
|
1288
1313
|
projectId: projectConfig.projectId,
|
|
1289
1314
|
environment
|
|
1290
|
-
}
|
|
1315
|
+
};
|
|
1316
|
+
if (projectConfig.organizationId) {
|
|
1317
|
+
params.organizationId = projectConfig.organizationId;
|
|
1318
|
+
}
|
|
1319
|
+
const response = await api.get("/api/cli/variables", params);
|
|
1291
1320
|
return response.data || [];
|
|
1292
1321
|
}
|
|
1293
1322
|
);
|
|
@@ -1355,7 +1384,10 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
|
|
|
1355
1384
|
key,
|
|
1356
1385
|
value
|
|
1357
1386
|
})),
|
|
1358
|
-
mode
|
|
1387
|
+
mode,
|
|
1388
|
+
...projectConfig.organizationId && {
|
|
1389
|
+
organizationId: projectConfig.organizationId
|
|
1390
|
+
}
|
|
1359
1391
|
});
|
|
1360
1392
|
return response.data;
|
|
1361
1393
|
}
|
|
@@ -2028,9 +2060,119 @@ var logoutCommand = new Command8("logout").description("Log out from Envpilot").
|
|
|
2028
2060
|
}
|
|
2029
2061
|
});
|
|
2030
2062
|
|
|
2063
|
+
// src/commands/usage.ts
|
|
2064
|
+
import { Command as Command9 } from "commander";
|
|
2065
|
+
import chalk10 from "chalk";
|
|
2066
|
+
function formatUsage(current, limit) {
|
|
2067
|
+
const limitStr = limit === null ? "unlimited" : String(limit);
|
|
2068
|
+
const ratio = `${current}/${limitStr}`;
|
|
2069
|
+
if (limit === null) return chalk10.green(ratio);
|
|
2070
|
+
if (current >= limit) return chalk10.red(ratio);
|
|
2071
|
+
if (current >= limit * 0.8) return chalk10.yellow(ratio);
|
|
2072
|
+
return chalk10.green(ratio);
|
|
2073
|
+
}
|
|
2074
|
+
function featureStatus(enabled) {
|
|
2075
|
+
return enabled ? chalk10.green("Enabled") : chalk10.dim("Disabled (Pro)");
|
|
2076
|
+
}
|
|
2077
|
+
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) => {
|
|
2078
|
+
try {
|
|
2079
|
+
if (!isAuthenticated()) {
|
|
2080
|
+
throw notAuthenticated();
|
|
2081
|
+
}
|
|
2082
|
+
const api = createAPIClient();
|
|
2083
|
+
const projectConfig = readProjectConfig();
|
|
2084
|
+
let organizationId = options.organization || projectConfig?.organizationId || getActiveOrganizationId();
|
|
2085
|
+
if (!organizationId) {
|
|
2086
|
+
const orgs = await withSpinner(
|
|
2087
|
+
"Fetching organizations...",
|
|
2088
|
+
async () => {
|
|
2089
|
+
const response = await api.get("/api/cli/organizations");
|
|
2090
|
+
return response.data || [];
|
|
2091
|
+
}
|
|
2092
|
+
);
|
|
2093
|
+
if (orgs.length === 0) {
|
|
2094
|
+
error("No organizations found.");
|
|
2095
|
+
process.exit(1);
|
|
2096
|
+
}
|
|
2097
|
+
if (orgs.length === 1) {
|
|
2098
|
+
organizationId = orgs[0]._id;
|
|
2099
|
+
} else {
|
|
2100
|
+
error(
|
|
2101
|
+
"Multiple organizations found. Use --organization to specify one."
|
|
2102
|
+
);
|
|
2103
|
+
console.log();
|
|
2104
|
+
for (const org of orgs) {
|
|
2105
|
+
console.log(
|
|
2106
|
+
` ${org.name} (${org.slug}): --organization ${org._id}`
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
process.exit(1);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
const usage = await withSpinner(
|
|
2113
|
+
"Fetching usage...",
|
|
2114
|
+
() => api.getUsage(organizationId)
|
|
2115
|
+
);
|
|
2116
|
+
if (options.json) {
|
|
2117
|
+
console.log(JSON.stringify(usage, null, 2));
|
|
2118
|
+
return;
|
|
2119
|
+
}
|
|
2120
|
+
const tierLabel = usage.tier === "pro" ? chalk10.green("Pro") : chalk10.white("Free");
|
|
2121
|
+
header(`Plan: ${tierLabel}`);
|
|
2122
|
+
blank();
|
|
2123
|
+
if (!usage.enforcementEnabled) {
|
|
2124
|
+
info("Pre-alpha mode \u2014 all limits are bypassed. Billing coming soon.");
|
|
2125
|
+
blank();
|
|
2126
|
+
}
|
|
2127
|
+
header("Resource Usage");
|
|
2128
|
+
blank();
|
|
2129
|
+
keyValue([
|
|
2130
|
+
["Projects", formatUsage(usage.usage.projects, usage.limits.projects)],
|
|
2131
|
+
[
|
|
2132
|
+
"Team Members",
|
|
2133
|
+
formatUsage(usage.usage.teamMembers, usage.limits.teamMembers)
|
|
2134
|
+
],
|
|
2135
|
+
["Pending Invitations", String(usage.usage.pendingInvitations)],
|
|
2136
|
+
["Total Variables", String(usage.usage.totalVariables)]
|
|
2137
|
+
]);
|
|
2138
|
+
blank();
|
|
2139
|
+
if (usage.usage.variablesPerProject.length > 0) {
|
|
2140
|
+
header("Variables per Project");
|
|
2141
|
+
blank();
|
|
2142
|
+
table(
|
|
2143
|
+
usage.usage.variablesPerProject.map((p) => ({
|
|
2144
|
+
project: p.projectName,
|
|
2145
|
+
variables: formatUsage(p.count, usage.limits.variablesPerProject)
|
|
2146
|
+
})),
|
|
2147
|
+
[
|
|
2148
|
+
{ key: "project", header: "Project" },
|
|
2149
|
+
{ key: "variables", header: "Variables" }
|
|
2150
|
+
]
|
|
2151
|
+
);
|
|
2152
|
+
blank();
|
|
2153
|
+
}
|
|
2154
|
+
header("Features");
|
|
2155
|
+
blank();
|
|
2156
|
+
keyValue([
|
|
2157
|
+
["Version History", featureStatus(usage.features.versionHistory)],
|
|
2158
|
+
["Bulk Import", featureStatus(usage.features.bulkImport)],
|
|
2159
|
+
[
|
|
2160
|
+
"Granular Permissions",
|
|
2161
|
+
featureStatus(usage.features.granularPermissions)
|
|
2162
|
+
],
|
|
2163
|
+
["Extension Access", featureStatus(usage.features.extensionAccess)],
|
|
2164
|
+
["Audit Log Retention", `${usage.features.auditLogRetentionDays} days`]
|
|
2165
|
+
]);
|
|
2166
|
+
blank();
|
|
2167
|
+
} catch (err) {
|
|
2168
|
+
error(err instanceof Error ? err.message : "Failed to get usage");
|
|
2169
|
+
process.exit(1);
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2031
2173
|
// src/index.ts
|
|
2032
|
-
var program = new
|
|
2033
|
-
program.name("envpilot").description("Envpilot CLI - Sync, secure, and share environment variables").version("
|
|
2174
|
+
var program = new Command10();
|
|
2175
|
+
program.name("envpilot").description("Envpilot CLI - Sync, secure, and share environment variables").version("1.0.0");
|
|
2034
2176
|
program.addCommand(loginCommand);
|
|
2035
2177
|
program.addCommand(logoutCommand);
|
|
2036
2178
|
program.addCommand(initCommand);
|
|
@@ -2039,4 +2181,5 @@ program.addCommand(pushCommand);
|
|
|
2039
2181
|
program.addCommand(switchCommand);
|
|
2040
2182
|
program.addCommand(listCommand);
|
|
2041
2183
|
program.addCommand(configCommand);
|
|
2184
|
+
program.addCommand(usageCommand);
|
|
2042
2185
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@envpilot/cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "CLI
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Envpilot CLI — sync and manage environment variables from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"envpilot": "./dist/index.js"
|
|
@@ -51,11 +51,14 @@
|
|
|
51
51
|
"dotenv",
|
|
52
52
|
"secrets"
|
|
53
53
|
],
|
|
54
|
-
"author": "",
|
|
54
|
+
"author": "Envpilot <hello@envpilot.dev> (https://www.envpilot.dev)",
|
|
55
55
|
"license": "UNLICENSED",
|
|
56
56
|
"repository": {
|
|
57
57
|
"type": "git",
|
|
58
58
|
"url": "https://github.com/rafay99-epic/envpilot.dev"
|
|
59
59
|
},
|
|
60
|
-
"homepage": "https://www.envpilot.dev"
|
|
60
|
+
"homepage": "https://www.envpilot.dev",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/rafay99-epic/envpilot.dev/issues"
|
|
63
|
+
}
|
|
61
64
|
}
|