@envpilot/cli 1.16.0 → 1.18.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.
|
@@ -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.18.0" : "0.0.0",
|
|
11
11
|
// All EnvPilot surfaces report to one Sentry project; the surface tag
|
|
12
12
|
// is how dashboards tell web / cli / extension events apart.
|
|
13
13
|
initialScope: { tags: { surface: "cli" } },
|
|
@@ -54,16 +54,12 @@ import Conf from "conf";
|
|
|
54
54
|
|
|
55
55
|
// src/lib/roles.ts
|
|
56
56
|
var ROLE_LEVEL = {
|
|
57
|
-
owner:
|
|
58
|
-
project_manager:
|
|
59
|
-
team_lead:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
owner: "Owner",
|
|
64
|
-
project_manager: "Project Manager",
|
|
65
|
-
team_lead: "Team Lead",
|
|
66
|
-
developer: "Developer"
|
|
57
|
+
owner: 100,
|
|
58
|
+
project_manager: 80,
|
|
59
|
+
team_lead: 60,
|
|
60
|
+
editor: 50,
|
|
61
|
+
developer: 40,
|
|
62
|
+
viewer: 20
|
|
67
63
|
};
|
|
68
64
|
function normalizeOrgRole(role) {
|
|
69
65
|
switch (role) {
|
|
@@ -71,20 +67,20 @@ function normalizeOrgRole(role) {
|
|
|
71
67
|
return "owner";
|
|
72
68
|
case "member":
|
|
73
69
|
return "developer";
|
|
74
|
-
case
|
|
75
|
-
case
|
|
76
|
-
case "
|
|
77
|
-
case "developer":
|
|
78
|
-
return role;
|
|
79
|
-
default:
|
|
70
|
+
case void 0:
|
|
71
|
+
case null:
|
|
72
|
+
case "":
|
|
80
73
|
return "developer";
|
|
74
|
+
default:
|
|
75
|
+
return role;
|
|
81
76
|
}
|
|
82
77
|
}
|
|
83
78
|
function roleLevel(role) {
|
|
84
|
-
return ROLE_LEVEL[normalizeOrgRole(role)];
|
|
79
|
+
return ROLE_LEVEL[normalizeOrgRole(role)] ?? 0;
|
|
85
80
|
}
|
|
86
|
-
function formatRoleLabel(role) {
|
|
87
|
-
|
|
81
|
+
function formatRoleLabel(role, meta) {
|
|
82
|
+
if (meta?.displayName) return meta.displayName;
|
|
83
|
+
return normalizeOrgRole(role).split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
88
84
|
}
|
|
89
85
|
function isFileWritable(access) {
|
|
90
86
|
if (access.role === "owner") return true;
|
|
@@ -93,7 +89,7 @@ function isFileWritable(access) {
|
|
|
93
89
|
case "project_manager":
|
|
94
90
|
case "team_lead":
|
|
95
91
|
return true;
|
|
96
|
-
|
|
92
|
+
default:
|
|
97
93
|
return access.hasWriteAccess;
|
|
98
94
|
}
|
|
99
95
|
}
|
|
@@ -196,6 +192,14 @@ function extendCacheFreshness(projectId, environment, organizationId) {
|
|
|
196
192
|
} catch {
|
|
197
193
|
}
|
|
198
194
|
}
|
|
195
|
+
function deleteCache(projectId, environment, organizationId) {
|
|
196
|
+
try {
|
|
197
|
+
const key = getCacheKey(projectId, environment, organizationId);
|
|
198
|
+
const path = getCachePath(key);
|
|
199
|
+
if (existsSync(path)) unlinkSync(path);
|
|
200
|
+
} catch {
|
|
201
|
+
}
|
|
202
|
+
}
|
|
199
203
|
function clearAllCache() {
|
|
200
204
|
let count = 0;
|
|
201
205
|
try {
|
|
@@ -466,7 +470,7 @@ function isInteractiveTerminal() {
|
|
|
466
470
|
async function openTUI() {
|
|
467
471
|
const [{ render }, { CLIApp }, { PressAnyKey }] = await Promise.all([
|
|
468
472
|
import("ink"),
|
|
469
|
-
import("./app-
|
|
473
|
+
import("./app-JYN7XJXA.js"),
|
|
470
474
|
import("./press-any-key-64XFP4O2.js")
|
|
471
475
|
]);
|
|
472
476
|
while (true) {
|
|
@@ -614,6 +618,8 @@ function formatRole(role) {
|
|
|
614
618
|
return chalk.blue(label);
|
|
615
619
|
case "developer":
|
|
616
620
|
return chalk.yellow(label);
|
|
621
|
+
default:
|
|
622
|
+
return label;
|
|
617
623
|
}
|
|
618
624
|
}
|
|
619
625
|
function roleNotice(role) {
|
|
@@ -665,7 +671,17 @@ var ErrorCodes = {
|
|
|
665
671
|
INVALID_INPUT: "INVALID_INPUT",
|
|
666
672
|
UNKNOWN_ERROR: "UNKNOWN_ERROR"
|
|
667
673
|
};
|
|
674
|
+
var ACCESS_SUSPENDED_TOKEN = "ACCESS_SUSPENDED";
|
|
675
|
+
var ACCESS_REVOKED_MESSAGE = "Your access to this organization has been revoked. Please contact your organization administrator.";
|
|
668
676
|
function formatError(error2) {
|
|
677
|
+
const data = error2?.data;
|
|
678
|
+
const raw = [
|
|
679
|
+
error2 instanceof Error ? error2.message : error2 ? String(error2) : "",
|
|
680
|
+
typeof data === "string" ? data : ""
|
|
681
|
+
].join(" ");
|
|
682
|
+
if (raw.includes(ACCESS_SUSPENDED_TOKEN)) {
|
|
683
|
+
return chalk2.red(`Error: ${ACCESS_REVOKED_MESSAGE}`);
|
|
684
|
+
}
|
|
669
685
|
if (error2 instanceof CLIError) {
|
|
670
686
|
let message = chalk2.red(`Error: ${error2.message}`);
|
|
671
687
|
if (error2.suggestion) {
|
|
@@ -731,6 +747,26 @@ function fileNotFound(path) {
|
|
|
731
747
|
function invalidInput(message) {
|
|
732
748
|
return new CLIError(message, ErrorCodes.INVALID_INPUT);
|
|
733
749
|
}
|
|
750
|
+
function isConnectivityError(error2) {
|
|
751
|
+
const code = error2?.code ?? "";
|
|
752
|
+
if ([
|
|
753
|
+
"ECONNREFUSED",
|
|
754
|
+
"ECONNRESET",
|
|
755
|
+
"ENOTFOUND",
|
|
756
|
+
"ETIMEDOUT",
|
|
757
|
+
"EAI_AGAIN",
|
|
758
|
+
"ENETUNREACH",
|
|
759
|
+
"EHOSTUNREACH",
|
|
760
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
761
|
+
].includes(code)) {
|
|
762
|
+
return true;
|
|
763
|
+
}
|
|
764
|
+
if (error2?.status !== void 0) return false;
|
|
765
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
766
|
+
return /fetch failed|network|socket hang up|getaddrinfo|connect timeout/i.test(
|
|
767
|
+
message
|
|
768
|
+
);
|
|
769
|
+
}
|
|
734
770
|
|
|
735
771
|
// src/lib/auth-flow.ts
|
|
736
772
|
import open from "open";
|
|
@@ -1292,7 +1328,8 @@ var APIClient = class {
|
|
|
1292
1328
|
environmentScope: result.meta.environmentScope,
|
|
1293
1329
|
hasWriteAccess: result.meta.hasWriteAccess,
|
|
1294
1330
|
scopeRestricted: result.meta.scopeRestricted,
|
|
1295
|
-
decryptionFailures: result.meta.decryptionFailures
|
|
1331
|
+
decryptionFailures: result.meta.decryptionFailures,
|
|
1332
|
+
capabilities: result.meta.capabilities
|
|
1296
1333
|
};
|
|
1297
1334
|
return {
|
|
1298
1335
|
variables,
|
|
@@ -1528,7 +1565,9 @@ var projectSchema = z2.object({
|
|
|
1528
1565
|
// Unified-role fields (optional so legacy server responses still parse)
|
|
1529
1566
|
unifiedRole: z2.string().nullable().optional(),
|
|
1530
1567
|
assigned: z2.boolean().optional(),
|
|
1531
|
-
environmentScope: z2.array(z2.string()).nullable().optional()
|
|
1568
|
+
environmentScope: z2.array(z2.string()).nullable().optional(),
|
|
1569
|
+
// Resolved capability map (additive; absent on older deployments).
|
|
1570
|
+
capabilities: z2.record(z2.string(), z2.boolean()).nullable().optional()
|
|
1532
1571
|
});
|
|
1533
1572
|
var variableTagSchema = z2.object({
|
|
1534
1573
|
_id: z2.string(),
|
|
@@ -1561,7 +1600,9 @@ var variablesMetaSchema = z2.object({
|
|
|
1561
1600
|
grantOnly: z2.boolean().optional(),
|
|
1562
1601
|
environmentScope: z2.array(z2.string()).nullable().optional(),
|
|
1563
1602
|
hasWriteAccess: z2.boolean().optional(),
|
|
1564
|
-
scopeRestricted: z2.boolean().optional()
|
|
1603
|
+
scopeRestricted: z2.boolean().optional(),
|
|
1604
|
+
// Resolved capability map (additive; absent on older deployments).
|
|
1605
|
+
capabilities: z2.record(z2.string(), z2.boolean()).optional()
|
|
1565
1606
|
}).passthrough();
|
|
1566
1607
|
var environmentSchema = z2.enum([
|
|
1567
1608
|
"development",
|
|
@@ -4781,14 +4822,19 @@ var runCommand = new Command14("run").description(
|
|
|
4781
4822
|
serverFingerprint
|
|
4782
4823
|
);
|
|
4783
4824
|
}
|
|
4784
|
-
} catch {
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4825
|
+
} catch (err) {
|
|
4826
|
+
if (isConnectivityError(err)) {
|
|
4827
|
+
variables = probe.entry.variables;
|
|
4828
|
+
cacheHit = true;
|
|
4829
|
+
cacheAge = formatAge(probe.entry.fetchedAt);
|
|
4830
|
+
if (!options.quiet) {
|
|
4831
|
+
warning(
|
|
4832
|
+
`Using offline cache (age ${cacheAge}) \u2014 could not reach the server to verify freshness.`
|
|
4833
|
+
);
|
|
4834
|
+
}
|
|
4835
|
+
} else {
|
|
4836
|
+
deleteCache(project.projectId, environment, organizationId);
|
|
4837
|
+
throw err;
|
|
4792
4838
|
}
|
|
4793
4839
|
}
|
|
4794
4840
|
} else {
|
|
@@ -5113,9 +5159,17 @@ function buildCreateVariableRequestBody(input) {
|
|
|
5113
5159
|
isSensitive: input.isSensitive ?? false
|
|
5114
5160
|
};
|
|
5115
5161
|
}
|
|
5162
|
+
function canSubmitRequests(input) {
|
|
5163
|
+
if (input.capabilities) {
|
|
5164
|
+
return input.capabilities["project.requests.submit"] === true;
|
|
5165
|
+
}
|
|
5166
|
+
return normalizeOrgRole(input.role) === "developer";
|
|
5167
|
+
}
|
|
5116
5168
|
function isRequestEligibleProject(project) {
|
|
5117
|
-
|
|
5118
|
-
|
|
5169
|
+
return canSubmitRequests({
|
|
5170
|
+
capabilities: project.capabilities,
|
|
5171
|
+
role: project.unifiedRole ?? project.role
|
|
5172
|
+
}) && project.assigned === true;
|
|
5119
5173
|
}
|
|
5120
5174
|
function buildEligibleRequestTargets(projects, orgNameById) {
|
|
5121
5175
|
return projects.filter(isRequestEligibleProject).map((p) => ({
|
|
@@ -5214,8 +5268,11 @@ var requestCommand = new Command17("request").description(
|
|
|
5214
5268
|
}
|
|
5215
5269
|
if (useDefault) {
|
|
5216
5270
|
const meta = await fetchProjectMeta(api, defaultEntry);
|
|
5217
|
-
const
|
|
5218
|
-
|
|
5271
|
+
const eligible = canSubmitRequests({
|
|
5272
|
+
capabilities: meta?.capabilities,
|
|
5273
|
+
role: meta?.unifiedRole ?? meta?.role
|
|
5274
|
+
});
|
|
5275
|
+
if (!eligible) {
|
|
5219
5276
|
warning(
|
|
5220
5277
|
"You have direct write access to this project. Use `envpilot push` or create the variable directly instead of submitting a request."
|
|
5221
5278
|
);
|
|
@@ -5329,10 +5386,6 @@ var requestCommand = new Command17("request").description(
|
|
|
5329
5386
|
);
|
|
5330
5387
|
info(`Status: ${created.status} \xB7 Id: ${created._id}`);
|
|
5331
5388
|
} catch (err) {
|
|
5332
|
-
if (err instanceof APIError && err.statusCode === 403) {
|
|
5333
|
-
error(err.message);
|
|
5334
|
-
return;
|
|
5335
|
-
}
|
|
5336
5389
|
await handleError(err);
|
|
5337
5390
|
}
|
|
5338
5391
|
});
|
package/dist/index.js
CHANGED
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
initSentry,
|
|
8
8
|
isInteractiveTerminal,
|
|
9
9
|
openTUI
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DYZH5VNC.js";
|
|
11
11
|
|
|
12
12
|
// src/lib/program.ts
|
|
13
13
|
import { Command } from "commander";
|
|
14
14
|
|
|
15
15
|
// src/lib/cli-version.ts
|
|
16
|
-
var CLI_VERSION = true ? "1.
|
|
16
|
+
var CLI_VERSION = true ? "1.18.0" : "0.0.0";
|
|
17
17
|
|
|
18
18
|
// src/lib/version-check.ts
|
|
19
19
|
import chalk from "chalk";
|