@envpilot/cli 1.1.0 → 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/dist/index.js +133 -3
- package/package.json +1 -1
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
|
*/
|
|
@@ -2041,8 +2060,118 @@ var logoutCommand = new Command8("logout").description("Log out from Envpilot").
|
|
|
2041
2060
|
}
|
|
2042
2061
|
});
|
|
2043
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
|
+
|
|
2044
2173
|
// src/index.ts
|
|
2045
|
-
var program = new
|
|
2174
|
+
var program = new Command10();
|
|
2046
2175
|
program.name("envpilot").description("Envpilot CLI - Sync, secure, and share environment variables").version("1.0.0");
|
|
2047
2176
|
program.addCommand(loginCommand);
|
|
2048
2177
|
program.addCommand(logoutCommand);
|
|
@@ -2052,4 +2181,5 @@ program.addCommand(pushCommand);
|
|
|
2052
2181
|
program.addCommand(switchCommand);
|
|
2053
2182
|
program.addCommand(listCommand);
|
|
2054
2183
|
program.addCommand(configCommand);
|
|
2184
|
+
program.addCommand(usageCommand);
|
|
2055
2185
|
program.parse();
|