@wraps.dev/cli 2.12.2 → 2.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -46,10 +46,6 @@ function isCI() {
46
46
  // Azure Pipelines
47
47
  "CODEBUILD_BUILD_ID",
48
48
  // AWS CodeBuild
49
- "NETLIFY",
50
- // Netlify
51
- "VERCEL",
52
- // Vercel
53
49
  "HEROKU_TEST_RUN_ID",
54
50
  // Heroku CI
55
51
  "BUDDY",
@@ -399,7 +395,9 @@ async function readAuthConfig() {
399
395
  async function saveAuthConfig(config2) {
400
396
  await ensureWrapsDir();
401
397
  const path3 = getConfigPath();
402
- await writeFile2(path3, JSON.stringify(config2, null, 2), "utf-8");
398
+ const existing = await readAuthConfig();
399
+ const merged = existing ? { ...existing, ...config2 } : config2;
400
+ await writeFile2(path3, JSON.stringify(merged, null, 2), "utf-8");
403
401
  await chmod(path3, 384);
404
402
  }
405
403
  async function clearAuthConfig() {
@@ -418,7 +416,13 @@ async function resolveTokenAsync(flags2) {
418
416
  return sync;
419
417
  }
420
418
  const config2 = await readAuthConfig();
421
- return config2?.auth?.token || null;
419
+ if (!config2?.auth?.token) {
420
+ return null;
421
+ }
422
+ if (config2.auth.expiresAt && new Date(config2.auth.expiresAt) <= /* @__PURE__ */ new Date()) {
423
+ return null;
424
+ }
425
+ return config2.auth.token;
422
426
  }
423
427
  var CONFIG_FILE;
424
428
  var init_config = __esm({
@@ -674,24 +678,34 @@ var init_client = __esm({
674
678
  await this.flush();
675
679
  }
676
680
  /**
677
- * Enable telemetry
678
- * Note: Won't override environment variable opt-outs (DO_NOT_TRACK, CI, etc.)
681
+ * Enable telemetry.
682
+ * Returns null if enabled, or a string describing why an env override prevented it.
679
683
  */
680
684
  enable() {
681
685
  this.config.setEnabled(true);
682
- if (process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true") {
686
+ const override = this.getEnvOverride();
687
+ if (override) {
683
688
  this.enabled = false;
684
- return;
689
+ return override;
690
+ }
691
+ this.enabled = true;
692
+ return null;
693
+ }
694
+ /**
695
+ * Check if an environment variable is overriding the config.
696
+ * Returns a human-readable reason, or null if no override.
697
+ */
698
+ getEnvOverride() {
699
+ if (process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true") {
700
+ return "DO_NOT_TRACK environment variable is set";
685
701
  }
686
702
  if (process.env.WRAPS_TELEMETRY_DISABLED === "1") {
687
- this.enabled = false;
688
- return;
703
+ return "WRAPS_TELEMETRY_DISABLED environment variable is set";
689
704
  }
690
705
  if (isCI()) {
691
- this.enabled = false;
692
- return;
706
+ return "CI environment detected";
693
707
  }
694
- this.enabled = true;
708
+ return null;
695
709
  }
696
710
  /**
697
711
  * Disable telemetry
@@ -8552,7 +8566,7 @@ async function login(options) {
8552
8566
  });
8553
8567
  trackError("DEVICE_AUTH_FAILED", "auth:login", { step: "request_code" });
8554
8568
  clack.log.error("Failed to start device authorization.");
8555
- process.exit(1);
8569
+ throw new Error("Failed to start device authorization.");
8556
8570
  }
8557
8571
  const {
8558
8572
  device_code,
@@ -8603,6 +8617,10 @@ async function login(options) {
8603
8617
  clack.log.info(`Organization: ${pc2.cyan(organizations[0].name)}`);
8604
8618
  } else if (organizations.length > 1) {
8605
8619
  clack.log.info(`${organizations.length} organizations available`);
8620
+ } else {
8621
+ clack.log.info(
8622
+ `No organizations found. Create one at ${pc2.underline(`${baseURL}/onboarding`)} and run ${pc2.cyan("wraps auth login")} again.`
8623
+ );
8606
8624
  }
8607
8625
  if (options.json) {
8608
8626
  console.log(
@@ -8616,7 +8634,8 @@ async function login(options) {
8616
8634
  return;
8617
8635
  }
8618
8636
  if (tokenError) {
8619
- const errorCode = tokenError.error || tokenError.code;
8637
+ const err = tokenError;
8638
+ const errorCode = err.error || err.code;
8620
8639
  if (errorCode === "authorization_pending") {
8621
8640
  continue;
8622
8641
  }
@@ -8633,7 +8652,7 @@ async function login(options) {
8633
8652
  trackError("ACCESS_DENIED", "auth:login", { step: "poll_token" });
8634
8653
  spinner9.stop("Denied.");
8635
8654
  clack.log.error("Authorization was denied.");
8636
- process.exit(1);
8655
+ throw new Error("Authorization was denied.");
8637
8656
  }
8638
8657
  if (errorCode === "expired_token") {
8639
8658
  break;
@@ -8648,7 +8667,7 @@ async function login(options) {
8648
8667
  trackError("DEVICE_CODE_EXPIRED", "auth:login", { step: "poll_token" });
8649
8668
  spinner9.stop("Expired.");
8650
8669
  clack.log.error("Device code expired. Run `wraps auth login` to try again.");
8651
- process.exit(1);
8670
+ throw new Error("Device code expired.");
8652
8671
  }
8653
8672
 
8654
8673
  // src/commands/auth/logout.ts
@@ -29497,8 +29516,12 @@ async function findExistingPhoneNumber(phoneNumberType) {
29497
29516
  }
29498
29517
  }
29499
29518
  return null;
29500
- } catch {
29501
- return null;
29519
+ } catch (error) {
29520
+ const name = error instanceof Error ? error.name : "";
29521
+ if (name === "ResourceNotFoundException") {
29522
+ return null;
29523
+ }
29524
+ throw error;
29502
29525
  }
29503
29526
  }
29504
29527
  async function createSMSPhoneNumber(phoneNumberType, optOutList) {
@@ -29885,7 +29908,12 @@ async function createSMSPhonePoolWithSDK(phoneNumberArn, region) {
29885
29908
  }
29886
29909
  }
29887
29910
  }
29888
- } catch {
29911
+ } catch (error) {
29912
+ const name = error instanceof Error ? error.name : "";
29913
+ if (name === "ResourceNotFoundException") {
29914
+ } else {
29915
+ throw error;
29916
+ }
29889
29917
  }
29890
29918
  try {
29891
29919
  const response = await client.send(
@@ -29901,8 +29929,12 @@ async function createSMSPhonePoolWithSDK(phoneNumberArn, region) {
29901
29929
  })
29902
29930
  );
29903
29931
  return response.PoolId;
29904
- } catch {
29905
- return;
29932
+ } catch (error) {
29933
+ const name = error instanceof Error ? error.name : "";
29934
+ if (name === "ConflictException") {
29935
+ return;
29936
+ }
29937
+ throw error;
29906
29938
  }
29907
29939
  }
29908
29940
  async function createSMSEventDestinationWithSDK(configurationSetName, snsTopicArn, region) {
@@ -29928,7 +29960,12 @@ async function createSMSEventDestinationWithSDK(configurationSetName, snsTopicAr
29928
29960
  return existingDest.EventDestinationName;
29929
29961
  }
29930
29962
  }
29931
- } catch {
29963
+ } catch (error) {
29964
+ const name = error instanceof Error ? error.name : "";
29965
+ if (name === "ResourceNotFoundException") {
29966
+ } else {
29967
+ throw error;
29968
+ }
29932
29969
  }
29933
29970
  try {
29934
29971
  const response = await client.send(
@@ -29942,8 +29979,12 @@ async function createSMSEventDestinationWithSDK(configurationSetName, snsTopicAr
29942
29979
  })
29943
29980
  );
29944
29981
  return response.EventDestination?.EventDestinationName || eventDestinationName;
29945
- } catch {
29946
- return eventDestinationName;
29982
+ } catch (error) {
29983
+ const name = error instanceof Error ? error.name : "";
29984
+ if (name === "ConflictException") {
29985
+ return eventDestinationName;
29986
+ }
29987
+ throw error;
29947
29988
  }
29948
29989
  }
29949
29990
  async function deleteSMSPhonePoolWithSDK(region) {
@@ -29972,7 +30013,12 @@ async function deleteSMSPhonePoolWithSDK(region) {
29972
30013
  }
29973
30014
  }
29974
30015
  }
29975
- } catch {
30016
+ } catch (error) {
30017
+ const name = error instanceof Error ? error.name : "";
30018
+ if (name === "ResourceNotFoundException") {
30019
+ } else {
30020
+ throw error;
30021
+ }
29976
30022
  }
29977
30023
  }
29978
30024
  async function deleteSMSEventDestinationWithSDK(configurationSetName, region) {
@@ -29986,7 +30032,12 @@ async function deleteSMSEventDestinationWithSDK(configurationSetName, region) {
29986
30032
  EventDestinationName: eventDestinationName
29987
30033
  })
29988
30034
  );
29989
- } catch {
30035
+ } catch (error) {
30036
+ const name = error instanceof Error ? error.name : "";
30037
+ if (name === "ResourceNotFoundException") {
30038
+ } else {
30039
+ throw error;
30040
+ }
29990
30041
  }
29991
30042
  }
29992
30043
  async function createSMSProtectConfigurationWithSDK(configurationSetName, region, options) {
@@ -30021,7 +30072,12 @@ async function createSMSProtectConfigurationWithSDK(configurationSetName, region
30021
30072
  break;
30022
30073
  }
30023
30074
  }
30024
- } catch {
30075
+ } catch (error) {
30076
+ const name = error instanceof Error ? error.name : "";
30077
+ if (name === "ResourceNotFoundException") {
30078
+ } else {
30079
+ throw error;
30080
+ }
30025
30081
  }
30026
30082
  try {
30027
30083
  let protectConfigId = existingProtectConfigId;
@@ -30087,8 +30143,12 @@ async function createSMSProtectConfigurationWithSDK(configurationSetName, region
30087
30143
  );
30088
30144
  }
30089
30145
  return protectConfigId;
30090
- } catch {
30091
- return;
30146
+ } catch (error) {
30147
+ const name = error instanceof Error ? error.name : "";
30148
+ if (name === "ConflictException") {
30149
+ return;
30150
+ }
30151
+ throw error;
30092
30152
  }
30093
30153
  }
30094
30154
  async function deleteSMSProtectConfigurationWithSDK(region) {
@@ -30125,7 +30185,12 @@ async function deleteSMSProtectConfigurationWithSDK(region) {
30125
30185
  }
30126
30186
  }
30127
30187
  }
30128
- } catch {
30188
+ } catch (error) {
30189
+ const name = error instanceof Error ? error.name : "";
30190
+ if (name === "ResourceNotFoundException") {
30191
+ } else {
30192
+ throw error;
30193
+ }
30129
30194
  }
30130
30195
  }
30131
30196
 
@@ -30148,7 +30213,29 @@ async function smsDestroy(options) {
30148
30213
  "Validating AWS credentials",
30149
30214
  async () => validateAWSCredentials()
30150
30215
  );
30151
- const region = await getAWSRegion();
30216
+ let region = options.region || await getAWSRegion();
30217
+ if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
30218
+ const smsConnections = await findConnectionsWithService(
30219
+ identity.accountId,
30220
+ "sms"
30221
+ );
30222
+ if (smsConnections.length === 1) {
30223
+ region = smsConnections[0].region;
30224
+ } else if (smsConnections.length > 1) {
30225
+ const selectedRegion = await clack38.select({
30226
+ message: "Multiple SMS deployments found. Which region to destroy?",
30227
+ options: smsConnections.map((conn) => ({
30228
+ value: conn.region,
30229
+ label: conn.region
30230
+ }))
30231
+ });
30232
+ if (clack38.isCancel(selectedRegion)) {
30233
+ clack38.cancel("Operation cancelled");
30234
+ process.exit(0);
30235
+ }
30236
+ region = selectedRegion;
30237
+ }
30238
+ }
30152
30239
  const metadata = await loadConnectionMetadata(identity.accountId, region);
30153
30240
  const smsService = metadata?.services?.sms;
30154
30241
  const storedStackName = smsService?.pulumiStackName;
@@ -30227,6 +30314,7 @@ async function smsDestroy(options) {
30227
30314
  await progress.execute("Cleaning up protect configuration", async () => {
30228
30315
  await deleteSMSProtectConfigurationWithSDK(region);
30229
30316
  });
30317
+ let destroyFailed = false;
30230
30318
  try {
30231
30319
  await progress.execute(
30232
30320
  "Destroying SMS infrastructure (this may take 2-3 minutes)",
@@ -30242,8 +30330,14 @@ async function smsDestroy(options) {
30242
30330
  } catch (_error) {
30243
30331
  throw new Error("No SMS infrastructure found to destroy");
30244
30332
  }
30245
- await stack.destroy({ onOutput: () => {
30333
+ await stack.refresh({ onOutput: () => {
30246
30334
  } });
30335
+ await withTimeout(
30336
+ stack.destroy({ onOutput: () => {
30337
+ }, continueOnError: true }),
30338
+ DEFAULT_PULUMI_TIMEOUT_MS,
30339
+ "Pulumi destroy"
30340
+ );
30247
30341
  await stack.workspace.removeStack(stackName);
30248
30342
  }
30249
30343
  );
@@ -30263,21 +30357,29 @@ async function smsDestroy(options) {
30263
30357
  throw errors.stackLocked();
30264
30358
  }
30265
30359
  trackError("DESTROY_FAILED", "sms destroy", { step: "destroy" });
30266
- clack38.log.error("SMS infrastructure destruction failed");
30267
- throw new Error(`SMS destruction failed: ${errorMessage}`);
30360
+ destroyFailed = true;
30361
+ clack38.log.warn(
30362
+ "Some resources may not have been fully removed. You can re-run this command or clean up manually in the AWS console."
30363
+ );
30268
30364
  }
30269
30365
  if (metadata) {
30270
30366
  removeServiceFromConnection(metadata, "sms");
30271
30367
  await saveConnectionMetadata(metadata);
30272
30368
  }
30273
30369
  progress.stop();
30274
- clack38.outro(pc41.green("SMS infrastructure has been removed"));
30275
- console.log(`
30370
+ if (destroyFailed) {
30371
+ clack38.outro(
30372
+ pc41.yellow("SMS infrastructure partially removed. Metadata cleaned up.")
30373
+ );
30374
+ } else {
30375
+ clack38.outro(pc41.green("SMS infrastructure has been removed"));
30376
+ console.log(`
30276
30377
  ${pc41.bold("Cleaned up:")}`);
30277
- console.log(` ${pc41.green("\u2713")} Phone number released`);
30278
- console.log(` ${pc41.green("\u2713")} Configuration set deleted`);
30279
- console.log(` ${pc41.green("\u2713")} Event processing infrastructure removed`);
30280
- console.log(` ${pc41.green("\u2713")} IAM role deleted`);
30378
+ console.log(` ${pc41.green("\u2713")} Phone number released`);
30379
+ console.log(` ${pc41.green("\u2713")} Configuration set deleted`);
30380
+ console.log(` ${pc41.green("\u2713")} Event processing infrastructure removed`);
30381
+ console.log(` ${pc41.green("\u2713")} IAM role deleted`);
30382
+ }
30281
30383
  console.log(
30282
30384
  `
30283
30385
  Run ${pc41.cyan("wraps sms init")} to deploy infrastructure again.
@@ -30285,6 +30387,7 @@ Run ${pc41.cyan("wraps sms init")} to deploy infrastructure again.
30285
30387
  );
30286
30388
  trackServiceRemoved("sms", {
30287
30389
  reason: "user_initiated",
30390
+ partial_failure: destroyFailed,
30288
30391
  duration_ms: Date.now() - startTime
30289
30392
  });
30290
30393
  }
@@ -30988,31 +31091,64 @@ ${pc42.yellow(pc42.bold("Important Notes:"))}`);
30988
31091
  };
30989
31092
  }
30990
31093
  );
31094
+ let sdkResourceWarning = false;
30991
31095
  if (outputs.phoneNumberArn) {
30992
- await progress.execute("Creating phone pool", async () => {
30993
- await createSMSPhonePoolWithSDK(outputs.phoneNumberArn, region);
30994
- });
31096
+ try {
31097
+ await progress.execute("Creating phone pool", async () => {
31098
+ await createSMSPhonePoolWithSDK(outputs.phoneNumberArn, region);
31099
+ });
31100
+ } catch (sdkError) {
31101
+ sdkResourceWarning = true;
31102
+ const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
31103
+ clack39.log.warn(`Phone pool creation failed: ${msg}`);
31104
+ clack39.log.info(
31105
+ `Run ${pc42.cyan("wraps sms sync")} to retry SDK resource creation.`
31106
+ );
31107
+ }
30995
31108
  }
30996
31109
  if (smsConfig.eventTracking?.enabled && outputs.configSetName && outputs.snsTopicArn) {
30997
- await progress.execute("Configuring event destination", async () => {
30998
- await createSMSEventDestinationWithSDK(
30999
- outputs.configSetName,
31000
- outputs.snsTopicArn,
31001
- region
31110
+ try {
31111
+ await progress.execute("Configuring event destination", async () => {
31112
+ await createSMSEventDestinationWithSDK(
31113
+ outputs.configSetName,
31114
+ outputs.snsTopicArn,
31115
+ region
31116
+ );
31117
+ });
31118
+ } catch (sdkError) {
31119
+ sdkResourceWarning = true;
31120
+ const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
31121
+ clack39.log.warn(`Event destination creation failed: ${msg}`);
31122
+ clack39.log.info(
31123
+ `Run ${pc42.cyan("wraps sms sync")} to retry SDK resource creation.`
31002
31124
  );
31003
- });
31125
+ }
31004
31126
  }
31005
31127
  if (smsConfig.protectConfiguration?.enabled && outputs.configSetName) {
31006
- await progress.execute("Configuring fraud protection", async () => {
31007
- await createSMSProtectConfigurationWithSDK(
31008
- outputs.configSetName,
31009
- region,
31010
- {
31011
- allowedCountries: smsConfig.protectConfiguration?.allowedCountries,
31012
- aitFiltering: smsConfig.protectConfiguration?.aitFiltering
31013
- }
31128
+ try {
31129
+ await progress.execute("Configuring fraud protection", async () => {
31130
+ await createSMSProtectConfigurationWithSDK(
31131
+ outputs.configSetName,
31132
+ region,
31133
+ {
31134
+ allowedCountries: smsConfig.protectConfiguration?.allowedCountries,
31135
+ aitFiltering: smsConfig.protectConfiguration?.aitFiltering
31136
+ }
31137
+ );
31138
+ });
31139
+ } catch (sdkError) {
31140
+ sdkResourceWarning = true;
31141
+ const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
31142
+ clack39.log.warn(`Protect configuration creation failed: ${msg}`);
31143
+ clack39.log.info(
31144
+ `Run ${pc42.cyan("wraps sms sync")} to retry SDK resource creation.`
31014
31145
  );
31015
- });
31146
+ }
31147
+ }
31148
+ if (sdkResourceWarning) {
31149
+ clack39.log.warn(
31150
+ "Some SDK resources failed to create. Core infrastructure is deployed."
31151
+ );
31016
31152
  }
31017
31153
  } catch (error) {
31018
31154
  trackServiceInit("sms", false, {
@@ -31141,7 +31277,8 @@ async function getPhoneNumberDetails(region) {
31141
31277
  }
31142
31278
  return null;
31143
31279
  } catch (error) {
31144
- console.error("Error fetching phone number:", error);
31280
+ const errorMessage = error instanceof Error ? error.message : String(error);
31281
+ clack40.log.error(`Error fetching phone number: ${errorMessage}`);
31145
31282
  return null;
31146
31283
  }
31147
31284
  }
@@ -31535,7 +31672,7 @@ Run ${pc45.cyan("wraps sms init")} to deploy SMS infrastructure first.
31535
31672
  smsConfig.protectConfiguration = {
31536
31673
  enabled: true,
31537
31674
  allowedCountries: ["US"],
31538
- aitFiltering: true
31675
+ aitFiltering: false
31539
31676
  };
31540
31677
  }
31541
31678
  }
@@ -31585,9 +31722,14 @@ import {
31585
31722
  } from "@aws-sdk/client-pinpoint-sms-voice-v2";
31586
31723
  import * as clack43 from "@clack/prompts";
31587
31724
  import pc46 from "picocolors";
31725
+
31726
+ // src/utils/sms/validation.ts
31727
+ init_esm_shims();
31588
31728
  function isValidPhoneNumber(phone) {
31589
31729
  return /^\+[1-9]\d{1,14}$/.test(phone);
31590
31730
  }
31731
+
31732
+ // src/commands/sms/test.ts
31591
31733
  var SIMULATOR_DESTINATIONS = [
31592
31734
  { number: "+14254147755", country: "United States (US)" },
31593
31735
  { number: "+447860019066", country: "United Kingdom (GB)" },
@@ -31757,18 +31899,39 @@ Run ${pc46.cyan("wraps sms init")} to deploy SMS infrastructure.
31757
31899
  error: errorMessage,
31758
31900
  duration_ms: Date.now() - startTime
31759
31901
  });
31760
- if (errorMessage.includes("not verified")) {
31902
+ const errorName = error instanceof Error ? error.name : "";
31903
+ if (errorName === "ConflictException" || errorMessage.includes("opt-out")) {
31904
+ clack43.log.error("Destination number has opted out of messages");
31905
+ console.log(
31906
+ `
31907
+ The recipient has opted out of receiving SMS messages.
31908
+ `
31909
+ );
31910
+ } else if (errorName === "ThrottlingException" || errorMessage.includes("spending limit")) {
31911
+ clack43.log.error("SMS rate or spending limit reached");
31912
+ console.log(
31913
+ `
31914
+ Check your AWS account SMS spending limits in the console.
31915
+ `
31916
+ );
31917
+ } else if (errorName === "ValidationException") {
31918
+ clack43.log.error(`Invalid request: ${errorMessage}`);
31919
+ } else if (errorMessage.includes("not verified") || errorMessage.includes("not registered")) {
31761
31920
  clack43.log.error("Toll-free number registration is not complete");
31762
31921
  console.log(
31763
31922
  `
31764
- Run ${pc46.cyan("wraps sms register")} to complete registration.
31923
+ Run ${pc46.cyan("wraps sms register")} to check registration status.
31924
+ `
31925
+ );
31926
+ } else if (errorName === "AccessDeniedException") {
31927
+ clack43.log.error(
31928
+ "Permission denied \u2014 IAM role may be missing SMS send permissions"
31929
+ );
31930
+ console.log(
31931
+ `
31932
+ Run ${pc46.cyan("wraps sms upgrade")} to update IAM policies.
31765
31933
  `
31766
31934
  );
31767
- } else if (errorMessage.includes("opt-out")) {
31768
- clack43.log.error("Destination number has opted out of messages");
31769
- } else if (errorMessage.includes("spending limit")) {
31770
- clack43.log.error("AWS SMS spending limit reached");
31771
- console.log("\nVisit the AWS console to increase your spending limit.\n");
31772
31935
  } else {
31773
31936
  clack43.log.error(`Failed to send SMS: ${errorMessage}`);
31774
31937
  }
@@ -32721,9 +32884,6 @@ import {
32721
32884
  } from "@aws-sdk/client-pinpoint-sms-voice-v2";
32722
32885
  import * as clack45 from "@clack/prompts";
32723
32886
  import pc48 from "picocolors";
32724
- function isValidPhoneNumber2(phone) {
32725
- return /^\+[1-9]\d{1,14}$/.test(phone);
32726
- }
32727
32887
  async function smsVerifyNumber(options) {
32728
32888
  const startTime = Date.now();
32729
32889
  const progress = new DeploymentProgress();
@@ -32844,7 +33004,7 @@ Usage: ${pc48.cyan("wraps sms verify-number --delete --phone-number +14155551234
32844
33004
  if (!value) {
32845
33005
  return "Phone number is required";
32846
33006
  }
32847
- if (!isValidPhoneNumber2(value)) {
33007
+ if (!isValidPhoneNumber(value)) {
32848
33008
  return "Please enter a valid phone number in E.164 format (e.g., +14155551234)";
32849
33009
  }
32850
33010
  return;
@@ -32855,7 +33015,7 @@ Usage: ${pc48.cyan("wraps sms verify-number --delete --phone-number +14155551234
32855
33015
  process.exit(0);
32856
33016
  }
32857
33017
  phoneNumber = result;
32858
- } else if (!isValidPhoneNumber2(phoneNumber)) {
33018
+ } else if (!isValidPhoneNumber(phoneNumber)) {
32859
33019
  progress.stop();
32860
33020
  clack45.log.error(
32861
33021
  `Invalid phone number format: ${phoneNumber}. Use E.164 format (e.g., +14155551234)`
@@ -33088,12 +33248,21 @@ import * as clack47 from "@clack/prompts";
33088
33248
  import pc50 from "picocolors";
33089
33249
  async function telemetryEnable() {
33090
33250
  const client = getTelemetryClient();
33091
- client.enable();
33092
- clack47.log.success(pc50.green("Telemetry enabled"));
33093
- console.log(` Config: ${pc50.dim(client.getConfigPath())}`);
33094
- console.log(`
33251
+ const override = client.enable();
33252
+ if (override) {
33253
+ clack47.log.warn(
33254
+ "Telemetry enabled in config, but overridden by environment"
33255
+ );
33256
+ console.log(` Reason: ${pc50.yellow(override)}`);
33257
+ console.log(` Config: ${pc50.dim(client.getConfigPath())}`);
33258
+ console.log();
33259
+ } else {
33260
+ clack47.log.success(pc50.green("Telemetry enabled"));
33261
+ console.log(` Config: ${pc50.dim(client.getConfigPath())}`);
33262
+ console.log(`
33095
33263
  ${pc50.dim("Thank you for helping improve Wraps!")}
33096
33264
  `);
33265
+ }
33097
33266
  }
33098
33267
  async function telemetryDisable() {
33099
33268
  const client = getTelemetryClient();
@@ -33109,9 +33278,13 @@ async function telemetryDisable() {
33109
33278
  async function telemetryStatus() {
33110
33279
  const client = getTelemetryClient();
33111
33280
  clack47.intro(pc50.bold("Telemetry Status"));
33281
+ const override = client.getEnvOverride();
33112
33282
  const status2 = client.isEnabled() ? pc50.green("Enabled") : pc50.red("Disabled");
33113
33283
  console.log();
33114
33284
  console.log(` ${pc50.bold("Status:")} ${status2}`);
33285
+ if (!client.isEnabled() && override) {
33286
+ console.log(` ${pc50.bold("Reason:")} ${pc50.yellow(override)}`);
33287
+ }
33115
33288
  console.log(` ${pc50.bold("Config file:")} ${pc50.dim(client.getConfigPath())}`);
33116
33289
  if (client.isEnabled()) {
33117
33290
  console.log();
@@ -34108,7 +34281,8 @@ Run ${pc51.cyan("wraps --help")} for available commands.
34108
34281
  case "destroy":
34109
34282
  await smsDestroy({
34110
34283
  force: flags.force,
34111
- preview: flags.preview
34284
+ preview: flags.preview,
34285
+ region: flags.region
34112
34286
  });
34113
34287
  break;
34114
34288
  case "verify-number":
@@ -34268,12 +34442,6 @@ Available commands: ${pc51.cyan("login")}, ${pc51.cyan("status")}, ${pc51.cyan("
34268
34442
  );
34269
34443
  throw new Error(`Unknown auth command: ${subCommand || "(none)"}`);
34270
34444
  }
34271
- const authDuration = Date.now() - startTime;
34272
- const authCommandName = `auth:${subCommand}`;
34273
- trackCommand(authCommandName, {
34274
- success: true,
34275
- duration_ms: authDuration
34276
- });
34277
34445
  return;
34278
34446
  }
34279
34447
  if (primaryCommand === "aws" && subCommand) {