@envpilot/cli 1.2.0 → 1.3.1

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.
Files changed (2) hide show
  1. package/dist/index.js +199 -68
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -1,11 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/lib/sentry.ts
4
+ import * as Sentry from "@sentry/node";
5
+ var initialized = false;
6
+ function initSentry() {
7
+ const dsn = true ? "" : "";
8
+ if (initialized || !dsn) return;
9
+ Sentry.init({
10
+ dsn,
11
+ environment: "cli",
12
+ release: true ? "1.3.1" : "0.0.0",
13
+ // Free tier: disable performance monitoring
14
+ tracesSampleRate: 0,
15
+ beforeSend(event) {
16
+ if (event.exception?.values) {
17
+ for (const exc of event.exception.values) {
18
+ if (exc.stacktrace?.frames) {
19
+ for (const frame of exc.stacktrace.frames) {
20
+ if (frame.filename) {
21
+ frame.filename = frame.filename.replace(
22
+ /\/Users\/[^/]+/g,
23
+ "/~"
24
+ );
25
+ frame.filename = frame.filename.replace(
26
+ /C:\\Users\\[^\\]+/g,
27
+ "C:\\~"
28
+ );
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ if (event.request?.data) {
35
+ event.request.data = "[REDACTED]";
36
+ }
37
+ return event;
38
+ }
39
+ });
40
+ initialized = true;
41
+ }
42
+ function captureError(error2, context) {
43
+ if (!initialized) return;
44
+ Sentry.captureException(error2, { tags: context });
45
+ }
46
+ async function flushSentry() {
47
+ if (!initialized) return;
48
+ await Sentry.flush(2e3);
49
+ }
50
+
3
51
  // src/index.ts
4
52
  import { Command as Command10 } from "commander";
5
53
 
6
54
  // src/commands/login.ts
7
55
  import { Command } from "commander";
8
- import chalk2 from "chalk";
56
+ import chalk3 from "chalk";
9
57
  import open from "open";
10
58
 
11
59
  // src/lib/ui.ts
@@ -498,6 +546,91 @@ function createAPIClient() {
498
546
  return new APIClient();
499
547
  }
500
548
 
549
+ // src/lib/errors.ts
550
+ import chalk2 from "chalk";
551
+ var CLIError = class extends Error {
552
+ constructor(message, code, suggestion) {
553
+ super(message);
554
+ this.code = code;
555
+ this.suggestion = suggestion;
556
+ this.name = "CLIError";
557
+ }
558
+ };
559
+ var ErrorCodes = {
560
+ NOT_AUTHENTICATED: "NOT_AUTHENTICATED",
561
+ NOT_INITIALIZED: "NOT_INITIALIZED",
562
+ PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
563
+ ORGANIZATION_NOT_FOUND: "ORGANIZATION_NOT_FOUND",
564
+ VARIABLE_NOT_FOUND: "VARIABLE_NOT_FOUND",
565
+ INVALID_CONFIG: "INVALID_CONFIG",
566
+ NETWORK_ERROR: "NETWORK_ERROR",
567
+ PERMISSION_DENIED: "PERMISSION_DENIED",
568
+ TIER_LIMIT_EXCEEDED: "TIER_LIMIT_EXCEEDED",
569
+ FILE_NOT_FOUND: "FILE_NOT_FOUND",
570
+ INVALID_INPUT: "INVALID_INPUT",
571
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"
572
+ };
573
+ function formatError(error2) {
574
+ if (error2 instanceof CLIError) {
575
+ let message = chalk2.red(`Error: ${error2.message}`);
576
+ if (error2.suggestion) {
577
+ message += `
578
+ ${chalk2.yellow("Suggestion:")} ${error2.suggestion}`;
579
+ }
580
+ return message;
581
+ }
582
+ if (error2 instanceof Error) {
583
+ return chalk2.red(`Error: ${error2.message}`);
584
+ }
585
+ return chalk2.red(`Error: ${String(error2)}`);
586
+ }
587
+ async function handleError(error2) {
588
+ console.error(formatError(error2));
589
+ const skipCodes = /* @__PURE__ */ new Set([
590
+ ErrorCodes.NOT_AUTHENTICATED,
591
+ ErrorCodes.INVALID_INPUT,
592
+ ErrorCodes.NOT_INITIALIZED
593
+ ]);
594
+ if (error2 instanceof CLIError) {
595
+ if (!skipCodes.has(error2.code)) {
596
+ captureError(error2, { errorCode: error2.code });
597
+ }
598
+ } else {
599
+ captureError(error2);
600
+ }
601
+ await flushSentry();
602
+ if (error2 instanceof CLIError) {
603
+ switch (error2.code) {
604
+ case ErrorCodes.NOT_AUTHENTICATED:
605
+ process.exit(2);
606
+ case ErrorCodes.PERMISSION_DENIED:
607
+ process.exit(3);
608
+ case ErrorCodes.TIER_LIMIT_EXCEEDED:
609
+ process.exit(4);
610
+ default:
611
+ process.exit(1);
612
+ }
613
+ }
614
+ process.exit(1);
615
+ }
616
+ function notAuthenticated() {
617
+ return new CLIError(
618
+ "You are not authenticated.",
619
+ ErrorCodes.NOT_AUTHENTICATED,
620
+ "Run `envpilot login` to authenticate."
621
+ );
622
+ }
623
+ function notInitialized() {
624
+ return new CLIError(
625
+ "This directory is not initialized with Envpilot.",
626
+ ErrorCodes.NOT_INITIALIZED,
627
+ "Run `envpilot init` to initialize."
628
+ );
629
+ }
630
+ function fileNotFound(path) {
631
+ return new CLIError(`File not found: ${path}`, ErrorCodes.FILE_NOT_FOUND);
632
+ }
633
+
501
634
  // src/commands/login.ts
502
635
  import { hostname } from "os";
503
636
  var POLL_INTERVAL_MS = 2e3;
@@ -515,12 +648,12 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
515
648
  const initResponse = await api.post("/api/cli/auth?action=initiate", { deviceName });
516
649
  spinner.stop();
517
650
  console.log();
518
- console.log(chalk2.bold("Your authentication code:"));
651
+ console.log(chalk3.bold("Your authentication code:"));
519
652
  console.log();
520
- console.log(chalk2.cyan.bold(` ${initResponse.code}`));
653
+ console.log(chalk3.cyan.bold(` ${initResponse.code}`));
521
654
  console.log();
522
655
  console.log(`Open this URL to authenticate:`);
523
- console.log(chalk2.dim(initResponse.url));
656
+ console.log(chalk3.dim(initResponse.url));
524
657
  console.log();
525
658
  if (options.browser !== false) {
526
659
  info("Opening browser...");
@@ -550,14 +683,14 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
550
683
  }
551
684
  authenticated = true;
552
685
  console.log();
553
- success(`Logged in as ${chalk2.bold(pollResponse.user?.email)}`);
686
+ success(`Logged in as ${chalk3.bold(pollResponse.user?.email)}`);
554
687
  console.log();
555
688
  console.log("Next steps:");
556
689
  console.log(
557
- ` ${chalk2.cyan("envpilot init")} Initialize a project in the current directory`
690
+ ` ${chalk3.cyan("envpilot init")} Initialize a project in the current directory`
558
691
  );
559
692
  console.log(
560
- ` ${chalk2.cyan("envpilot list")} List your projects and organizations`
693
+ ` ${chalk3.cyan("envpilot list")} List your projects and organizations`
561
694
  );
562
695
  console.log();
563
696
  break;
@@ -575,8 +708,7 @@ var loginCommand = new Command("login").description("Authenticate with Envpilot"
575
708
  process.exit(1);
576
709
  }
577
710
  } catch (err) {
578
- error(err instanceof Error ? err.message : "Authentication failed");
579
- process.exit(1);
711
+ await handleError(err);
580
712
  }
581
713
  });
582
714
  function sleep(ms) {
@@ -709,48 +841,6 @@ function getTrackedEnvFiles(directory = process.cwd()) {
709
841
  }
710
842
  }
711
843
 
712
- // src/lib/errors.ts
713
- import chalk3 from "chalk";
714
- var CLIError = class extends Error {
715
- constructor(message, code, suggestion) {
716
- super(message);
717
- this.code = code;
718
- this.suggestion = suggestion;
719
- this.name = "CLIError";
720
- }
721
- };
722
- var ErrorCodes = {
723
- NOT_AUTHENTICATED: "NOT_AUTHENTICATED",
724
- NOT_INITIALIZED: "NOT_INITIALIZED",
725
- PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
726
- ORGANIZATION_NOT_FOUND: "ORGANIZATION_NOT_FOUND",
727
- VARIABLE_NOT_FOUND: "VARIABLE_NOT_FOUND",
728
- INVALID_CONFIG: "INVALID_CONFIG",
729
- NETWORK_ERROR: "NETWORK_ERROR",
730
- PERMISSION_DENIED: "PERMISSION_DENIED",
731
- TIER_LIMIT_EXCEEDED: "TIER_LIMIT_EXCEEDED",
732
- FILE_NOT_FOUND: "FILE_NOT_FOUND",
733
- INVALID_INPUT: "INVALID_INPUT",
734
- UNKNOWN_ERROR: "UNKNOWN_ERROR"
735
- };
736
- function notAuthenticated() {
737
- return new CLIError(
738
- "You are not authenticated.",
739
- ErrorCodes.NOT_AUTHENTICATED,
740
- "Run `envpilot login` to authenticate."
741
- );
742
- }
743
- function notInitialized() {
744
- return new CLIError(
745
- "This directory is not initialized with Envpilot.",
746
- ErrorCodes.NOT_INITIALIZED,
747
- "Run `envpilot init` to initialize."
748
- );
749
- }
750
- function fileNotFound(path) {
751
- return new CLIError(`File not found: ${path}`, ErrorCodes.FILE_NOT_FOUND);
752
- }
753
-
754
844
  // src/commands/init.ts
755
845
  var initCommand = new Command2("init").description("Initialize Envpilot in the current directory").option("-o, --organization <id>", "Organization ID").option("-p, --project <id>", "Project ID").option(
756
846
  "-e, --environment <env>",
@@ -933,8 +1023,7 @@ var initCommand = new Command2("init").description("Initialize Envpilot in the c
933
1023
  );
934
1024
  console.log();
935
1025
  } catch (err) {
936
- error(err instanceof Error ? err.message : "Initialization failed");
937
- process.exit(1);
1026
+ await handleError(err);
938
1027
  }
939
1028
  });
940
1029
 
@@ -1170,8 +1259,7 @@ var pullCommand = new Command3("pull").description("Download environment variabl
1170
1259
  chalk5.dim(` Removed: ${Object.keys(diffResult.removed).length}`)
1171
1260
  );
1172
1261
  } catch (err) {
1173
- error(err instanceof Error ? err.message : "Pull failed");
1174
- process.exit(1);
1262
+ await handleError(err);
1175
1263
  }
1176
1264
  });
1177
1265
 
@@ -1419,8 +1507,7 @@ var pushCommand = new Command4("push").description("Upload local .env file to cl
1419
1507
  }
1420
1508
  }
1421
1509
  } catch (err) {
1422
- error(err instanceof Error ? err.message : "Push failed");
1423
- process.exit(1);
1510
+ await handleError(err);
1424
1511
  }
1425
1512
  });
1426
1513
 
@@ -1674,8 +1761,7 @@ var switchCommand = new Command5("switch").description("Switch project or enviro
1674
1761
  }
1675
1762
  }
1676
1763
  } catch (err) {
1677
- error(err instanceof Error ? err.message : "Switch failed");
1678
- process.exit(1);
1764
+ await handleError(err);
1679
1765
  }
1680
1766
  });
1681
1767
 
@@ -1717,8 +1803,7 @@ var listCommand = new Command6("list").description("List resources").argument(
1717
1803
  process.exit(1);
1718
1804
  }
1719
1805
  } catch (err) {
1720
- error(err instanceof Error ? err.message : "List failed");
1721
- process.exit(1);
1806
+ await handleError(err);
1722
1807
  }
1723
1808
  });
1724
1809
  async function listOrganizations(api, options) {
@@ -1920,8 +2005,7 @@ var configCommand = new Command7("config").description("Manage CLI configuration
1920
2005
  process.exit(1);
1921
2006
  }
1922
2007
  } catch (err) {
1923
- error(err instanceof Error ? err.message : "Config operation failed");
1924
- process.exit(1);
2008
+ await handleError(err);
1925
2009
  }
1926
2010
  });
1927
2011
  async function handleGet(key) {
@@ -2055,8 +2139,7 @@ var logoutCommand = new Command8("logout").description("Log out from Envpilot").
2055
2139
  clearAuth();
2056
2140
  success(`Logged out${user?.email ? ` from ${user.email}` : ""}`);
2057
2141
  } catch (err) {
2058
- error(err instanceof Error ? err.message : "Logout failed");
2059
- process.exit(1);
2142
+ await handleError(err);
2060
2143
  }
2061
2144
  });
2062
2145
 
@@ -2165,14 +2248,59 @@ var usageCommand = new Command9("usage").description("Show plan usage and limits
2165
2248
  ]);
2166
2249
  blank();
2167
2250
  } catch (err) {
2168
- error(err instanceof Error ? err.message : "Failed to get usage");
2169
- process.exit(1);
2251
+ await handleError(err);
2170
2252
  }
2171
2253
  });
2172
2254
 
2255
+ // src/lib/version-check.ts
2256
+ import chalk11 from "chalk";
2257
+ import Conf2 from "conf";
2258
+ var CLI_VERSION = "1.3.1";
2259
+ var CHECK_INTERVAL = 60 * 60 * 1e3;
2260
+ var _cache = null;
2261
+ function getCache() {
2262
+ if (!_cache) {
2263
+ _cache = new Conf2({
2264
+ projectName: "envpilot",
2265
+ configName: "version-cache"
2266
+ });
2267
+ }
2268
+ return _cache;
2269
+ }
2270
+ function checkForUpdate() {
2271
+ const cache = getCache();
2272
+ const lastCheck = cache.get("lastVersionCheck");
2273
+ if (lastCheck && Date.now() - lastCheck < CHECK_INTERVAL) return;
2274
+ const apiUrl = getApiUrl();
2275
+ fetch(`${apiUrl}/api/version`, { signal: AbortSignal.timeout(5e3) }).then((res) => {
2276
+ if (!res.ok) return;
2277
+ return res.json();
2278
+ }).then((data) => {
2279
+ if (!data?.cli) return;
2280
+ cache.set("lastVersionCheck", Date.now());
2281
+ if (data.cli !== CLI_VERSION) {
2282
+ console.log();
2283
+ console.log(
2284
+ chalk11.yellow(" Update available:"),
2285
+ chalk11.dim(CLI_VERSION),
2286
+ chalk11.yellow("\u2192"),
2287
+ chalk11.green(data.cli)
2288
+ );
2289
+ console.log(
2290
+ chalk11.dim(" Run"),
2291
+ chalk11.cyan("npm update -g @envpilot/cli"),
2292
+ chalk11.dim("to update")
2293
+ );
2294
+ console.log();
2295
+ }
2296
+ }).catch(() => {
2297
+ });
2298
+ }
2299
+
2173
2300
  // src/index.ts
2301
+ initSentry();
2174
2302
  var program = new Command10();
2175
- program.name("envpilot").description("Envpilot CLI - Sync, secure, and share environment variables").version("1.0.0");
2303
+ program.name("envpilot").description("Envpilot CLI - Sync, secure, and share environment variables").version("1.3.1");
2176
2304
  program.addCommand(loginCommand);
2177
2305
  program.addCommand(logoutCommand);
2178
2306
  program.addCommand(initCommand);
@@ -2182,4 +2310,7 @@ program.addCommand(switchCommand);
2182
2310
  program.addCommand(listCommand);
2183
2311
  program.addCommand(configCommand);
2184
2312
  program.addCommand(usageCommand);
2313
+ program.hook("postAction", () => {
2314
+ checkForUpdate();
2315
+ });
2185
2316
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envpilot/cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Envpilot CLI — sync and manage environment variables from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,8 +12,8 @@
12
12
  "README.md"
13
13
  ],
14
14
  "scripts": {
15
- "build": "tsup src/index.ts --format esm --dts --clean",
16
- "dev": "tsup src/index.ts --format esm --watch",
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
17
  "lint": "eslint \"src/**/*.ts\"",
18
18
  "typecheck": "tsc --noEmit",
19
19
  "test": "vitest run",
@@ -21,6 +21,7 @@
21
21
  "prepublishOnly": "npm run build"
22
22
  },
23
23
  "dependencies": {
24
+ "@sentry/node": "^10.43.0",
24
25
  "chalk": "^5.3.0",
25
26
  "commander": "^12.1.0",
26
27
  "conf": "^13.0.1",