@envpilot/cli 1.6.0 → 1.7.2

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.6.0" : "0.0.0",
10
+ release: true ? "1.11.0" : "0.0.0",
11
11
  // Free tier: disable performance monitoring
12
12
  tracesSampleRate: 0,
13
13
  beforeSend(event) {
@@ -49,6 +49,26 @@ async function flushSentry() {
49
49
  // src/lib/config.ts
50
50
  import Conf from "conf";
51
51
  var DEFAULT_API_URL = "https://www.envpilot.dev";
52
+ var HOST_CANONICALIZATION = {
53
+ "envpilot.dev": "www.envpilot.dev"
54
+ };
55
+ function normalizeApiUrl(raw) {
56
+ let value = raw.trim();
57
+ if (!/^https?:\/\//i.test(value)) {
58
+ value = `https://${value}`;
59
+ }
60
+ try {
61
+ const parsed = new URL(value);
62
+ const canonicalHost = HOST_CANONICALIZATION[parsed.hostname.toLowerCase()];
63
+ if (canonicalHost) {
64
+ parsed.hostname = canonicalHost;
65
+ }
66
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "");
67
+ return parsed.toString().replace(/\/$/, "");
68
+ } catch {
69
+ return value;
70
+ }
71
+ }
52
72
  var config = new Conf({
53
73
  projectName: "envpilot",
54
74
  defaults: {
@@ -57,7 +77,7 @@ var config = new Conf({
57
77
  });
58
78
  function getConfig() {
59
79
  return {
60
- apiUrl: config.get("apiUrl") ?? DEFAULT_API_URL,
80
+ apiUrl: normalizeApiUrl(config.get("apiUrl") ?? DEFAULT_API_URL),
61
81
  accessToken: config.get("accessToken"),
62
82
  refreshToken: config.get("refreshToken"),
63
83
  activeProjectId: config.get("activeProjectId"),
@@ -67,10 +87,12 @@ function getConfig() {
67
87
  };
68
88
  }
69
89
  function getApiUrl() {
70
- return config.get("apiUrl") ?? DEFAULT_API_URL;
90
+ const stored = config.get("apiUrl");
91
+ const raw = stored ?? DEFAULT_API_URL;
92
+ return normalizeApiUrl(raw);
71
93
  }
72
94
  function setApiUrl(url) {
73
- config.set("apiUrl", url);
95
+ config.set("apiUrl", normalizeApiUrl(url));
74
96
  }
75
97
  function getAccessToken() {
76
98
  return config.get("accessToken");
@@ -121,9 +143,6 @@ function getConfigPath() {
121
143
  return config.path;
122
144
  }
123
145
 
124
- // src/ui/render-tui.tsx
125
- import chalk from "chalk";
126
-
127
146
  // src/ui/execute-command.ts
128
147
  import { spawn } from "child_process";
129
148
  import { dirname, resolve } from "path";
@@ -155,9 +174,10 @@ async function executeCommand(argv) {
155
174
  // src/ui/render-tui.tsx
156
175
  import { jsx } from "react/jsx-runtime";
157
176
  async function openTUI() {
158
- const [{ render }, { CLIApp }] = await Promise.all([
177
+ const [{ render }, { CLIApp }, { PressAnyKey }] = await Promise.all([
159
178
  import("ink"),
160
- import("./app-UJRUWQKL.js")
179
+ import("./app-QG4JFCWP.js"),
180
+ import("./press-any-key-64XFP4O2.js")
161
181
  ]);
162
182
  while (true) {
163
183
  let selectedArgv = null;
@@ -179,24 +199,18 @@ async function openTUI() {
179
199
  if (code !== 0) {
180
200
  process.exitCode = code;
181
201
  }
182
- console.log();
183
- console.log(
184
- chalk.dim(" Press any key to return to the TUI\u2026 (q to quit)")
185
- );
186
- const quit = await new Promise((resolve3) => {
187
- if (process.stdin.isTTY) {
188
- process.stdin.setRawMode(true);
189
- }
190
- process.stdin.resume();
191
- process.stdin.once("data", (data) => {
192
- const ch = data.toString();
193
- if (process.stdin.isTTY) {
194
- process.stdin.setRawMode(false);
202
+ let quit = false;
203
+ const prompt = render(
204
+ /* @__PURE__ */ jsx(
205
+ PressAnyKey,
206
+ {
207
+ onResolve: (q) => {
208
+ quit = q;
209
+ }
195
210
  }
196
- process.stdin.pause();
197
- resolve3(ch === "q" || ch === "Q");
198
- });
199
- });
211
+ )
212
+ );
213
+ await prompt.waitUntilExit();
200
214
  if (quit) {
201
215
  break;
202
216
  }
@@ -207,7 +221,7 @@ async function openTUI() {
207
221
  import { Command } from "commander";
208
222
 
209
223
  // src/lib/ui.ts
210
- import chalk2 from "chalk";
224
+ import chalk from "chalk";
211
225
  import ora from "ora";
212
226
  function createSpinner(text) {
213
227
  return ora({
@@ -228,25 +242,25 @@ async function withSpinner(text, operation, options) {
228
242
  }
229
243
  }
230
244
  function success(message) {
231
- console.log(chalk2.green("\u2713"), message);
245
+ console.log(chalk.green("\u2713"), message);
232
246
  }
233
247
  function info(message) {
234
- console.log(chalk2.blue("\u2139"), message);
248
+ console.log(chalk.blue("\u2139"), message);
235
249
  }
236
250
  function warning(message) {
237
- console.log(chalk2.yellow("\u26A0"), message);
251
+ console.log(chalk.yellow("\u26A0"), message);
238
252
  }
239
253
  function error(message) {
240
- console.log(chalk2.red("\u2717"), message);
254
+ console.log(chalk.red("\u2717"), message);
241
255
  }
242
256
  function header(text) {
243
257
  console.log();
244
- console.log(chalk2.bold(text));
245
- console.log(chalk2.dim("\u2500".repeat(text.length)));
258
+ console.log(chalk.bold(text));
259
+ console.log(chalk.dim("\u2500".repeat(text.length)));
246
260
  }
247
261
  function table(data, columns) {
248
262
  if (data.length === 0) {
249
- console.log(chalk2.dim("No data to display"));
263
+ console.log(chalk.dim("No data to display"));
250
264
  return;
251
265
  }
252
266
  const widths = columns.map((col) => {
@@ -257,8 +271,8 @@ function table(data, columns) {
257
271
  return col.width ?? Math.max(headerWidth, maxDataWidth);
258
272
  });
259
273
  const headerLine = columns.map((col, i) => col.header.padEnd(widths[i])).join(" ");
260
- console.log(chalk2.bold(headerLine));
261
- console.log(chalk2.dim("\u2500".repeat(headerLine.length)));
274
+ console.log(chalk.bold(headerLine));
275
+ console.log(chalk.dim("\u2500".repeat(headerLine.length)));
262
276
  for (const row of data) {
263
277
  const line2 = columns.map((col, i) => String(row[col.key] ?? "").padEnd(widths[i])).join(" ");
264
278
  console.log(line2);
@@ -268,23 +282,23 @@ function keyValue(pairs) {
268
282
  const maxKeyLength = Math.max(...pairs.map(([key]) => key.length));
269
283
  for (const [key, value] of pairs) {
270
284
  const paddedKey = key.padEnd(maxKeyLength);
271
- console.log(`${chalk2.dim(paddedKey)} ${value ?? chalk2.dim("(not set)")}`);
285
+ console.log(`${chalk.dim(paddedKey)} ${value ?? chalk.dim("(not set)")}`);
272
286
  }
273
287
  }
274
288
  function diff(added, removed, changed) {
275
289
  if (Object.keys(added).length === 0 && Object.keys(removed).length === 0 && Object.keys(changed).length === 0) {
276
- console.log(chalk2.dim("No changes"));
290
+ console.log(chalk.dim("No changes"));
277
291
  return;
278
292
  }
279
293
  for (const [key, value] of Object.entries(added)) {
280
- console.log(chalk2.green(`+ ${key}=${maskValue(value)}`));
294
+ console.log(chalk.green(`+ ${key}=${maskValue(value)}`));
281
295
  }
282
296
  for (const [key, value] of Object.entries(removed)) {
283
- console.log(chalk2.red(`- ${key}=${maskValue(value)}`));
297
+ console.log(chalk.red(`- ${key}=${maskValue(value)}`));
284
298
  }
285
299
  for (const [key, { local, remote }] of Object.entries(changed)) {
286
- console.log(chalk2.red(`- ${key}=${maskValue(remote)}`));
287
- console.log(chalk2.green(`+ ${key}=${maskValue(local)}`));
300
+ console.log(chalk.red(`- ${key}=${maskValue(remote)}`));
301
+ console.log(chalk.green(`+ ${key}=${maskValue(local)}`));
288
302
  }
289
303
  }
290
304
  function maskValue(value, showChars = 4) {
@@ -294,7 +308,7 @@ function maskValue(value, showChars = 4) {
294
308
  return value.slice(0, showChars) + "****" + value.slice(-showChars);
295
309
  }
296
310
  function line() {
297
- console.log(chalk2.dim("\u2500".repeat(50)));
311
+ console.log(chalk.dim("\u2500".repeat(50)));
298
312
  }
299
313
  function blank() {
300
314
  console.log();
@@ -302,19 +316,19 @@ function blank() {
302
316
  function formatRole(role) {
303
317
  switch (role) {
304
318
  case "admin":
305
- return chalk2.green("Admin");
319
+ return chalk.green("Admin");
306
320
  case "team_lead":
307
- return chalk2.blue("Team Lead");
321
+ return chalk.blue("Team Lead");
308
322
  case "member":
309
- return chalk2.yellow("Member");
323
+ return chalk.yellow("Member");
310
324
  default:
311
- return chalk2.dim("Unknown");
325
+ return chalk.dim("Unknown");
312
326
  }
313
327
  }
314
328
  function roleNotice(role) {
315
329
  if (role === "member") {
316
330
  console.log(
317
- chalk2.yellow(
331
+ chalk.yellow(
318
332
  " You have Member access. Write operations will create pending requests for approval."
319
333
  )
320
334
  );
@@ -323,19 +337,19 @@ function roleNotice(role) {
323
337
  function formatProjectRole(role) {
324
338
  switch (role) {
325
339
  case "manager":
326
- return chalk2.green("Manager");
340
+ return chalk.green("Manager");
327
341
  case "developer":
328
- return chalk2.blue("Developer");
342
+ return chalk.blue("Developer");
329
343
  case "viewer":
330
- return chalk2.yellow("Viewer");
344
+ return chalk.yellow("Viewer");
331
345
  default:
332
- return chalk2.dim("-");
346
+ return chalk.dim("-");
333
347
  }
334
348
  }
335
349
  function projectRoleNotice(projectRole) {
336
350
  if (projectRole === "viewer") {
337
351
  console.log(
338
- chalk2.yellow(
352
+ chalk.yellow(
339
353
  " You have Viewer access to this project. You can only view variables you have been explicitly granted access to."
340
354
  )
341
355
  );
@@ -343,7 +357,7 @@ function projectRoleNotice(projectRole) {
343
357
  }
344
358
 
345
359
  // src/lib/errors.ts
346
- import chalk3 from "chalk";
360
+ import chalk2 from "chalk";
347
361
  var CLIError = class extends Error {
348
362
  constructor(message, code, suggestion) {
349
363
  super(message);
@@ -368,17 +382,17 @@ var ErrorCodes = {
368
382
  };
369
383
  function formatError(error2) {
370
384
  if (error2 instanceof CLIError) {
371
- let message = chalk3.red(`Error: ${error2.message}`);
385
+ let message = chalk2.red(`Error: ${error2.message}`);
372
386
  if (error2.suggestion) {
373
387
  message += `
374
- ${chalk3.yellow("Suggestion:")} ${error2.suggestion}`;
388
+ ${chalk2.yellow("Suggestion:")} ${error2.suggestion}`;
375
389
  }
376
390
  return message;
377
391
  }
378
392
  if (error2 instanceof Error) {
379
- return chalk3.red(`Error: ${error2.message}`);
393
+ return chalk2.red(`Error: ${error2.message}`);
380
394
  }
381
- return chalk3.red(`Error: ${String(error2)}`);
395
+ return chalk2.red(`Error: ${String(error2)}`);
382
396
  }
383
397
  async function handleError(error2) {
384
398
  console.error(formatError(error2));
@@ -435,10 +449,16 @@ function invalidInput(message) {
435
449
 
436
450
  // src/lib/auth-flow.ts
437
451
  import open from "open";
438
- import chalk4 from "chalk";
452
+ import chalk3 from "chalk";
439
453
  import { hostname } from "os";
440
454
 
441
455
  // src/lib/api.ts
456
+ function registrableDomain(hostname2) {
457
+ const parts = hostname2.toLowerCase().split(".").filter(Boolean);
458
+ if (parts.length <= 2) return parts.join(".");
459
+ return parts.slice(-2).join(".");
460
+ }
461
+ var MAX_MANUAL_REDIRECTS = 5;
442
462
  var APIError = class extends Error {
443
463
  constructor(message, statusCode, code) {
444
464
  super(message);
@@ -474,7 +494,59 @@ var APIClient = class {
474
494
  const finalUrl = response.url || "";
475
495
  const contentType = response.headers.get("content-type") || "";
476
496
  const preview = (bodyText || "").slice(0, 512).toLowerCase();
477
- return response.redirected || location.includes("authkit") || finalUrl.includes("authkit") || contentType.includes("text/html") && (preview.includes("authorization_session_id") || preview.includes("client_id=") || preview.includes("<!doctype html"));
497
+ return location.includes("authkit") || finalUrl.includes("authkit") || contentType.includes("text/html") && (preview.includes("authorization_session_id") || preview.includes("client_id=") || preview.includes("<!doctype html"));
498
+ }
499
+ /**
500
+ * Perform a fetch that follows 3xx redirects manually, re-attaching the
501
+ * Authorization header when the redirect stays inside the same registrable
502
+ * domain (eTLD+1). This defends against the apex→www redirect case where
503
+ * Node's default redirect follower drops the Authorization header on any
504
+ * hostname change and the resulting request comes back as a bogus 401 —
505
+ * which used to wipe the user's credentials.
506
+ *
507
+ * Cross-site redirects (different registrable domain) are followed without
508
+ * the Authorization header, matching browser/fetch security semantics.
509
+ */
510
+ async fetchWithSafeRedirects(initialUrl, init2) {
511
+ let currentUrl = initialUrl;
512
+ let currentInit = { ...init2, redirect: "manual" };
513
+ for (let hop = 0; hop < MAX_MANUAL_REDIRECTS; hop++) {
514
+ const response = await fetch(currentUrl, currentInit);
515
+ if (response.status < 300 || response.status >= 400) {
516
+ return response;
517
+ }
518
+ const location = response.headers.get("location");
519
+ if (!location) return response;
520
+ const nextUrl = new URL(location, currentUrl);
521
+ const prevHost = new URL(currentUrl).hostname;
522
+ const sameSite = registrableDomain(nextUrl.hostname) === registrableDomain(prevHost);
523
+ const headers = new Headers(currentInit.headers);
524
+ if (!sameSite) {
525
+ headers.delete("Authorization");
526
+ }
527
+ let nextMethod = (currentInit.method || "GET").toUpperCase();
528
+ let nextBody = currentInit.body;
529
+ if (response.status === 301 || response.status === 302 || response.status === 303) {
530
+ if (nextMethod !== "GET" && nextMethod !== "HEAD") {
531
+ nextMethod = "GET";
532
+ nextBody = void 0;
533
+ headers.delete("Content-Type");
534
+ }
535
+ }
536
+ currentUrl = nextUrl.toString();
537
+ currentInit = {
538
+ ...currentInit,
539
+ method: nextMethod,
540
+ headers,
541
+ body: nextBody,
542
+ redirect: "manual"
543
+ };
544
+ }
545
+ throw new APIError(
546
+ `Too many redirects while calling ${initialUrl}`,
547
+ 0,
548
+ "TOO_MANY_REDIRECTS"
549
+ );
478
550
  }
479
551
  /**
480
552
  * Make a GET request
@@ -486,10 +558,9 @@ var APIClient = class {
486
558
  url.searchParams.set(key, value);
487
559
  }
488
560
  }
489
- const response = await fetch(url.toString(), {
561
+ const response = await this.fetchWithSafeRedirects(url.toString(), {
490
562
  method: "GET",
491
- headers: this.getHeaders(),
492
- redirect: "follow"
563
+ headers: this.getHeaders()
493
564
  });
494
565
  return this.handleResponse(response);
495
566
  }
@@ -498,11 +569,10 @@ var APIClient = class {
498
569
  */
499
570
  async post(path, body) {
500
571
  const url = new URL(path, this.baseUrl);
501
- const response = await fetch(url.toString(), {
572
+ const response = await this.fetchWithSafeRedirects(url.toString(), {
502
573
  method: "POST",
503
574
  headers: this.getHeaders(),
504
- body: body ? JSON.stringify(body) : void 0,
505
- redirect: "follow"
575
+ body: body ? JSON.stringify(body) : void 0
506
576
  });
507
577
  return this.handleResponse(response);
508
578
  }
@@ -511,11 +581,10 @@ var APIClient = class {
511
581
  */
512
582
  async put(path, body) {
513
583
  const url = new URL(path, this.baseUrl);
514
- const response = await fetch(url.toString(), {
584
+ const response = await this.fetchWithSafeRedirects(url.toString(), {
515
585
  method: "PUT",
516
586
  headers: this.getHeaders(),
517
- body: body ? JSON.stringify(body) : void 0,
518
- redirect: "follow"
587
+ body: body ? JSON.stringify(body) : void 0
519
588
  });
520
589
  return this.handleResponse(response);
521
590
  }
@@ -524,11 +593,10 @@ var APIClient = class {
524
593
  */
525
594
  async patch(path, body) {
526
595
  const url = new URL(path, this.baseUrl);
527
- const response = await fetch(url.toString(), {
596
+ const response = await this.fetchWithSafeRedirects(url.toString(), {
528
597
  method: "PATCH",
529
598
  headers: this.getHeaders(),
530
- body: body ? JSON.stringify(body) : void 0,
531
- redirect: "follow"
599
+ body: body ? JSON.stringify(body) : void 0
532
600
  });
533
601
  return this.handleResponse(response);
534
602
  }
@@ -537,10 +605,9 @@ var APIClient = class {
537
605
  */
538
606
  async delete(path) {
539
607
  const url = new URL(path, this.baseUrl);
540
- const response = await fetch(url.toString(), {
608
+ const response = await this.fetchWithSafeRedirects(url.toString(), {
541
609
  method: "DELETE",
542
- headers: this.getHeaders(),
543
- redirect: "follow"
610
+ headers: this.getHeaders()
544
611
  });
545
612
  if (!response.ok) {
546
613
  await this.handleError(response);
@@ -557,7 +624,6 @@ var APIClient = class {
557
624
  if (!contentType.includes("application/json")) {
558
625
  const body2 = await response.text();
559
626
  if (this.isAuthRedirect(response, body2)) {
560
- clearAuth();
561
627
  throw new APIError(
562
628
  "Your CLI session is not authorized for this endpoint. Please run `envpilot login` and try again.",
563
629
  401,
@@ -594,20 +660,12 @@ var APIClient = class {
594
660
  code = data.code;
595
661
  } catch {
596
662
  }
597
- if (response.status >= 300 && response.status < 400 && this.isAuthRedirect(response)) {
598
- clearAuth();
599
- throw new APIError(
600
- "Your CLI session expired or the server redirected this request to browser sign-in. Please run `envpilot login`.",
601
- 401,
602
- "AUTH_REDIRECT"
603
- );
604
- }
605
663
  if (response.status === 401) {
606
664
  clearAuth();
607
665
  throw new APIError(
608
- "Authentication required. Please run `envpilot login`.",
666
+ "Authentication failed. Please run `envpilot login`.",
609
667
  401,
610
- "UNAUTHORIZED"
668
+ code || "UNAUTHORIZED"
611
669
  );
612
670
  }
613
671
  if (response.status === 403 && code === "TIER_LIMIT_REACHED") {
@@ -636,7 +694,7 @@ var APIClient = class {
636
694
  * Get current user info
637
695
  */
638
696
  async getCurrentUser() {
639
- return this.get("/api/cli/auth/me");
697
+ return this.get("/api/cli/auth", { action: "me" });
640
698
  }
641
699
  /**
642
700
  * Get tier info for the active organization
@@ -752,25 +810,25 @@ var APIClient = class {
752
810
  * Initiate CLI authentication flow
753
811
  */
754
812
  async initiateAuth(deviceName) {
755
- return this.post("/api/cli/auth/initiate", { deviceName });
813
+ return this.post("/api/cli/auth?action=initiate", { deviceName });
756
814
  }
757
815
  /**
758
816
  * Poll for authentication status
759
817
  */
760
818
  async pollAuth(code) {
761
- return this.get("/api/cli/auth/poll", { code });
819
+ return this.get("/api/cli/auth", { action: "poll", code });
762
820
  }
763
821
  /**
764
822
  * Refresh access token
765
823
  */
766
824
  async refreshToken(refreshToken) {
767
- return this.post("/api/cli/auth/refresh", { refreshToken });
825
+ return this.post("/api/cli/auth?action=refresh", { refreshToken });
768
826
  }
769
827
  /**
770
828
  * Revoke access token (logout)
771
829
  */
772
830
  async revokeToken() {
773
- return this.post("/api/cli/auth/revoke", {});
831
+ return this.post("/api/cli/auth?action=revoke", {});
774
832
  }
775
833
  };
776
834
  function createAPIClient() {
@@ -792,19 +850,19 @@ async function performLogin(options) {
792
850
  spinner.start();
793
851
  let initResponse;
794
852
  try {
795
- initResponse = await api.post("/api/cli/auth?action=initiate", { deviceName });
853
+ initResponse = await api.initiateAuth(deviceName);
796
854
  } catch (error2) {
797
855
  spinner.stop();
798
856
  throw error2;
799
857
  }
800
858
  spinner.stop();
801
859
  console.log();
802
- console.log(chalk4.bold("Your authentication code:"));
860
+ console.log(chalk3.bold("Your authentication code:"));
803
861
  console.log();
804
- console.log(chalk4.cyan.bold(` ${initResponse.code}`));
862
+ console.log(chalk3.cyan.bold(` ${initResponse.code}`));
805
863
  console.log();
806
864
  console.log(`Open this URL to authenticate:`);
807
- console.log(chalk4.dim(initResponse.url));
865
+ console.log(chalk3.dim(initResponse.url));
808
866
  console.log();
809
867
  if (options?.browser !== false) {
810
868
  info("Opening browser...");
@@ -818,10 +876,7 @@ async function performLogin(options) {
818
876
  await sleep(POLL_INTERVAL_MS);
819
877
  let pollResponse;
820
878
  try {
821
- pollResponse = await api.get("/api/cli/auth", {
822
- action: "poll",
823
- code: initResponse.code
824
- });
879
+ pollResponse = await api.pollAuth(initResponse.code);
825
880
  consecutiveErrors = 0;
826
881
  } catch {
827
882
  consecutiveErrors++;
@@ -834,12 +889,13 @@ async function performLogin(options) {
834
889
  }
835
890
  if (pollResponse.status === "authenticated") {
836
891
  pollSpinner.stop();
837
- if (pollResponse.accessToken) {
838
- setAccessToken(pollResponse.accessToken);
839
- }
840
- if (pollResponse.refreshToken) {
841
- setRefreshToken(pollResponse.refreshToken);
892
+ if (!pollResponse.accessToken || !pollResponse.refreshToken) {
893
+ throw new Error(
894
+ "Authentication succeeded but the server did not return session tokens. This is likely a server-side issue. Please try again or contact support."
895
+ );
842
896
  }
897
+ setAccessToken(pollResponse.accessToken);
898
+ setRefreshToken(pollResponse.refreshToken);
843
899
  if (pollResponse.user) {
844
900
  setUser({
845
901
  id: pollResponse.user.id,
@@ -848,7 +904,7 @@ async function performLogin(options) {
848
904
  });
849
905
  }
850
906
  console.log();
851
- success(`Logged in as ${chalk4.bold(pollResponse.user?.email)}`);
907
+ success(`Logged in as ${chalk3.bold(pollResponse.user?.email)}`);
852
908
  return { email: pollResponse.user?.email || "" };
853
909
  }
854
910
  if (pollResponse.status === "expired" || pollResponse.status === "not_found") {
@@ -862,7 +918,7 @@ async function performLogin(options) {
862
918
  }
863
919
 
864
920
  // src/commands/login.ts
865
- var loginCommand = new Command("login").description("Authenticate with Envpilot").option("--api-url <url>", "API URL (default: http://localhost:3000)").option("--no-browser", "Do not automatically open the browser").action(async (options) => {
921
+ var loginCommand = new Command("login").description("Authenticate with Envpilot").option("--api-url <url>", "API URL (default: https://www.envpilot.dev)").option("--no-browser", "Do not automatically open the browser").action(async (options) => {
866
922
  try {
867
923
  if (options.apiUrl) {
868
924
  setApiUrl(options.apiUrl);
@@ -883,7 +939,7 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
883
939
 
884
940
  // src/commands/init.ts
885
941
  import { Command as Command2 } from "commander";
886
- import chalk5 from "chalk";
942
+ import chalk4 from "chalk";
887
943
  import inquirer from "inquirer";
888
944
 
889
945
  // src/lib/project-config.ts
@@ -1388,18 +1444,18 @@ async function addProject(existingConfig, options) {
1388
1444
  console.log();
1389
1445
  success(`Added "${selectedProject.name}" to linked projects!`);
1390
1446
  console.log(
1391
- chalk5.dim(` ${existingConfig.projects.length + 1} projects now linked`)
1447
+ chalk4.dim(` ${existingConfig.projects.length + 1} projects now linked`)
1392
1448
  );
1393
1449
  console.log();
1394
1450
  console.log("Next steps:");
1395
1451
  console.log(
1396
- ` ${chalk5.cyan("envpilot pull --all")} Pull all projects`
1452
+ ` ${chalk4.cyan("envpilot pull --all")} Pull all projects`
1397
1453
  );
1398
1454
  console.log(
1399
- ` ${chalk5.cyan(`envpilot pull --project "${selectedProject.name}"`)} Pull this project`
1455
+ ` ${chalk4.cyan(`envpilot pull --project "${selectedProject.name}"`)} Pull this project`
1400
1456
  );
1401
1457
  console.log(
1402
- ` ${chalk5.cyan("envpilot list linked")} See all linked projects`
1458
+ ` ${chalk4.cyan("envpilot list linked")} See all linked projects`
1403
1459
  );
1404
1460
  console.log();
1405
1461
  }
@@ -1428,7 +1484,7 @@ async function selectOrgProjectEnv(options) {
1428
1484
  selectedOrg = org;
1429
1485
  } else if (organizations.length === 1) {
1430
1486
  selectedOrg = organizations[0];
1431
- info(`Using organization: ${chalk5.bold(selectedOrg.name)}`);
1487
+ info(`Using organization: ${chalk4.bold(selectedOrg.name)}`);
1432
1488
  } else {
1433
1489
  const { orgId } = await inquirer.prompt([
1434
1490
  {
@@ -1436,7 +1492,7 @@ async function selectOrgProjectEnv(options) {
1436
1492
  name: "orgId",
1437
1493
  message: "Select an organization:",
1438
1494
  choices: organizations.map((org) => ({
1439
- name: `${org.name} ${org.tier === "pro" ? chalk5.green("(Pro)") : chalk5.dim("(Free)")}`,
1495
+ name: `${org.name} ${org.tier === "pro" ? chalk4.green("(Pro)") : chalk4.dim("(Free)")}`,
1440
1496
  value: org._id
1441
1497
  }))
1442
1498
  }
@@ -1466,7 +1522,7 @@ async function selectOrgProjectEnv(options) {
1466
1522
  selectedProject = project;
1467
1523
  } else if (projects.length === 1) {
1468
1524
  selectedProject = projects[0];
1469
- info(`Using project: ${chalk5.bold(selectedProject.name)}`);
1525
+ info(`Using project: ${chalk4.bold(selectedProject.name)}`);
1470
1526
  } else {
1471
1527
  const { projectId } = await inquirer.prompt([
1472
1528
  {
@@ -1517,29 +1573,29 @@ function warnTrackedFiles() {
1517
1573
  console.log();
1518
1574
  warning("Security risk: .env files are tracked by git!");
1519
1575
  for (const file of trackedFiles) {
1520
- console.log(chalk5.red(` tracked: ${file}`));
1576
+ console.log(chalk4.red(` tracked: ${file}`));
1521
1577
  }
1522
1578
  console.log();
1523
1579
  console.log(
1524
- chalk5.yellow(
1580
+ chalk4.yellow(
1525
1581
  " Run the following to untrack them (without deleting the files):"
1526
1582
  )
1527
1583
  );
1528
1584
  for (const file of trackedFiles) {
1529
- console.log(chalk5.cyan(` git rm --cached ${file}`));
1585
+ console.log(chalk4.cyan(` git rm --cached ${file}`));
1530
1586
  }
1531
1587
  }
1532
1588
  }
1533
1589
  function printPostInit(selectedOrg, selectedProject) {
1534
1590
  console.log();
1535
- console.log(chalk5.dim("Configuration saved to .envpilot"));
1591
+ console.log(chalk4.dim("Configuration saved to .envpilot"));
1536
1592
  if (selectedOrg.role) {
1537
- console.log(chalk5.dim(` Org role: ${formatRole(selectedOrg.role)}`));
1593
+ console.log(chalk4.dim(` Org role: ${formatRole(selectedOrg.role)}`));
1538
1594
  roleNotice(selectedOrg.role);
1539
1595
  }
1540
1596
  if (selectedProject.projectRole) {
1541
1597
  console.log(
1542
- chalk5.dim(
1598
+ chalk4.dim(
1543
1599
  ` Project role: ${formatProjectRole(selectedProject.projectRole)}`
1544
1600
  )
1545
1601
  );
@@ -1548,17 +1604,17 @@ function printPostInit(selectedOrg, selectedProject) {
1548
1604
  console.log();
1549
1605
  console.log("Next steps:");
1550
1606
  console.log(
1551
- ` ${chalk5.cyan("envpilot pull")} Download environment variables`
1607
+ ` ${chalk4.cyan("envpilot pull")} Download environment variables`
1552
1608
  );
1553
1609
  console.log(
1554
- ` ${chalk5.cyan("envpilot push")} Upload local .env to cloud`
1610
+ ` ${chalk4.cyan("envpilot push")} Upload local .env to cloud`
1555
1611
  );
1556
1612
  console.log();
1557
1613
  }
1558
1614
 
1559
1615
  // src/commands/pull.ts
1560
1616
  import { Command as Command3 } from "commander";
1561
- import chalk6 from "chalk";
1617
+ import chalk5 from "chalk";
1562
1618
  import inquirer2 from "inquirer";
1563
1619
 
1564
1620
  // src/lib/format-converter.ts
@@ -1972,7 +2028,7 @@ async function pullAllProjects(options) {
1972
2028
  const displayName = project.projectName || project.projectId;
1973
2029
  console.log();
1974
2030
  console.log(
1975
- chalk6.bold(
2031
+ chalk5.bold(
1976
2032
  `Pulling "${displayName}" (${project.environment}) \u2192 ${outputPath}`
1977
2033
  )
1978
2034
  );
@@ -2022,7 +2078,7 @@ async function pullProject(project, outputPath, options) {
2022
2078
  const api = createAPIClient();
2023
2079
  let metaProjectRole;
2024
2080
  const variables = await withSpinner(
2025
- `Fetching ${chalk6.bold(project.environment)} variables...`,
2081
+ `Fetching ${chalk5.bold(project.environment)} variables...`,
2026
2082
  async () => {
2027
2083
  const response = await api.get("/api/cli/variables", {
2028
2084
  projectId: project.projectId,
@@ -2051,7 +2107,7 @@ async function pullProject(project, outputPath, options) {
2051
2107
  return;
2052
2108
  }
2053
2109
  console.log();
2054
- console.log(chalk6.bold("Changes:"));
2110
+ console.log(chalk5.bold("Changes:"));
2055
2111
  console.log();
2056
2112
  diff(diffResult.added, diffResult.removed, diffResult.changed);
2057
2113
  console.log();
@@ -2101,7 +2157,7 @@ async function pullProject(project, outputPath, options) {
2101
2157
  const role = getRole();
2102
2158
  applyFileProtection(outputPath, role, metaProjectRole);
2103
2159
  success(
2104
- `Downloaded ${variables.length} variables to ${chalk6.bold(outputPath)}`
2160
+ `Downloaded ${variables.length} variables to ${chalk5.bold(outputPath)}`
2105
2161
  );
2106
2162
  if (metaProjectRole === "viewer") {
2107
2163
  info(
@@ -2115,12 +2171,12 @@ async function pullProject(project, outputPath, options) {
2115
2171
  );
2116
2172
  }
2117
2173
  console.log();
2118
- console.log(chalk6.dim(` Added: ${Object.keys(diffResult.added).length}`));
2174
+ console.log(chalk5.dim(` Added: ${Object.keys(diffResult.added).length}`));
2119
2175
  console.log(
2120
- chalk6.dim(` Changed: ${Object.keys(diffResult.changed).length}`)
2176
+ chalk5.dim(` Changed: ${Object.keys(diffResult.changed).length}`)
2121
2177
  );
2122
2178
  console.log(
2123
- chalk6.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
2179
+ chalk5.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
2124
2180
  );
2125
2181
  }
2126
2182
  function checkTrackedFiles() {
@@ -2129,16 +2185,16 @@ function checkTrackedFiles() {
2129
2185
  error("Security risk: .env files are tracked by git!");
2130
2186
  console.log();
2131
2187
  for (const file of trackedFiles) {
2132
- console.log(chalk6.red(` tracked: ${file}`));
2188
+ console.log(chalk5.red(` tracked: ${file}`));
2133
2189
  }
2134
2190
  console.log();
2135
2191
  console.log(
2136
- chalk6.yellow(
2192
+ chalk5.yellow(
2137
2193
  " Run the following to untrack them (without deleting the files):"
2138
2194
  )
2139
2195
  );
2140
2196
  for (const file of trackedFiles) {
2141
- console.log(chalk6.cyan(` git rm --cached ${file}`));
2197
+ console.log(chalk5.cyan(` git rm --cached ${file}`));
2142
2198
  }
2143
2199
  console.log();
2144
2200
  process.exit(1);
@@ -2147,7 +2203,7 @@ function checkTrackedFiles() {
2147
2203
 
2148
2204
  // src/commands/push.ts
2149
2205
  import { Command as Command4 } from "commander";
2150
- import chalk7 from "chalk";
2206
+ import chalk6 from "chalk";
2151
2207
  import inquirer3 from "inquirer";
2152
2208
 
2153
2209
  // src/lib/validators.ts
@@ -2235,16 +2291,16 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
2235
2291
  error("Security risk: .env files are tracked by git!");
2236
2292
  console.log();
2237
2293
  for (const file of trackedFiles) {
2238
- console.log(chalk7.red(` tracked: ${file}`));
2294
+ console.log(chalk6.red(` tracked: ${file}`));
2239
2295
  }
2240
2296
  console.log();
2241
2297
  console.log(
2242
- chalk7.yellow(
2298
+ chalk6.yellow(
2243
2299
  " Run the following to untrack them (without deleting the files):"
2244
2300
  )
2245
2301
  );
2246
2302
  for (const file of trackedFiles) {
2247
- console.log(chalk7.cyan(` git rm --cached ${file}`));
2303
+ console.log(chalk6.cyan(` git rm --cached ${file}`));
2248
2304
  }
2249
2305
  console.log();
2250
2306
  process.exit(1);
@@ -2311,7 +2367,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
2311
2367
  if (invalid.length > 0) {
2312
2368
  warning("Some variables have invalid keys and will be skipped:");
2313
2369
  for (const { key, error: err } of invalid) {
2314
- console.log(chalk7.red(` ${key}: ${err}`));
2370
+ console.log(chalk6.red(` ${key}: ${err}`));
2315
2371
  }
2316
2372
  console.log();
2317
2373
  }
@@ -2344,14 +2400,14 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
2344
2400
  return;
2345
2401
  }
2346
2402
  console.log();
2347
- console.log(chalk7.bold("Changes to push:"));
2403
+ console.log(chalk6.bold("Changes to push:"));
2348
2404
  console.log();
2349
2405
  const removedToShow = mode === "replace" ? diffResult.removed : {};
2350
2406
  diff(diffResult.added, removedToShow, diffResult.changed);
2351
2407
  if (mode === "merge" && Object.keys(diffResult.removed).length > 0) {
2352
2408
  console.log();
2353
2409
  console.log(
2354
- chalk7.dim(
2410
+ chalk6.dim(
2355
2411
  `Note: ${Object.keys(diffResult.removed).length} remote variables not in local file will be preserved (use --replace to remove them)`
2356
2412
  )
2357
2413
  );
@@ -2388,7 +2444,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
2388
2444
  }
2389
2445
  }
2390
2446
  const result = await withSpinner(
2391
- `Pushing variables to ${chalk7.bold(environment)}...`,
2447
+ `Pushing variables to ${chalk6.bold(environment)}...`,
2392
2448
  async () => {
2393
2449
  const response = await api.post("/api/cli/variables/bulk", {
2394
2450
  projectId,
@@ -2405,28 +2461,28 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
2405
2461
  );
2406
2462
  if (result?.requested && result.requested > 0) {
2407
2463
  success(
2408
- `Created ${result.requested} pending request(s) for ${chalk7.bold(environment)}`
2464
+ `Created ${result.requested} pending request(s) for ${chalk6.bold(environment)}`
2409
2465
  );
2410
2466
  console.log();
2411
2467
  console.log(
2412
- chalk7.yellow(
2468
+ chalk6.yellow(
2413
2469
  " These changes require approval from an Admin or Team Lead."
2414
2470
  )
2415
2471
  );
2416
2472
  console.log();
2417
- console.log(chalk7.dim(` Requested: ${result.requested}`));
2473
+ console.log(chalk6.dim(` Requested: ${result.requested}`));
2418
2474
  if (result?.skipped && result.skipped > 0) {
2419
- console.log(chalk7.dim(` Skipped: ${result.skipped}`));
2475
+ console.log(chalk6.dim(` Skipped: ${result.skipped}`));
2420
2476
  }
2421
2477
  } else {
2422
2478
  success(
2423
- `Pushed ${result?.total || Object.keys(valid).length} variables to ${chalk7.bold(environment)}`
2479
+ `Pushed ${result?.total || Object.keys(valid).length} variables to ${chalk6.bold(environment)}`
2424
2480
  );
2425
2481
  console.log();
2426
- console.log(chalk7.dim(` Created: ${result?.created || 0}`));
2427
- console.log(chalk7.dim(` Updated: ${result?.updated || 0}`));
2482
+ console.log(chalk6.dim(` Created: ${result?.created || 0}`));
2483
+ console.log(chalk6.dim(` Updated: ${result?.updated || 0}`));
2428
2484
  if (mode === "replace") {
2429
- console.log(chalk7.dim(` Deleted: ${result?.deleted || 0}`));
2485
+ console.log(chalk6.dim(` Deleted: ${result?.deleted || 0}`));
2430
2486
  }
2431
2487
  }
2432
2488
  } catch (err) {
@@ -2436,7 +2492,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
2436
2492
 
2437
2493
  // src/commands/switch.ts
2438
2494
  import { Command as Command5 } from "commander";
2439
- import chalk8 from "chalk";
2495
+ import chalk7 from "chalk";
2440
2496
  import inquirer4 from "inquirer";
2441
2497
  var switchCommand = new Command5("switch").description("Switch project, environment, or active linked project").argument("[target]", "project slug or environment name").option("-o, --organization <id>", "Switch organization").option("-p, --project <id>", "Switch project").option(
2442
2498
  "-e, --env <environment>",
@@ -2464,7 +2520,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2464
2520
  console.log();
2465
2521
  console.log("Linked projects:");
2466
2522
  for (const p of configV2.projects) {
2467
- const mark = p.projectId === configV2.activeProjectId ? chalk8.green(" *") : "";
2523
+ const mark = p.projectId === configV2.activeProjectId ? chalk7.green(" *") : "";
2468
2524
  console.log(
2469
2525
  ` ${p.projectName || p.projectId} (${p.environment})${mark}`
2470
2526
  );
@@ -2476,7 +2532,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2476
2532
  setActiveProjectId(target2.projectId);
2477
2533
  setActiveOrganizationId(target2.organizationId);
2478
2534
  success(
2479
- `Active project: ${chalk8.bold(target2.projectName || target2.projectId)}`
2535
+ `Active project: ${chalk7.bold(target2.projectName || target2.projectId)}`
2480
2536
  );
2481
2537
  return;
2482
2538
  }
@@ -2487,7 +2543,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2487
2543
  process.exit(1);
2488
2544
  }
2489
2545
  updateProjectConfig({ environment });
2490
- success(`Switched to ${chalk8.bold(environment)} environment`);
2546
+ success(`Switched to ${chalk7.bold(environment)} environment`);
2491
2547
  return;
2492
2548
  }
2493
2549
  if (options.organization) {
@@ -2512,9 +2568,9 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2512
2568
  if (projectConfig) {
2513
2569
  updateProjectConfig({ organizationId: org._id });
2514
2570
  }
2515
- success(`Switched to organization: ${chalk8.bold(org.name)}`);
2571
+ success(`Switched to organization: ${chalk7.bold(org.name)}`);
2516
2572
  if (org.role) {
2517
- console.log(chalk8.dim(` Role: ${formatRole(org.role)}`));
2573
+ console.log(chalk7.dim(` Role: ${formatRole(org.role)}`));
2518
2574
  roleNotice(org.role);
2519
2575
  }
2520
2576
  return;
@@ -2535,7 +2591,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2535
2591
  setActiveProjectId(linked.projectId);
2536
2592
  setActiveOrganizationId(linked.organizationId);
2537
2593
  success(
2538
- `Switched to project: ${chalk8.bold(linked.projectName || linked.projectId)}`
2594
+ `Switched to project: ${chalk7.bold(linked.projectName || linked.projectId)}`
2539
2595
  );
2540
2596
  return;
2541
2597
  }
@@ -2565,7 +2621,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2565
2621
  name: "orgId",
2566
2622
  message: "Select an organization:",
2567
2623
  choices: organizations.map((org) => ({
2568
- name: `${org.name} ${org.tier === "pro" ? chalk8.green("(Pro)") : chalk8.dim("(Free)")}`,
2624
+ name: `${org.name} ${org.tier === "pro" ? chalk7.green("(Pro)") : chalk7.dim("(Free)")}`,
2569
2625
  value: org._id
2570
2626
  }))
2571
2627
  }
@@ -2601,10 +2657,10 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2601
2657
  organizationId,
2602
2658
  environment
2603
2659
  });
2604
- success(`Switched to project: ${chalk8.bold(project.name)}`);
2660
+ success(`Switched to project: ${chalk7.bold(project.name)}`);
2605
2661
  if (project.projectRole) {
2606
2662
  console.log(
2607
- chalk8.dim(
2663
+ chalk7.dim(
2608
2664
  ` Project role: ${formatProjectRole(project.projectRole)}`
2609
2665
  )
2610
2666
  );
@@ -2644,7 +2700,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2644
2700
  choices: configV2.projects.map((p) => {
2645
2701
  const isActive = p.projectId === configV2.activeProjectId;
2646
2702
  return {
2647
- name: `${p.projectName || p.projectId} (${p.environment})${isActive ? chalk8.green(" *current") : ""}`,
2703
+ name: `${p.projectName || p.projectId} (${p.environment})${isActive ? chalk7.green(" *current") : ""}`,
2648
2704
  value: p.projectId
2649
2705
  };
2650
2706
  }),
@@ -2659,7 +2715,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2659
2715
  setActiveProjectId(projectId);
2660
2716
  setActiveOrganizationId(selected.organizationId);
2661
2717
  success(
2662
- `Active project: ${chalk8.bold(selected.projectName || selected.projectId)}`
2718
+ `Active project: ${chalk7.bold(selected.projectName || selected.projectId)}`
2663
2719
  );
2664
2720
  return;
2665
2721
  }
@@ -2682,7 +2738,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2682
2738
  }
2683
2739
  ]);
2684
2740
  updateProjectConfig({ environment });
2685
- success(`Switched to ${chalk8.bold(environment)} environment`);
2741
+ success(`Switched to ${chalk7.bold(environment)} environment`);
2686
2742
  return;
2687
2743
  }
2688
2744
  if (switchType === "organization" || switchType === "project") {
@@ -2703,7 +2759,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2703
2759
  name: "orgId",
2704
2760
  message: "Select an organization:",
2705
2761
  choices: organizations.map((org) => ({
2706
- name: `${org.name} ${org.tier === "pro" ? chalk8.green("(Pro)") : chalk8.dim("(Free)")}`,
2762
+ name: `${org.name} ${org.tier === "pro" ? chalk7.green("(Pro)") : chalk7.dim("(Free)")}`,
2707
2763
  value: org._id
2708
2764
  })),
2709
2765
  default: projectConfig?.organizationId
@@ -2715,9 +2771,9 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2715
2771
  if (org.role) {
2716
2772
  setRole(org.role);
2717
2773
  }
2718
- success(`Switched to organization: ${chalk8.bold(org.name)}`);
2774
+ success(`Switched to organization: ${chalk7.bold(org.name)}`);
2719
2775
  if (org.role) {
2720
- console.log(chalk8.dim(` Role: ${formatRole(org.role)}`));
2776
+ console.log(chalk7.dim(` Role: ${formatRole(org.role)}`));
2721
2777
  roleNotice(org.role);
2722
2778
  }
2723
2779
  return;
@@ -2758,10 +2814,10 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2758
2814
  organizationId: orgId,
2759
2815
  environment
2760
2816
  });
2761
- success(`Switched to project: ${chalk8.bold(project.name)}`);
2817
+ success(`Switched to project: ${chalk7.bold(project.name)}`);
2762
2818
  if (project.projectRole) {
2763
2819
  console.log(
2764
- chalk8.dim(
2820
+ chalk7.dim(
2765
2821
  ` Project role: ${formatProjectRole(project.projectRole)}`
2766
2822
  )
2767
2823
  );
@@ -2776,7 +2832,7 @@ var switchCommand = new Command5("switch").description("Switch project, environm
2776
2832
 
2777
2833
  // src/commands/list.ts
2778
2834
  import { Command as Command6 } from "commander";
2779
- import chalk9 from "chalk";
2835
+ import chalk8 from "chalk";
2780
2836
  var listCommand = new Command6("list").description("List resources").argument(
2781
2837
  "[resource]",
2782
2838
  "Resource type: projects, organizations, variables, linked",
@@ -2831,19 +2887,19 @@ function listLinked() {
2831
2887
  console.log();
2832
2888
  for (const project of configV2.projects) {
2833
2889
  const isActive = project.projectId === configV2.activeProjectId;
2834
- const marker = isActive ? chalk9.green("*") : " ";
2890
+ const marker = isActive ? chalk8.green("*") : " ";
2835
2891
  const envFile = getEnvPathForEnvironment(project.environment);
2836
2892
  console.log(
2837
- ` ${marker} ${chalk9.bold(project.projectName || project.projectId)} ${chalk9.dim(`(${project.organizationName || project.organizationId})`)}`
2893
+ ` ${marker} ${chalk8.bold(project.projectName || project.projectId)} ${chalk8.dim(`(${project.organizationName || project.organizationId})`)}`
2838
2894
  );
2839
- console.log(` ${project.environment} ${chalk9.dim("\u2192")} ${envFile}`);
2895
+ console.log(` ${project.environment} ${chalk8.dim("\u2192")} ${envFile}`);
2840
2896
  console.log();
2841
2897
  }
2842
2898
  if (configV2.projects.length > 1) {
2843
- console.log(chalk9.dim(" (* = active project)"));
2899
+ console.log(chalk8.dim(" (* = active project)"));
2844
2900
  console.log();
2845
2901
  console.log(
2846
- chalk9.dim(
2902
+ chalk8.dim(
2847
2903
  ' Use `envpilot switch --active "<name>"` to change the active project'
2848
2904
  )
2849
2905
  );
@@ -2871,7 +2927,7 @@ async function listOrganizations(api, options) {
2871
2927
  organizations.map((org) => ({
2872
2928
  name: org.name,
2873
2929
  slug: org.slug,
2874
- tier: org.tier === "pro" ? chalk9.green("Pro") : chalk9.dim("Free"),
2930
+ tier: org.tier === "pro" ? chalk8.green("Pro") : chalk8.dim("Free"),
2875
2931
  role: org.role
2876
2932
  })),
2877
2933
  [
@@ -2929,9 +2985,9 @@ async function listProjects(api, projectConfig, options) {
2929
2985
  icon: project.icon || "\u{1F4E6}",
2930
2986
  name: project.name,
2931
2987
  slug: project.slug,
2932
- description: project.description || chalk9.dim("-"),
2988
+ description: project.description || chalk8.dim("-"),
2933
2989
  role: project.userRole === "admin" ? formatRole("admin") : formatProjectRole(project.projectRole),
2934
- active: projectConfig?.projectId === project._id ? chalk9.green("\u2713") : ""
2990
+ active: projectConfig?.projectId === project._id ? chalk8.green("\u2713") : ""
2935
2991
  })),
2936
2992
  [
2937
2993
  { key: "icon", header: "" },
@@ -2945,7 +3001,7 @@ async function listProjects(api, projectConfig, options) {
2945
3001
  const role = getRole();
2946
3002
  if (role) {
2947
3003
  console.log();
2948
- console.log(chalk9.dim(`Your org role: ${formatRole(role)}`));
3004
+ console.log(chalk8.dim(`Your org role: ${formatRole(role)}`));
2949
3005
  }
2950
3006
  }
2951
3007
  async function listVariables(api, projectConfig, options) {
@@ -2992,8 +3048,8 @@ async function listVariables(api, projectConfig, options) {
2992
3048
  filtered.map((variable) => ({
2993
3049
  key: variable.key,
2994
3050
  value: options.showValues ? variable.value : maskValue(variable.value),
2995
- sensitive: variable.isSensitive ? chalk9.yellow("\u25CF") : "",
2996
- tags: hasTags ? variable.tags?.map((t) => t.name).join(", ") || chalk9.dim("-") : "",
3051
+ sensitive: variable.isSensitive ? chalk8.yellow("\u25CF") : "",
3052
+ tags: hasTags ? variable.tags?.map((t) => t.name).join(", ") || chalk8.dim("-") : "",
2997
3053
  version: `v${variable.version}`
2998
3054
  })),
2999
3055
  [
@@ -3005,29 +3061,29 @@ async function listVariables(api, projectConfig, options) {
3005
3061
  ]
3006
3062
  );
3007
3063
  console.log();
3008
- console.log(chalk9.dim(`Total: ${filtered.length} variables`));
3064
+ console.log(chalk8.dim(`Total: ${filtered.length} variables`));
3009
3065
  const role = getRole();
3010
3066
  if (role) {
3011
- console.log(chalk9.dim(`Your org role: ${formatRole(role)}`));
3067
+ console.log(chalk8.dim(`Your org role: ${formatRole(role)}`));
3012
3068
  }
3013
3069
  if (metaProjectRole) {
3014
3070
  console.log(
3015
- chalk9.dim(`Your project role: ${formatProjectRole(metaProjectRole)}`)
3071
+ chalk8.dim(`Your project role: ${formatProjectRole(metaProjectRole)}`)
3016
3072
  );
3017
3073
  }
3018
3074
  if (role === "member" || metaProjectRole === "viewer") {
3019
3075
  console.log(
3020
- chalk9.dim("You may only see variables you have been granted access to.")
3076
+ chalk8.dim("You may only see variables you have been granted access to.")
3021
3077
  );
3022
3078
  }
3023
3079
  if (!options.showValues) {
3024
- console.log(chalk9.dim("Use --show-values to see actual values"));
3080
+ console.log(chalk8.dim("Use --show-values to see actual values"));
3025
3081
  }
3026
3082
  }
3027
3083
 
3028
3084
  // src/commands/config.ts
3029
3085
  import { Command as Command7 } from "commander";
3030
- import chalk10 from "chalk";
3086
+ import chalk9 from "chalk";
3031
3087
  var configCommand = new Command7("config").description("Manage CLI configuration").argument("[action]", "Action: get, set, list, path, reset").argument("[key]", "Config key (for get/set)").argument("[value]", "Config value (for set)").action(async (action, key, value) => {
3032
3088
  try {
3033
3089
  switch (action) {
@@ -3082,14 +3138,14 @@ async function handleGet(key) {
3082
3138
  if (config2.user) {
3083
3139
  console.log(JSON.stringify(config2.user, null, 2));
3084
3140
  } else {
3085
- console.log(chalk10.dim("(not set)"));
3141
+ console.log(chalk9.dim("(not set)"));
3086
3142
  }
3087
3143
  break;
3088
3144
  case "activeProjectId":
3089
- console.log(config2.activeProjectId || chalk10.dim("(not set)"));
3145
+ console.log(config2.activeProjectId || chalk9.dim("(not set)"));
3090
3146
  break;
3091
3147
  case "activeOrganizationId":
3092
- console.log(config2.activeOrganizationId || chalk10.dim("(not set)"));
3148
+ console.log(config2.activeOrganizationId || chalk9.dim("(not set)"));
3093
3149
  break;
3094
3150
  default:
3095
3151
  error(`Unknown key: ${key}`);
@@ -3105,16 +3161,18 @@ async function handleSet(key, value) {
3105
3161
  process.exit(1);
3106
3162
  }
3107
3163
  switch (key) {
3108
- case "apiUrl":
3164
+ case "apiUrl": {
3165
+ const normalized = normalizeApiUrl(value);
3109
3166
  try {
3110
- new URL(value);
3167
+ new URL(normalized);
3111
3168
  } catch {
3112
3169
  error("Invalid URL format");
3113
3170
  process.exit(1);
3114
3171
  }
3115
3172
  setApiUrl(value);
3116
- success(`Set apiUrl to ${value}`);
3173
+ success(`Set apiUrl to ${normalized}`);
3117
3174
  break;
3175
+ }
3118
3176
  default:
3119
3177
  error(`Cannot set key: ${key}`);
3120
3178
  console.log();
@@ -3130,7 +3188,7 @@ async function handleList() {
3130
3188
  console.log();
3131
3189
  keyValue([
3132
3190
  ["API URL", config2.apiUrl],
3133
- ["Authenticated", isAuthenticated() ? chalk10.green("Yes") : chalk10.red("No")],
3191
+ ["Authenticated", isAuthenticated() ? chalk9.green("Yes") : chalk9.red("No")],
3134
3192
  ["User", config2.user?.email],
3135
3193
  ["Active Organization", config2.activeOrganizationId],
3136
3194
  ["Active Project", config2.activeProjectId]
@@ -3199,7 +3257,7 @@ var logoutCommand = new Command8("logout").description("Log out from Envpilot").
3199
3257
 
3200
3258
  // src/commands/unlink.ts
3201
3259
  import { Command as Command9 } from "commander";
3202
- import chalk11 from "chalk";
3260
+ import chalk10 from "chalk";
3203
3261
  import inquirer5 from "inquirer";
3204
3262
  var unlinkCommand = new Command9("unlink").description("Remove a linked project from this directory").argument("[project]", "Project name or ID to unlink").option("--force", "Skip confirmation").action(async (projectArg, options) => {
3205
3263
  try {
@@ -3234,7 +3292,7 @@ var unlinkCommand = new Command9("unlink").description("Remove a linked project
3234
3292
  choices: config2.projects.map((p) => {
3235
3293
  const isActive = p.projectId === config2.activeProjectId;
3236
3294
  return {
3237
- name: `${p.projectName || p.projectId} (${p.organizationName || p.organizationId})${isActive ? chalk11.green(" *active") : ""}`,
3295
+ name: `${p.projectName || p.projectId} (${p.organizationName || p.organizationId})${isActive ? chalk10.green(" *active") : ""}`,
3238
3296
  value: p.projectId
3239
3297
  };
3240
3298
  })
@@ -3277,7 +3335,7 @@ var unlinkCommand = new Command9("unlink").description("Remove a linked project
3277
3335
  );
3278
3336
  }
3279
3337
  console.log(
3280
- chalk11.dim(
3338
+ chalk10.dim(
3281
3339
  ` ${updated.projects.length} project${updated.projects.length !== 1 ? "s" : ""} remaining`
3282
3340
  )
3283
3341
  );
@@ -3289,7 +3347,7 @@ var unlinkCommand = new Command9("unlink").description("Remove a linked project
3289
3347
 
3290
3348
  // src/commands/sync.ts
3291
3349
  import { Command as Command10 } from "commander";
3292
- import chalk12 from "chalk";
3350
+ import chalk11 from "chalk";
3293
3351
 
3294
3352
  // src/lib/commit-guard.ts
3295
3353
  import {
@@ -3467,7 +3525,7 @@ var syncCommand = new Command10("sync").description(
3467
3525
  projectName = active.projectName;
3468
3526
  organizationName = active.organizationName;
3469
3527
  info(
3470
- `Using project ${chalk12.bold(projectName || projectId)} (${environment})`
3528
+ `Using project ${chalk11.bold(projectName || projectId)} (${environment})`
3471
3529
  );
3472
3530
  } else {
3473
3531
  const selection = await selectOrgProjectEnv(options);
@@ -3521,7 +3579,7 @@ var syncCommand = new Command10("sync").description(
3521
3579
  console.log();
3522
3580
  let metaProjectRole;
3523
3581
  const variables = await withSpinner(
3524
- `Fetching ${chalk12.bold(environment)} variables...`,
3582
+ `Fetching ${chalk11.bold(environment)} variables...`,
3525
3583
  async () => {
3526
3584
  const api = createAPIClient();
3527
3585
  const response = await api.get("/api/cli/variables", {
@@ -3547,12 +3605,12 @@ var syncCommand = new Command10("sync").description(
3547
3605
  const diffResult = diffEnvVars(remoteVars, localVars);
3548
3606
  const hasChanges = Object.keys(diffResult.added).length > 0 || Object.keys(diffResult.removed).length > 0 || Object.keys(diffResult.changed).length > 0;
3549
3607
  if (!hasChanges) {
3550
- success(`${chalk12.bold(outputPath)} is up to date.`);
3608
+ success(`${chalk11.bold(outputPath)} is up to date.`);
3551
3609
  console.log();
3552
3610
  return;
3553
3611
  }
3554
3612
  console.log();
3555
- console.log(chalk12.bold("Changes:"));
3613
+ console.log(chalk11.bold("Changes:"));
3556
3614
  console.log();
3557
3615
  diff(diffResult.added, diffResult.removed, diffResult.changed);
3558
3616
  console.log();
@@ -3573,7 +3631,7 @@ var syncCommand = new Command10("sync").description(
3573
3631
  const role = getRole();
3574
3632
  applyFileProtection(outputPath, role, metaProjectRole);
3575
3633
  success(
3576
- `Synced ${variables.length} variables to ${chalk12.bold(outputPath)}`
3634
+ `Synced ${variables.length} variables to ${chalk11.bold(outputPath)}`
3577
3635
  );
3578
3636
  const isProtected = role !== "admin" && role !== "team_lead" && metaProjectRole !== "manager";
3579
3637
  if (isProtected) {
@@ -3583,13 +3641,13 @@ var syncCommand = new Command10("sync").description(
3583
3641
  }
3584
3642
  console.log();
3585
3643
  console.log(
3586
- chalk12.dim(` Added: ${Object.keys(diffResult.added).length}`)
3644
+ chalk11.dim(` Added: ${Object.keys(diffResult.added).length}`)
3587
3645
  );
3588
3646
  console.log(
3589
- chalk12.dim(` Changed: ${Object.keys(diffResult.changed).length}`)
3647
+ chalk11.dim(` Changed: ${Object.keys(diffResult.changed).length}`)
3590
3648
  );
3591
3649
  console.log(
3592
- chalk12.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
3650
+ chalk11.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
3593
3651
  );
3594
3652
  console.log();
3595
3653
  } catch (err) {
@@ -3599,17 +3657,17 @@ var syncCommand = new Command10("sync").description(
3599
3657
 
3600
3658
  // src/commands/usage.ts
3601
3659
  import { Command as Command11 } from "commander";
3602
- import chalk13 from "chalk";
3660
+ import chalk12 from "chalk";
3603
3661
  function formatUsage(current, limit) {
3604
3662
  const limitStr = limit === null ? "unlimited" : String(limit);
3605
3663
  const ratio = `${current}/${limitStr}`;
3606
- if (limit === null) return chalk13.green(ratio);
3607
- if (current >= limit) return chalk13.red(ratio);
3608
- if (current >= limit * 0.8) return chalk13.yellow(ratio);
3609
- return chalk13.green(ratio);
3664
+ if (limit === null) return chalk12.green(ratio);
3665
+ if (current >= limit) return chalk12.red(ratio);
3666
+ if (current >= limit * 0.8) return chalk12.yellow(ratio);
3667
+ return chalk12.green(ratio);
3610
3668
  }
3611
3669
  function featureStatus(enabled) {
3612
- return enabled ? chalk13.green("Enabled") : chalk13.dim("Disabled (Pro)");
3670
+ return enabled ? chalk12.green("Enabled") : chalk12.dim("Disabled (Pro)");
3613
3671
  }
3614
3672
  var usageCommand = new Command11("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) => {
3615
3673
  try {
@@ -3654,7 +3712,7 @@ var usageCommand = new Command11("usage").description("Show plan usage and limit
3654
3712
  console.log(JSON.stringify(usage, null, 2));
3655
3713
  return;
3656
3714
  }
3657
- const tierLabel = usage.tier === "pro" ? chalk13.green("Pro") : chalk13.white("Free");
3715
+ const tierLabel = usage.tier === "pro" ? chalk12.green("Pro") : chalk12.white("Free");
3658
3716
  header(`Plan: ${tierLabel}`);
3659
3717
  blank();
3660
3718
  if (!usage.enforcementEnabled) {
@@ -3708,7 +3766,7 @@ var usageCommand = new Command11("usage").description("Show plan usage and limit
3708
3766
 
3709
3767
  // src/commands/whoami.ts
3710
3768
  import { Command as Command12 } from "commander";
3711
- import chalk14 from "chalk";
3769
+ import chalk13 from "chalk";
3712
3770
  var whoamiCommand = new Command12("whoami").description("Show the current authenticated user and active CLI context").action(async () => {
3713
3771
  try {
3714
3772
  if (!isAuthenticated()) {
@@ -3734,7 +3792,7 @@ var whoamiCommand = new Command12("whoami").description("Show the current authen
3734
3792
  ["Environment", activeProject?.environment]
3735
3793
  ]);
3736
3794
  blank();
3737
- console.log(chalk14.dim("Token verified against the CLI auth endpoint."));
3795
+ console.log(chalk13.dim("Token verified against the CLI auth endpoint."));
3738
3796
  } catch (err) {
3739
3797
  await handleError(err);
3740
3798
  }
@@ -3743,7 +3801,7 @@ var whoamiCommand = new Command12("whoami").description("Show the current authen
3743
3801
  // src/commands/run.ts
3744
3802
  import { Command as Command13 } from "commander";
3745
3803
  import { spawn as spawn2 } from "child_process";
3746
- import chalk15 from "chalk";
3804
+ import chalk14 from "chalk";
3747
3805
 
3748
3806
  // src/lib/variables-cache.ts
3749
3807
  import { createHash } from "crypto";
@@ -3991,9 +4049,9 @@ var runCommand = new Command13("run").description(
3991
4049
  }
3992
4050
  if (!options.quiet) {
3993
4051
  const injectedCount = Object.keys(secrets).length;
3994
- const cacheTag = cacheHit ? chalk15.dim(` \u26A1 cache (${cacheAge})`) : "";
4052
+ const cacheTag = cacheHit ? chalk14.dim(` \u26A1 cache (${cacheAge})`) : "";
3995
4053
  info(
3996
- `Injected ${chalk15.bold(injectedCount)} ${injectedCount === 1 ? "variable" : "variables"} from ${chalk15.bold(`${project.projectName || project.projectId}/${environment}`)}${cacheTag}`
4054
+ `Injected ${chalk14.bold(injectedCount)} ${injectedCount === 1 ? "variable" : "variables"} from ${chalk14.bold(`${project.projectName || project.projectId}/${environment}`)}${cacheTag}`
3997
4055
  );
3998
4056
  if (overridden.length > 0) {
3999
4057
  warning(
@@ -4009,7 +4067,7 @@ var runCommand = new Command13("run").description(
4009
4067
  }
4010
4068
  });
4011
4069
  async function doFetch(project, environment, organizationId, quiet, labelPrefix = "Loading") {
4012
- const label = `${labelPrefix} ${chalk15.bold(environment)} secrets for ${chalk15.bold(project.projectName || project.projectId)}...`;
4070
+ const label = `${labelPrefix} ${chalk14.bold(environment)} secrets for ${chalk14.bold(project.projectName || project.projectId)}...`;
4013
4071
  const api = createAPIClient();
4014
4072
  const { variables, decryptionFailures } = quiet ? await api.listVariables(project.projectId, environment, organizationId) : await withSpinner(
4015
4073
  label,
@@ -4018,7 +4076,7 @@ async function doFetch(project, environment, organizationId, quiet, labelPrefix
4018
4076
  if (decryptionFailures.length > 0) {
4019
4077
  for (const key of decryptionFailures) {
4020
4078
  warning(
4021
- `Could not decrypt ${chalk15.bold(key)} \u2014 skipped (vault error, check server logs)`
4079
+ `Could not decrypt ${chalk14.bold(key)} \u2014 skipped (vault error, check server logs)`
4022
4080
  );
4023
4081
  }
4024
4082
  }
@@ -4028,18 +4086,18 @@ function printInjectionPreview(secrets, project, environment) {
4028
4086
  const keys = Object.keys(secrets).sort();
4029
4087
  console.log();
4030
4088
  console.log(
4031
- chalk15.bold(
4032
- `Would inject ${keys.length} ${keys.length === 1 ? "variable" : "variables"} from ${chalk15.cyan(`${project.projectName || project.projectId}/${environment}`)}:`
4089
+ chalk14.bold(
4090
+ `Would inject ${keys.length} ${keys.length === 1 ? "variable" : "variables"} from ${chalk14.cyan(`${project.projectName || project.projectId}/${environment}`)}:`
4033
4091
  )
4034
4092
  );
4035
4093
  console.log();
4036
4094
  if (keys.length === 0) {
4037
- console.log(chalk15.dim(" (no variables)"));
4095
+ console.log(chalk14.dim(" (no variables)"));
4038
4096
  } else {
4039
4097
  for (const key of keys) {
4040
4098
  const value = secrets[key];
4041
4099
  const masked = maskForPreview(value);
4042
- console.log(` ${chalk15.cyan(key)}=${chalk15.dim(masked)}`);
4100
+ console.log(` ${chalk14.cyan(key)}=${chalk14.dim(masked)}`);
4043
4101
  }
4044
4102
  }
4045
4103
  console.log();
@@ -4119,38 +4177,38 @@ function runChild(commandArgs, env, options) {
4119
4177
 
4120
4178
  // src/commands/man.ts
4121
4179
  import { Command as Command14 } from "commander";
4122
- import chalk16 from "chalk";
4180
+ import chalk15 from "chalk";
4123
4181
  function printCommandManual(commandName) {
4124
4182
  const command = findCommandDefinition(commandName);
4125
4183
  if (!command) {
4126
- console.log(chalk16.red(`Unknown command reference: ${commandName}`));
4184
+ console.log(chalk15.red(`Unknown command reference: ${commandName}`));
4127
4185
  console.log();
4128
4186
  console.log("Run `envpilot man` to see all supported commands.");
4129
4187
  process.exit(1);
4130
4188
  }
4131
- console.log(chalk16.bold(formatArgv(command.argv)));
4189
+ console.log(chalk15.bold(formatArgv(command.argv)));
4132
4190
  if (command.args) {
4133
- console.log(chalk16.dim(command.args));
4191
+ console.log(chalk15.dim(command.args));
4134
4192
  }
4135
4193
  blank();
4136
4194
  console.log(command.description);
4137
4195
  blank();
4138
- console.log(chalk16.green("Examples"));
4196
+ console.log(chalk15.green("Examples"));
4139
4197
  for (const example of command.examples) {
4140
- console.log(` ${chalk16.cyan(formatArgv(example))}`);
4198
+ console.log(` ${chalk15.cyan(formatArgv(example))}`);
4141
4199
  }
4142
4200
  blank();
4143
- console.log(chalk16.green("Notes"));
4201
+ console.log(chalk15.green("Notes"));
4144
4202
  for (const note of command.notes) {
4145
4203
  console.log(` - ${note}`);
4146
4204
  }
4147
4205
  }
4148
4206
  function printManualIndex(commands) {
4149
- console.log(chalk16.bold("ENVPILOT(1)"));
4207
+ console.log(chalk15.bold("ENVPILOT(1)"));
4150
4208
  console.log("TypeScript CLI manual");
4151
4209
  blank();
4152
4210
  console.log(
4153
- `Total supported top-level commands: ${chalk16.green(String(CLI_COMMAND_COUNT))}`
4211
+ `Total supported top-level commands: ${chalk15.green(String(CLI_COMMAND_COUNT))}`
4154
4212
  );
4155
4213
  blank();
4156
4214
  console.log(
@@ -4158,15 +4216,15 @@ function printManualIndex(commands) {
4158
4216
  );
4159
4217
  blank();
4160
4218
  line();
4161
- console.log(chalk16.green("Commands"));
4219
+ console.log(chalk15.green("Commands"));
4162
4220
  for (const command of commands) {
4163
4221
  console.log(
4164
- ` ${chalk16.cyan(formatArgv(command.argv).padEnd(24))} ${chalk16.dim(command.description)}`
4222
+ ` ${chalk15.cyan(formatArgv(command.argv).padEnd(24))} ${chalk15.dim(command.description)}`
4165
4223
  );
4166
4224
  }
4167
4225
  blank();
4168
4226
  line();
4169
- console.log(chalk16.green("Security"));
4227
+ console.log(chalk15.green("Security"));
4170
4228
  console.log(" - `.env*` is ignored by the repository `.gitignore`.");
4171
4229
  console.log(
4172
4230
  " - `envpilot init` and `envpilot sync` ensure env files are added to `.gitignore` locally."
@@ -4179,7 +4237,7 @@ function printManualIndex(commands) {
4179
4237
  );
4180
4238
  blank();
4181
4239
  line();
4182
- console.log(chalk16.green("Usage"));
4240
+ console.log(chalk15.green("Usage"));
4183
4241
  console.log(
4184
4242
  " - `envpilot` or `envpilot ui` opens the interactive terminal UI."
4185
4243
  );