@envpilot/cli 1.17.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.
@@ -4,7 +4,7 @@ import {
4
4
  getTopLevelCommandCatalog,
5
5
  getUser,
6
6
  isAuthenticated
7
- } from "./chunk-VEZRLJGM.js";
7
+ } from "./chunk-DYZH5VNC.js";
8
8
 
9
9
  // src/ui/app.tsx
10
10
  import {
@@ -7,7 +7,7 @@ function initSentry() {
7
7
  Sentry.init({
8
8
  dsn,
9
9
  environment: "cli",
10
- release: true ? "1.17.0" : "0.0.0",
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: 4,
58
- project_manager: 3,
59
- team_lead: 2,
60
- developer: 1
61
- };
62
- var ORG_ROLE_LABELS = {
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 "owner":
75
- case "project_manager":
76
- case "team_lead":
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
- return ORG_ROLE_LABELS[normalizeOrgRole(role)];
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
- case "developer":
92
+ default:
97
93
  return access.hasWriteAccess;
98
94
  }
99
95
  }
@@ -474,7 +470,7 @@ function isInteractiveTerminal() {
474
470
  async function openTUI() {
475
471
  const [{ render }, { CLIApp }, { PressAnyKey }] = await Promise.all([
476
472
  import("ink"),
477
- import("./app-7IL7GWIN.js"),
473
+ import("./app-JYN7XJXA.js"),
478
474
  import("./press-any-key-64XFP4O2.js")
479
475
  ]);
480
476
  while (true) {
@@ -622,6 +618,8 @@ function formatRole(role) {
622
618
  return chalk.blue(label);
623
619
  case "developer":
624
620
  return chalk.yellow(label);
621
+ default:
622
+ return label;
625
623
  }
626
624
  }
627
625
  function roleNotice(role) {
@@ -1330,7 +1328,8 @@ var APIClient = class {
1330
1328
  environmentScope: result.meta.environmentScope,
1331
1329
  hasWriteAccess: result.meta.hasWriteAccess,
1332
1330
  scopeRestricted: result.meta.scopeRestricted,
1333
- decryptionFailures: result.meta.decryptionFailures
1331
+ decryptionFailures: result.meta.decryptionFailures,
1332
+ capabilities: result.meta.capabilities
1334
1333
  };
1335
1334
  return {
1336
1335
  variables,
@@ -1566,7 +1565,9 @@ var projectSchema = z2.object({
1566
1565
  // Unified-role fields (optional so legacy server responses still parse)
1567
1566
  unifiedRole: z2.string().nullable().optional(),
1568
1567
  assigned: z2.boolean().optional(),
1569
- 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()
1570
1571
  });
1571
1572
  var variableTagSchema = z2.object({
1572
1573
  _id: z2.string(),
@@ -1599,7 +1600,9 @@ var variablesMetaSchema = z2.object({
1599
1600
  grantOnly: z2.boolean().optional(),
1600
1601
  environmentScope: z2.array(z2.string()).nullable().optional(),
1601
1602
  hasWriteAccess: z2.boolean().optional(),
1602
- 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()
1603
1606
  }).passthrough();
1604
1607
  var environmentSchema = z2.enum([
1605
1608
  "development",
@@ -5156,9 +5159,17 @@ function buildCreateVariableRequestBody(input) {
5156
5159
  isSensitive: input.isSensitive ?? false
5157
5160
  };
5158
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
+ }
5159
5168
  function isRequestEligibleProject(project) {
5160
- const role = normalizeOrgRole(project.unifiedRole ?? project.role);
5161
- return role === "developer" && project.assigned === true;
5169
+ return canSubmitRequests({
5170
+ capabilities: project.capabilities,
5171
+ role: project.unifiedRole ?? project.role
5172
+ }) && project.assigned === true;
5162
5173
  }
5163
5174
  function buildEligibleRequestTargets(projects, orgNameById) {
5164
5175
  return projects.filter(isRequestEligibleProject).map((p) => ({
@@ -5257,8 +5268,11 @@ var requestCommand = new Command17("request").description(
5257
5268
  }
5258
5269
  if (useDefault) {
5259
5270
  const meta = await fetchProjectMeta(api, defaultEntry);
5260
- const role = normalizeOrgRole(meta?.unifiedRole ?? meta?.role);
5261
- if (role !== "developer") {
5271
+ const eligible = canSubmitRequests({
5272
+ capabilities: meta?.capabilities,
5273
+ role: meta?.unifiedRole ?? meta?.role
5274
+ });
5275
+ if (!eligible) {
5262
5276
  warning(
5263
5277
  "You have direct write access to this project. Use `envpilot push` or create the variable directly instead of submitting a request."
5264
5278
  );
@@ -5372,10 +5386,6 @@ var requestCommand = new Command17("request").description(
5372
5386
  );
5373
5387
  info(`Status: ${created.status} \xB7 Id: ${created._id}`);
5374
5388
  } catch (err) {
5375
- if (err instanceof APIError && err.statusCode === 403) {
5376
- error(err.message);
5377
- return;
5378
- }
5379
5389
  await handleError(err);
5380
5390
  }
5381
5391
  });
package/dist/index.js CHANGED
@@ -7,13 +7,13 @@ import {
7
7
  initSentry,
8
8
  isInteractiveTerminal,
9
9
  openTUI
10
- } from "./chunk-VEZRLJGM.js";
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.17.0" : "0.0.0";
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envpilot/cli",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "Envpilot CLI — sync and manage environment variables from the terminal",
5
5
  "type": "module",
6
6
  "bin": {