@dropthis/cli 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -29,6 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
30
  mod
31
31
  ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
33
 
33
34
  // src/inline-auth.ts
34
35
  var inline_auth_exports = {};
@@ -150,42 +151,12 @@ var init_inline_auth = __esm({
150
151
  }
151
152
  });
152
153
 
153
- // src/program.ts
154
- var import_commander = require("commander");
155
- var import_picocolors4 = __toESM(require("picocolors"), 1);
156
-
157
- // src/auth.ts
158
- async function resolveCredential(input) {
159
- if (input.apiKey) return { apiKey: input.apiKey, source: "flag" };
160
- if (input.env.DROPTHIS_API_KEY) {
161
- return { apiKey: input.env.DROPTHIS_API_KEY, source: "env" };
162
- }
163
- const stored = await input.store.read();
164
- if (!stored) return null;
165
- return {
166
- apiKey: stored.apiKey,
167
- source: "storage",
168
- ...stored.keyId ? { keyId: stored.keyId } : {},
169
- ...stored.keyLast4 ? { keyLast4: stored.keyLast4 } : {},
170
- ...stored.accountId ? { accountId: stored.accountId } : {},
171
- ...stored.email ? { email: stored.email } : {}
172
- };
173
- }
174
- async function requireCredential(input) {
175
- const credential = await resolveCredential(input);
176
- if (!credential) {
177
- throw Object.assign(new Error("No API key found."), {
178
- code: "auth_error"
179
- });
180
- }
181
- return credential;
182
- }
183
- function maskKey(apiKey) {
184
- return apiKey.length <= 8 ? "sk_..." : `${apiKey.slice(0, 3)}...${apiKey.slice(-4)}`;
185
- }
186
-
187
- // src/fmt.ts
188
- var import_picocolors2 = __toESM(require("picocolors"), 1);
154
+ // src/cli.ts
155
+ var cli_exports = {};
156
+ __export(cli_exports, {
157
+ writeUsageErrorEnvelope: () => writeUsageErrorEnvelope
158
+ });
159
+ module.exports = __toCommonJS(cli_exports);
189
160
 
190
161
  // src/output.ts
191
162
  var UPLOAD_NEXT_ACTIONS = {
@@ -213,7 +184,7 @@ function apiErrorEnvelope(error2) {
213
184
  return {
214
185
  ok: false,
215
186
  error: {
216
- code: error2.code ?? "api_error",
187
+ code: normalizeApiErrorCode(error2),
217
188
  message: error2.message,
218
189
  ...error2.statusCode !== void 0 ? { status: error2.statusCode } : {},
219
190
  ...typeof error2.detail === "string" ? { detail: error2.detail } : {},
@@ -226,6 +197,11 @@ function apiErrorEnvelope(error2) {
226
197
  }
227
198
  };
228
199
  }
200
+ function normalizeApiErrorCode(error2) {
201
+ if (error2.code) return error2.code;
202
+ if (error2.statusCode === 404) return "not_found";
203
+ return "api_error";
204
+ }
229
205
  function nextActionForApiError(error2) {
230
206
  if (error2.suggestion) return error2.suggestion;
231
207
  const uploadNextAction = error2.code ? UPLOAD_NEXT_ACTIONS[error2.code] : void 0;
@@ -233,6 +209,9 @@ function nextActionForApiError(error2) {
233
209
  if (error2.code === "revision_conflict") {
234
210
  return "Fetch the drop, merge your changes, and retry with the current revision.";
235
211
  }
212
+ if (error2.statusCode === 404 || error2.code === "not_found") {
213
+ return "Check the drop id or slug and retry; list your drops with dropthis drops list.";
214
+ }
236
215
  if (error2.statusCode === 401 || error2.code === "missing_api_key") {
237
216
  return "Authenticate with dropthis login or set DROPTHIS_API_KEY.";
238
217
  }
@@ -248,6 +227,7 @@ function nextActionForApiError(error2) {
248
227
  return "Fix the request or retry after checking the drop state.";
249
228
  }
250
229
  function exitCodeFor(code) {
230
+ if (code === "usage_error") return 2;
251
231
  if (code === "invalid_usage") return 2;
252
232
  if (code === "auth_error") return 3;
253
233
  if (code === "local_input_error") return 4;
@@ -255,6 +235,43 @@ function exitCodeFor(code) {
255
235
  return 1;
256
236
  }
257
237
 
238
+ // src/program.ts
239
+ var import_commander = require("commander");
240
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
241
+
242
+ // src/auth.ts
243
+ async function resolveCredential(input) {
244
+ if (input.apiKey) return { apiKey: input.apiKey, source: "flag" };
245
+ if (input.env.DROPTHIS_API_KEY) {
246
+ return { apiKey: input.env.DROPTHIS_API_KEY, source: "env" };
247
+ }
248
+ const stored = await input.store.read();
249
+ if (!stored) return null;
250
+ return {
251
+ apiKey: stored.apiKey,
252
+ source: "storage",
253
+ ...stored.keyId ? { keyId: stored.keyId } : {},
254
+ ...stored.keyLast4 ? { keyLast4: stored.keyLast4 } : {},
255
+ ...stored.accountId ? { accountId: stored.accountId } : {},
256
+ ...stored.email ? { email: stored.email } : {}
257
+ };
258
+ }
259
+ async function requireCredential(input) {
260
+ const credential = await resolveCredential(input);
261
+ if (!credential) {
262
+ throw Object.assign(new Error("No API key found."), {
263
+ code: "auth_error"
264
+ });
265
+ }
266
+ return credential;
267
+ }
268
+ function maskKey(apiKey) {
269
+ return apiKey.length <= 8 ? "sk_..." : `${apiKey.slice(0, 3)}...${apiKey.slice(-4)}`;
270
+ }
271
+
272
+ // src/fmt.ts
273
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
274
+
258
275
  // src/ui.ts
259
276
  var import_picocolors = __toESM(require("picocolors"), 1);
260
277
  var symbols = {
@@ -295,13 +312,13 @@ function writeResult(deps, link, verb, data) {
295
312
  }
296
313
  function formatDropDetails(data) {
297
314
  const parts = [];
298
- const size = data.sizeBytes ?? data.size_bytes;
315
+ const size = data.sizeBytes;
299
316
  if (typeof size === "number") parts.push(formatBytes(size));
300
- const ct = data.contentType ?? data.content_type;
317
+ const ct = data.contentType;
301
318
  if (typeof ct === "string") parts.push(ct.split(";")[0]);
302
319
  const vis = data.visibility;
303
320
  if (vis === "unlisted") parts.push("unlisted");
304
- const exp = data.expiresAt ?? data.expires_at;
321
+ const exp = data.expiresAt;
305
322
  if (typeof exp === "string") parts.push(`expires ${exp.split("T")[0]}`);
306
323
  if (parts.length === 0) return "";
307
324
  return ` ${import_picocolors2.default.dim(parts.join(" \xB7 "))}`;
@@ -404,16 +421,66 @@ async function runAccountGet(_input, deps) {
404
421
  }
405
422
  const result = await deps.client.account.get();
406
423
  if (result.error) {
407
- return writeApiErrorSimple(deps, result.error.message);
424
+ return writeApiError(deps, result.error);
408
425
  }
409
426
  const data = result.data;
410
427
  const pairs = [];
411
428
  if (data?.id) pairs.push(["ID", String(data.id)]);
412
429
  if (data?.email) pairs.push(["Email", String(data.email)]);
413
430
  if (data?.plan) pairs.push(["Plan", String(data.plan)]);
431
+ if (data?.displayName) pairs.push(["Name", String(data.displayName)]);
432
+ if (data?.status) pairs.push(["Status", String(data.status)]);
433
+ if (data?.createdAt)
434
+ pairs.push(["Created", String(data.createdAt).split("T")[0]]);
435
+ writeKv(deps, pairs, { ok: true, account: result.data });
436
+ return { exitCode: 0 };
437
+ }
438
+ async function runAccountUpdate(input, deps) {
439
+ try {
440
+ await requireCredential({
441
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
442
+ env: deps.env,
443
+ store: deps.store
444
+ });
445
+ } catch {
446
+ return writeAuthError(deps);
447
+ }
448
+ const result = await deps.client.account.update({
449
+ displayName: input.displayName
450
+ });
451
+ if (result.error) return writeApiError(deps, result.error);
452
+ const data = result.data;
453
+ const pairs = [];
454
+ if (data?.id) pairs.push(["ID", String(data.id)]);
455
+ if (data?.displayName) pairs.push(["Name", String(data.displayName)]);
414
456
  writeKv(deps, pairs, { ok: true, account: result.data });
415
457
  return { exitCode: 0 };
416
458
  }
459
+ async function runAccountDelete(input, deps) {
460
+ if (!input.yes && input.interactive === false) {
461
+ return writeError(
462
+ deps,
463
+ "invalid_usage",
464
+ "Pass --yes to delete the account in non-interactive mode."
465
+ );
466
+ }
467
+ try {
468
+ await requireCredential({
469
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
470
+ env: deps.env,
471
+ store: deps.store
472
+ });
473
+ } catch {
474
+ return writeAuthError(deps);
475
+ }
476
+ const result = await deps.client.account.delete();
477
+ if (result.error) return writeApiError(deps, result.error);
478
+ writeHumanOrJson(deps, success("Account deleted"), {
479
+ ok: true,
480
+ deleted: true
481
+ });
482
+ return { exitCode: 0 };
483
+ }
417
484
 
418
485
  // src/commands/api-keys.ts
419
486
  var prompts = __toESM(require("@clack/prompts"), 1);
@@ -445,12 +512,12 @@ async function runApiKeysCreate(input, deps) {
445
512
  return writeAuthError(deps);
446
513
  }
447
514
  const result = await deps.client.apiKeys.create({ label: input.label });
448
- if (result.error) return writeApiErrorSimple(deps, result.error.message);
515
+ if (result.error) return writeApiError(deps, result.error);
449
516
  const data = result.data;
450
517
  const pairs = [];
451
518
  if (data.id) pairs.push(["ID", String(data.id)]);
452
519
  if (data.key) pairs.push(["Key", String(data.key)]);
453
- if (data.last4) pairs.push(["Last 4", String(data.last4)]);
520
+ if (data.keyLast4) pairs.push(["Last 4", String(data.keyLast4)]);
454
521
  writeKv(deps, pairs, { ok: true, api_key: result.data });
455
522
  return { exitCode: 0 };
456
523
  }
@@ -465,8 +532,8 @@ async function runApiKeysList(_input, deps) {
465
532
  return writeAuthError(deps);
466
533
  }
467
534
  const result = await deps.client.apiKeys.list();
468
- if (result.error) return writeApiErrorSimple(deps, result.error.message);
469
- const raw = unwrapListData(result.data, "apiKeys", "api_keys");
535
+ if (result.error) return writeApiError(deps, result.error);
536
+ const raw = unwrapListData(result.data);
470
537
  const items = Array.isArray(raw) ? raw : void 0;
471
538
  if (deps.outputMode === "human") {
472
539
  if (!items || items.length === 0) {
@@ -474,7 +541,7 @@ async function runApiKeysList(_input, deps) {
474
541
  } else {
475
542
  for (const item of items) {
476
543
  deps.stdout(
477
- `${item.id ?? ""} ${item.label ?? ""} ...${item.last4 ?? ""}
544
+ `${item.id ?? ""} ${item.label ?? ""} ...${item.keyLast4 ?? ""}
478
545
  `
479
546
  );
480
547
  }
@@ -510,7 +577,7 @@ async function runApiKeysDelete(keyId, input, deps) {
510
577
  return writeAuthError(deps);
511
578
  }
512
579
  const result = await deps.client.apiKeys.delete(keyId);
513
- if (result?.error) return writeApiErrorSimple(deps, result.error.message);
580
+ if (result?.error) return writeApiError(deps, result.error);
514
581
  writeHumanOrJson(deps, success(`Deleted ${keyId}`), {
515
582
  ok: true,
516
583
  deleted: true,
@@ -520,12 +587,9 @@ async function runApiKeysDelete(keyId, input, deps) {
520
587
  }
521
588
 
522
589
  // src/catalog.ts
523
- var COMMAND_CATALOG = [
524
- {
525
- name: "publish",
526
- description: "Publish an input and return a Dropthis URL.",
527
- arguments: ["input"],
528
- options: ["--json", "--url", "--dry-run", "--title", "--metadata"],
590
+ var COMMAND_ANNOTATIONS = {
591
+ publish: {
592
+ auth: "required",
529
593
  examples: [
530
594
  "dropthis ./file.html",
531
595
  "dropthis publish ./site --json",
@@ -533,69 +597,70 @@ var COMMAND_CATALOG = [
533
597
  "dropthis publish ./dist --dry-run"
534
598
  ]
535
599
  },
536
- {
537
- name: "deployments list <dropId>",
538
- description: "List deployments for a drop.",
539
- arguments: ["dropId"],
540
- options: ["--json", "--limit", "--cursor"],
541
- auth: "required",
542
- examples: ["dropthis deployments list drop_abc --json"]
543
- },
544
- {
545
- name: "deployments get <dropId> <deploymentId>",
546
- description: "Get deployment details for a drop.",
547
- arguments: ["dropId", "deploymentId"],
548
- options: ["--json"],
600
+ drops: {
549
601
  auth: "required",
550
- examples: ["dropthis deployments get drop_abc dep_abc --json"]
551
- },
552
- {
553
- name: "drops",
554
- description: "List, inspect, update, and delete drops.",
555
602
  examples: [
556
603
  "dropthis drops list --json",
557
604
  "dropthis drops update drop_abc ./site --json",
558
605
  "dropthis drops update drop_abc --title 'New Title' --dry-run"
559
606
  ]
560
607
  },
561
- {
562
- name: "api-keys",
563
- description: "Create, list, and delete API keys.",
608
+ deployments: { auth: "required" },
609
+ "deployments list": {
610
+ auth: "required",
611
+ examples: ["dropthis deployments list drop_abc --json"]
612
+ },
613
+ "deployments get": {
614
+ auth: "required",
615
+ examples: ["dropthis deployments get drop_abc dep_abc --json"]
616
+ },
617
+ "api-keys": {
618
+ auth: "required",
564
619
  examples: ["dropthis api-keys create --label CI --json"]
565
620
  },
566
- {
567
- name: "login",
568
- description: "Authenticate with email OTP and store an API key.",
621
+ login: {
569
622
  examples: [
570
623
  "dropthis login verify --email user@example.com --otp 123456 --json"
571
624
  ]
572
625
  },
573
- {
574
- name: "logout",
575
- description: "Remove stored local credentials.",
576
- examples: ["dropthis logout --json"]
577
- },
578
- {
579
- name: "whoami",
580
- description: "Show current auth source and credential metadata.",
581
- examples: ["dropthis whoami --json"]
582
- },
583
- {
584
- name: "account",
585
- description: "Get account details.",
586
- examples: ["dropthis account --json"]
626
+ logout: { examples: ["dropthis logout --json"] },
627
+ whoami: { auth: "required", examples: ["dropthis whoami --json"] },
628
+ account: { auth: "required", examples: ["dropthis account --json"] },
629
+ "account get": { auth: "required" },
630
+ "account update": {
631
+ auth: "required",
632
+ examples: ["dropthis account update --display-name 'Ada' --json"]
587
633
  },
588
- {
589
- name: "doctor",
590
- description: "Report local CLI diagnostics.",
591
- examples: ["dropthis doctor --json"]
634
+ "account delete": {
635
+ auth: "required",
636
+ examples: ["dropthis account delete --yes --json"]
592
637
  },
593
- {
594
- name: "commands",
595
- description: "Print this machine-readable command tree.",
596
- examples: ["dropthis commands --json"]
597
- }
598
- ];
638
+ doctor: { examples: ["dropthis doctor --json"] },
639
+ commands: { examples: ["dropthis commands --json"] }
640
+ };
641
+ function describeArgs(cmd) {
642
+ return cmd.registeredArguments.map((a) => a.name());
643
+ }
644
+ function describeOptions(cmd) {
645
+ return cmd.options.map((o) => o.long ?? o.short ?? o.flags);
646
+ }
647
+ function toEntry(cmd, path) {
648
+ const fullPath = [...path, cmd.name()];
649
+ const annotation = COMMAND_ANNOTATIONS[fullPath.join(" ")];
650
+ const subs = cmd.commands.map((sub) => toEntry(sub, fullPath));
651
+ return {
652
+ name: cmd.name(),
653
+ description: cmd.description(),
654
+ ...describeArgs(cmd).length ? { arguments: describeArgs(cmd) } : {},
655
+ ...describeOptions(cmd).length ? { options: describeOptions(cmd) } : {},
656
+ ...annotation?.auth ? { auth: annotation.auth } : {},
657
+ ...annotation?.examples ? { examples: annotation.examples } : {},
658
+ ...subs.length ? { subcommands: subs } : {}
659
+ };
660
+ }
661
+ function buildCatalog(program) {
662
+ return program.commands.map((cmd) => toEntry(cmd, []));
663
+ }
599
664
 
600
665
  // src/commands/commands.ts
601
666
  async function runCommands(_input, deps) {
@@ -603,7 +668,7 @@ async function runCommands(_input, deps) {
603
668
  `${JSON.stringify({
604
669
  ok: true,
605
670
  output: "JSON by default in CI, pipes, non-TTY, --json, or --quiet.",
606
- commands: COMMAND_CATALOG
671
+ commands: buildCatalog(deps.program)
607
672
  })}
608
673
  `
609
674
  );
@@ -640,7 +705,7 @@ async function runDeploymentsList(dropId, input, deps) {
640
705
  } else if (Array.isArray(items)) {
641
706
  for (const item of items) {
642
707
  deps.stdout(
643
- `${item.id ?? ""} rev ${item.revision ?? "?"} ${item.created_at ?? ""}
708
+ `${item.id ?? ""} rev ${item.revision ?? "?"} ${item.createdAt ?? ""}
644
709
  `
645
710
  );
646
711
  }
@@ -671,7 +736,7 @@ async function runDeploymentsGet(dropId, deploymentId, _input, deps) {
671
736
  if (data.id) pairs.push(["ID", String(data.id)]);
672
737
  if (data.revision !== void 0)
673
738
  pairs.push(["Revision", String(data.revision)]);
674
- if (data.created_at) pairs.push(["Created", String(data.created_at)]);
739
+ if (data.createdAt) pairs.push(["Created", String(data.createdAt)]);
675
740
  writeKv(deps, pairs, { ok: true, deployment: result.data });
676
741
  return { exitCode: 0 };
677
742
  }
@@ -689,13 +754,13 @@ async function runDoctor(_input, deps) {
689
754
  const authSource = credential?.source ?? "missing";
690
755
  const storageBackend = stored?.storage ?? "none";
691
756
  const pairs = [
692
- ["Version", "0.5.0"],
757
+ ["Version", "0.6.0"],
693
758
  ["Auth", authSource],
694
759
  ["Storage", storageBackend]
695
760
  ];
696
761
  writeKv(deps, pairs, {
697
762
  ok: true,
698
- version: "0.5.0",
763
+ version: "0.6.0",
699
764
  auth: { source: authSource },
700
765
  storage: { backend: storageBackend }
701
766
  });
@@ -719,7 +784,7 @@ async function runDropsList(input, deps) {
719
784
  ...input.cursor ? { cursor: input.cursor } : {}
720
785
  };
721
786
  const result = await deps.client.drops.list(params);
722
- if (result.error) return writeApiErrorSimple(deps, result.error.message);
787
+ if (result.error) return writeApiError(deps, result.error);
723
788
  const raw = unwrapListData(result.data, "drops");
724
789
  const items = Array.isArray(raw) ? raw : void 0;
725
790
  if (deps.outputMode === "human") {
@@ -749,7 +814,7 @@ async function runDropsGet(dropId, _input, deps) {
749
814
  return writeAuthError(deps);
750
815
  }
751
816
  const result = await deps.client.drops.get(dropId);
752
- if (result.error) return writeApiErrorSimple(deps, result.error.message);
817
+ if (result.error) return writeApiError(deps, result.error);
753
818
  const data = result.data;
754
819
  const pairs = [];
755
820
  if (data.id) pairs.push(["ID", String(data.id)]);
@@ -758,7 +823,7 @@ async function runDropsGet(dropId, _input, deps) {
758
823
  if (data.visibility) pairs.push(["Visibility", String(data.visibility)]);
759
824
  if (data.revision !== void 0)
760
825
  pairs.push(["Revision", String(data.revision)]);
761
- if (data.created_at) pairs.push(["Created", String(data.created_at)]);
826
+ if (data.createdAt) pairs.push(["Created", String(data.createdAt)]);
762
827
  if (data.accessible !== void 0)
763
828
  pairs.push(["Accessible", String(data.accessible)]);
764
829
  if (data.persistent !== void 0)
@@ -794,7 +859,7 @@ async function runDropsDelete(dropId, input, deps) {
794
859
  return writeAuthError(deps);
795
860
  }
796
861
  const result = await deps.client.drops.delete(dropId);
797
- if (result?.error) return writeApiErrorSimple(deps, result.error.message);
862
+ if (result?.error) return writeApiError(deps, result.error);
798
863
  writeHumanOrJson(deps, success(`Deleted ${dropId}`), {
799
864
  ok: true,
800
865
  deleted: true,
@@ -946,51 +1011,16 @@ async function runLogout(input, deps) {
946
1011
  return { exitCode: 0 };
947
1012
  }
948
1013
 
949
- // src/commands/publish.ts
950
- var import_promises3 = require("fs/promises");
951
- var import_node_path2 = require("path");
952
-
953
1014
  // src/drop-operations.ts
954
1015
  var import_node_crypto = require("crypto");
955
- var import_node_path = require("path");
956
1016
  var MAX_BUNDLE_FILE_COUNT = 200;
957
1017
  function isFileSystemError(error2) {
958
1018
  if (!(error2 instanceof Error)) return false;
959
1019
  const code = error2.code;
960
1020
  return code === "ENOENT" || code === "ENOTDIR" || code === "EACCES" || code === "ELIMIT";
961
1021
  }
962
- function mimeForPath(filePath) {
963
- const ext = (0, import_node_path.extname)(filePath).toLowerCase();
964
- const types = {
965
- ".html": "text/html",
966
- ".htm": "text/html",
967
- ".css": "text/css",
968
- ".js": "text/javascript",
969
- ".mjs": "text/javascript",
970
- ".json": "application/json",
971
- ".xml": "application/xml",
972
- ".svg": "image/svg+xml",
973
- ".txt": "text/plain",
974
- ".md": "text/markdown",
975
- ".jpg": "image/jpeg",
976
- ".jpeg": "image/jpeg",
977
- ".png": "image/png",
978
- ".gif": "image/gif",
979
- ".webp": "image/webp",
980
- ".ico": "image/x-icon",
981
- ".avif": "image/avif",
982
- ".pdf": "application/pdf",
983
- ".zip": "application/zip",
984
- ".woff": "font/woff",
985
- ".woff2": "font/woff2",
986
- ".ttf": "font/ttf",
987
- ".mp4": "video/mp4",
988
- ".webm": "video/webm"
989
- };
990
- return types[ext] ?? "application/octet-stream";
991
- }
992
- function withIdempotencyKey(options, prefix) {
993
- return options.idempotencyKey ? options : { ...options, idempotencyKey: `cli_${prefix}_${(0, import_node_crypto.randomUUID)()}` };
1022
+ function withIdempotencyKey(options, _prefix) {
1023
+ return options.idempotencyKey ? options : { ...options, idempotencyKey: (0, import_node_crypto.randomUUID)() };
994
1024
  }
995
1025
  function validateManifestFileCount(count) {
996
1026
  if (count > MAX_BUNDLE_FILE_COUNT) {
@@ -1003,11 +1033,23 @@ function validateManifestFileCount(count) {
1003
1033
  }
1004
1034
  }
1005
1035
  function formatDryRunManifest(prepared, extra) {
1036
+ if (prepared.kind === "source") {
1037
+ return {
1038
+ ok: true,
1039
+ dryRun: true,
1040
+ kind: "source",
1041
+ ...extra,
1042
+ sourceUrl: prepared.sourceUrl,
1043
+ options: prepared.options,
1044
+ ...prepared.metadata ? { metadata: prepared.metadata } : {}
1045
+ };
1046
+ }
1006
1047
  const totalBytes = prepared.manifest.files.reduce(
1007
1048
  (sum, f) => sum + f.sizeBytes,
1008
1049
  0
1009
1050
  );
1010
1051
  return {
1052
+ ok: true,
1011
1053
  dryRun: true,
1012
1054
  kind: "staged",
1013
1055
  ...extra,
@@ -1020,15 +1062,6 @@ function formatDryRunManifest(prepared, extra) {
1020
1062
  totalBytes
1021
1063
  };
1022
1064
  }
1023
- function dryRunOptionsBody(options) {
1024
- const result = {};
1025
- if (options.title) result.title = options.title;
1026
- if (options.visibility) result.visibility = options.visibility;
1027
- if (options.password !== void 0) result.password = options.password;
1028
- if (options.noindex !== void 0) result.noindex = options.noindex;
1029
- if (options.expiresAt) result.expires_at = options.expiresAt;
1030
- return result;
1031
- }
1032
1065
 
1033
1066
  // src/options.ts
1034
1067
  var import_promises = require("fs/promises");
@@ -1156,16 +1189,16 @@ async function runPublish(input, raw, deps) {
1156
1189
  if (raw.dryRun) {
1157
1190
  return handlePublishDryRun(input, raw, deps, client);
1158
1191
  }
1159
- const singleInput = Array.isArray(input) ? input[0] : input;
1192
+ const hasInput = Array.isArray(input) ? input.length > 0 : input !== void 0;
1160
1193
  const spin = shouldSpin(deps.outputMode) ? createSpinner("Publishing\u2026", deps.stderr) : void 0;
1161
1194
  try {
1162
- if (raw.fromJson && singleInput) {
1195
+ if (raw.fromJson && hasInput) {
1163
1196
  throw new Error("Use either <input> or --from-json, not both.");
1164
1197
  }
1165
1198
  const options = withIdempotencyKey(await parseDropOptions(raw), "pub");
1166
1199
  const jsonBody = raw.fromJson ? await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson) : void 0;
1167
1200
  const idempotencyOpt = options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {};
1168
- const doPublish = (c) => jsonBody ? c.drops.createRaw(jsonBody, idempotencyOpt) : singleInput ? c.publish(singleInput, options) : (() => {
1201
+ const doPublish = (c) => jsonBody ? c.drops.createRaw(jsonBody, idempotencyOpt) : hasInput ? c.publish(input, options) : (() => {
1169
1202
  throw new Error("Publish requires <input> or --from-json.");
1170
1203
  })();
1171
1204
  const result = await doPublish(client);
@@ -1233,7 +1266,7 @@ async function handlePublishDryRun(input, raw, deps, client) {
1233
1266
  raw.fromJson
1234
1267
  );
1235
1268
  deps.stdout(
1236
- `${JSON.stringify({ dryRun: true, kind: "raw_json", endpoint: "POST /drops", body }, null, 2)}
1269
+ `${JSON.stringify({ ok: true, dryRun: true, kind: "raw_json", endpoint: "POST /drops", body }, null, 2)}
1237
1270
  `
1238
1271
  );
1239
1272
  return { exitCode: 0 };
@@ -1242,17 +1275,14 @@ async function handlePublishDryRun(input, raw, deps, client) {
1242
1275
  throw new Error("Publish requires <input> or --from-json.");
1243
1276
  }
1244
1277
  const options = await parseDropOptions(raw);
1245
- if (Array.isArray(input)) {
1246
- return dryRunMultiFile(input, options, deps);
1247
- }
1248
1278
  if (!client.prepare) {
1249
1279
  throw new Error("Client does not support dry-run.");
1250
1280
  }
1251
1281
  const prepared = await client.prepare(input, options);
1252
1282
  const output = formatDryRunManifest(prepared);
1253
- validateManifestFileCount(
1254
- output.manifest.files.length
1255
- );
1283
+ if (prepared.kind === "staged") {
1284
+ validateManifestFileCount(prepared.manifest.files.length);
1285
+ }
1256
1286
  deps.stdout(`${JSON.stringify(output, null, 2)}
1257
1287
  `);
1258
1288
  return { exitCode: 0 };
@@ -1262,46 +1292,6 @@ async function handlePublishDryRun(input, raw, deps, client) {
1262
1292
  return writeError(deps, code, message);
1263
1293
  }
1264
1294
  }
1265
- async function dryRunMultiFile(inputs, options, deps) {
1266
- const files = [];
1267
- for (const filePath of inputs) {
1268
- let info;
1269
- try {
1270
- info = await (0, import_promises3.stat)(filePath);
1271
- } catch {
1272
- return writeError(
1273
- deps,
1274
- "local_input_error",
1275
- `File not found: ${filePath}`
1276
- );
1277
- }
1278
- if (info.isDirectory()) {
1279
- return writeError(
1280
- deps,
1281
- "local_input_error",
1282
- `Cannot mix directories with multiple file arguments. Use a single folder instead: dropthis publish ${filePath}`
1283
- );
1284
- }
1285
- files.push({
1286
- path: (0, import_node_path2.basename)(filePath),
1287
- contentType: mimeForPath(filePath),
1288
- sizeBytes: info.size
1289
- });
1290
- }
1291
- validateManifestFileCount(files.length);
1292
- const entry = options.entry ?? files.find((f) => f.path === "index.html")?.path ?? files[0]?.path ?? null;
1293
- const totalBytes = files.reduce((sum, f) => sum + f.sizeBytes, 0);
1294
- const output = {
1295
- dryRun: true,
1296
- kind: "staged",
1297
- manifest: { files, entry },
1298
- options: dryRunOptionsBody(options),
1299
- totalBytes
1300
- };
1301
- deps.stdout(`${JSON.stringify(output, null, 2)}
1302
- `);
1303
- return { exitCode: 0 };
1304
- }
1305
1295
 
1306
1296
  // src/commands/update.ts
1307
1297
  var prompts4 = __toESM(require("@clack/prompts"), 1);
@@ -1355,17 +1345,14 @@ async function runUpdate(target, input, raw, deps) {
1355
1345
  },
1356
1346
  "upd"
1357
1347
  )
1358
- ) : updateInput ? await deps.client.update(
1348
+ ) : updateInput ? await deps.client.deploy(
1359
1349
  target,
1360
1350
  updateInput,
1361
- withIdempotencyKey(
1362
- {
1363
- ...parsed,
1364
- ...revisionOptions
1365
- },
1366
- "upd"
1367
- )
1368
- ) : await deps.client.update(target, parsed, revisionOptions);
1351
+ withIdempotencyKey({ ...parsed, ...revisionOptions }, "upd")
1352
+ ) : await deps.client.update(
1353
+ target,
1354
+ withIdempotencyKey({ ...parsed, ...revisionOptions }, "upd")
1355
+ );
1369
1356
  if (result.error) {
1370
1357
  spin?.fail();
1371
1358
  return writeApiError(deps, result.error);
@@ -1556,7 +1543,7 @@ async function handleUpdateDryRun(target, input, raw, deps) {
1556
1543
  raw.fromJson
1557
1544
  );
1558
1545
  deps.stdout(
1559
- `${JSON.stringify({ dryRun: true, kind: "raw_json", endpoint: `POST /drops/${target}/deployments`, body }, null, 2)}
1546
+ `${JSON.stringify({ ok: true, dryRun: true, kind: "raw_json", endpoint: `POST /drops/${target}/deployments`, body }, null, 2)}
1560
1547
  `
1561
1548
  );
1562
1549
  return { exitCode: 0 };
@@ -1572,7 +1559,7 @@ async function handleUpdateDryRun(target, input, raw, deps) {
1572
1559
  if (options.expiresAt) fields.expires_at = options.expiresAt;
1573
1560
  if (options.metadata) fields.metadata = options.metadata;
1574
1561
  deps.stdout(
1575
- `${JSON.stringify({ dryRun: true, kind: "options_update", target, fields }, null, 2)}
1562
+ `${JSON.stringify({ ok: true, dryRun: true, kind: "options_update", target, fields }, null, 2)}
1576
1563
  `
1577
1564
  );
1578
1565
  return { exitCode: 0 };
@@ -1582,7 +1569,9 @@ async function handleUpdateDryRun(target, input, raw, deps) {
1582
1569
  }
1583
1570
  const prepared = await deps.client.prepare(input, options);
1584
1571
  const output = formatDryRunManifest(prepared, { target });
1585
- validateManifestFileCount(prepared.manifest.files.length);
1572
+ if (prepared.kind === "staged") {
1573
+ validateManifestFileCount(prepared.manifest.files.length);
1574
+ }
1586
1575
  deps.stdout(`${JSON.stringify(output, null, 2)}
1587
1576
  `);
1588
1577
  return { exitCode: 0 };
@@ -1603,6 +1592,7 @@ function assertDropId(target) {
1603
1592
  // src/commands/whoami.ts
1604
1593
  async function runWhoami(_input, deps) {
1605
1594
  const credential = await resolveCredential({
1595
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
1606
1596
  env: deps.env,
1607
1597
  store: deps.store
1608
1598
  });
@@ -1613,21 +1603,34 @@ async function runWhoami(_input, deps) {
1613
1603
  });
1614
1604
  return { exitCode: 0 };
1615
1605
  }
1606
+ const result = await deps.client.account.get();
1607
+ if (result.error) {
1608
+ writeHumanOrJson(
1609
+ deps,
1610
+ `Not authenticated: ${result.error.message}. Run dropthis login.`,
1611
+ { ok: true, authenticated: false, reason: result.error.message }
1612
+ );
1613
+ return { exitCode: 0 };
1614
+ }
1615
+ const account = result.data ?? {};
1616
1616
  const masked = maskKey(credential.apiKey);
1617
+ const last4 = credential.keyLast4 ?? credential.apiKey.slice(-4);
1617
1618
  const pairs = [];
1618
- if (credential.email) pairs.push(["Email", credential.email]);
1619
+ if (credential.email ?? account.email)
1620
+ pairs.push(["Email", String(credential.email ?? account.email)]);
1619
1621
  pairs.push(["Key", masked]);
1620
1622
  pairs.push(["Source", credential.source]);
1621
- if (credential.accountId) pairs.push(["Account", credential.accountId]);
1623
+ if (credential.accountId ?? account.id)
1624
+ pairs.push(["Account", String(credential.accountId ?? account.id)]);
1622
1625
  const jsonEnvelope = {
1623
1626
  ok: true,
1624
1627
  authenticated: true,
1625
1628
  source: credential.source,
1626
1629
  masked_key: masked,
1627
1630
  ...credential.keyId ? { key_id: credential.keyId } : {},
1628
- ...credential.keyLast4 ? { key_last4: credential.keyLast4 } : {},
1629
- ...credential.accountId ? { account_id: credential.accountId } : {},
1630
- ...credential.email ? { email: credential.email } : {}
1631
+ ...last4 ? { key_last4: last4 } : {},
1632
+ ...credential.accountId ?? account.id ? { account_id: String(credential.accountId ?? account.id) } : {},
1633
+ ...credential.email ?? account.email ? { email: String(credential.email ?? account.email) } : {}
1631
1634
  };
1632
1635
  writeKv(deps, pairs, jsonEnvelope);
1633
1636
  return { exitCode: 0 };
@@ -1660,9 +1663,9 @@ function createContext(input) {
1660
1663
  }
1661
1664
 
1662
1665
  // src/storage.ts
1663
- var import_promises4 = require("fs/promises");
1666
+ var import_promises3 = require("fs/promises");
1664
1667
  var import_node_os = require("os");
1665
- var import_node_path3 = require("path");
1668
+ var import_node_path = require("path");
1666
1669
  var import_keyring = require("@napi-rs/keyring");
1667
1670
  var MemoryCredentialStore = class {
1668
1671
  credential = null;
@@ -1694,7 +1697,7 @@ var InsecureFileCredentialStore = class {
1694
1697
  });
1695
1698
  }
1696
1699
  async clear() {
1697
- await (0, import_promises4.rm)(this.filePath, { force: true });
1700
+ await (0, import_promises3.rm)(this.filePath, { force: true });
1698
1701
  }
1699
1702
  };
1700
1703
  var KeyringCredentialStore = class {
@@ -1721,7 +1724,7 @@ var KeyringCredentialStore = class {
1721
1724
  }
1722
1725
  async clear() {
1723
1726
  await this.keyring.deletePassword();
1724
- await (0, import_promises4.rm)(this.filePath, { force: true });
1727
+ await (0, import_promises3.rm)(this.filePath, { force: true });
1725
1728
  }
1726
1729
  };
1727
1730
  function createCredentialStore(options = {}) {
@@ -1739,14 +1742,14 @@ function defaultKeyringAdapter() {
1739
1742
  };
1740
1743
  }
1741
1744
  function credentialPath(configDir) {
1742
- return (0, import_node_path3.join)(
1743
- configDir ?? (0, import_node_path3.join)((0, import_node_os.homedir)(), ".config", "dropthis"),
1745
+ return (0, import_node_path.join)(
1746
+ configDir ?? (0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "dropthis"),
1744
1747
  "credentials.json"
1745
1748
  );
1746
1749
  }
1747
1750
  async function readJsonFile(path) {
1748
1751
  try {
1749
- return JSON.parse(await (0, import_promises4.readFile)(path, "utf8"));
1752
+ return JSON.parse(await (0, import_promises3.readFile)(path, "utf8"));
1750
1753
  } catch (error2) {
1751
1754
  if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
1752
1755
  return null;
@@ -1755,20 +1758,34 @@ async function readJsonFile(path) {
1755
1758
  }
1756
1759
  }
1757
1760
  async function writeCredentialFile(path, credential) {
1758
- await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
1761
+ await (0, import_promises3.mkdir)((0, import_node_path.dirname)(path), { recursive: true });
1759
1762
  const tmpPath = `${path}.${process.pid}.tmp`;
1760
- await (0, import_promises4.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
1763
+ await (0, import_promises3.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
1761
1764
  `, {
1762
1765
  mode: 384
1763
1766
  });
1764
- await (0, import_promises4.chmod)(tmpPath, 384);
1765
- await (0, import_promises4.rename)(tmpPath, path);
1767
+ await (0, import_promises3.chmod)(tmpPath, 384);
1768
+ await (0, import_promises3.rename)(tmpPath, path);
1766
1769
  }
1767
1770
 
1768
1771
  // src/program.ts
1769
1772
  function buildProgram(options = {}) {
1770
1773
  const program = new import_commander.Command();
1771
1774
  const store = options.store ?? new MemoryCredentialStore();
1775
+ const writeErr = options.stderr ?? ((value) => process.stderr.write(value));
1776
+ const jsonModeForOutput = () => {
1777
+ const argv = program.rawArgs ?? process.argv;
1778
+ return argv.includes("--json") || argv.includes("--quiet") || argv.includes("-q") || options.env?.CI === "true" || options.env === void 0 && process.env.CI === "true" || options.stdoutIsTTY === false || options.stdoutIsTTY === void 0 && process.stdout.isTTY !== true;
1779
+ };
1780
+ program.exitOverride();
1781
+ program.configureOutput({
1782
+ writeErr,
1783
+ // In JSON mode, suppress commander's default plain-text error so the
1784
+ // single JSON envelope written by cli.ts's catch is the only output.
1785
+ outputError: (str, write) => {
1786
+ if (!jsonModeForOutput()) write(str);
1787
+ }
1788
+ });
1772
1789
  program.name("dropthis").description(
1773
1790
  [
1774
1791
  import_picocolors4.default.dim("Publish anything online and get a URL back."),
@@ -1777,7 +1794,7 @@ function buildProgram(options = {}) {
1777
1794
  ` ${import_picocolors4.default.cyan("dropthis login")}`,
1778
1795
  ` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
1779
1796
  ].join("\n")
1780
- ).version("0.5.0").configureHelp({
1797
+ ).version("0.6.0").configureHelp({
1781
1798
  subcommandTerm(cmd) {
1782
1799
  const args = cmd.registeredArguments.map((a) => {
1783
1800
  const name = a.name();
@@ -1807,7 +1824,10 @@ function buildProgram(options = {}) {
1807
1824
  ).option(
1808
1825
  "--metadata <json>",
1809
1826
  `Attach JSON key-value pairs, e.g. '{"source":"ci"}'`
1810
- ).option("--metadata-file <path>", "Read metadata JSON from a file").option("--path <name>", "Set filename when publishing from stdin").option("--url", "Print only the published URL (no JSON envelope)").option("--dry-run", "Show what would be published without publishing").option("--json", "Force JSON output").option("--from-json <path>", "Send raw API request body from a JSON file").option(
1827
+ ).option("--metadata-file <path>", "Read metadata JSON from a file").option("--path <name>", "Set filename when publishing from stdin").option("--url", "Print only the published URL (no JSON envelope)").option(
1828
+ "--dry-run",
1829
+ "Show what would be published without publishing (JSON; cannot combine with --url)"
1830
+ ).option("--json", "Force JSON output").option("--from-json <path>", "Send raw API request body from a JSON file").option(
1811
1831
  "--idempotency-key <key>",
1812
1832
  "Prevent duplicate publishes on retry (auto-generated)"
1813
1833
  ).action(async (inputs, commandOptions) => {
@@ -1825,15 +1845,11 @@ function buildProgram(options = {}) {
1825
1845
  );
1826
1846
  let publishInput;
1827
1847
  try {
1828
- if (commandOptions.dryRun && inputs.length > 1) {
1829
- publishInput = inputs;
1830
- } else {
1831
- publishInput = await resolvePublishInputs(
1832
- inputs,
1833
- options.stdin,
1834
- stdinIsTTY
1835
- );
1836
- }
1848
+ publishInput = await resolvePublishInputs(
1849
+ inputs,
1850
+ options.stdin,
1851
+ stdinIsTTY
1852
+ );
1837
1853
  } catch (err) {
1838
1854
  const msg = err instanceof Error ? err.message : "Invalid input.";
1839
1855
  process.exitCode = writeError(deps, "local_input_error", msg).exitCode;
@@ -1876,7 +1892,10 @@ function buildProgram(options = {}) {
1876
1892
  "--if-revision <n>",
1877
1893
  "Fail if current revision doesn't match (optimistic lock)",
1878
1894
  parseInteger
1879
- ).option("--url", "Print only the published URL (no JSON envelope)").option("--dry-run", "Show what would be updated without updating").option("--json", "Force JSON output").option(
1895
+ ).option("--url", "Print only the published URL (no JSON envelope)").option(
1896
+ "--dry-run",
1897
+ "Show what would be updated without updating (JSON; cannot combine with --url)"
1898
+ ).option("--json", "Force JSON output").option(
1880
1899
  "--from-json <path>",
1881
1900
  "Send raw API deployment body from a JSON file"
1882
1901
  ).option(
@@ -2045,11 +2064,36 @@ function buildProgram(options = {}) {
2045
2064
  const result = await runWhoami(commandOptions, deps);
2046
2065
  process.exitCode = result.exitCode;
2047
2066
  });
2048
- program.command("account").description("Show account details").option("--json", "Force JSON output").action(async (commandOptions) => {
2067
+ const account = program.command("account").description("Show or manage your account");
2068
+ account.command("get", { isDefault: true }).description("Show account details").option("--json", "Force JSON output").action(async (commandOptions) => {
2049
2069
  const deps = await commandDeps(program, options, store, commandOptions);
2050
2070
  const result = await runAccountGet(commandOptions, deps);
2051
2071
  process.exitCode = result.exitCode;
2052
2072
  });
2073
+ account.command("update").description("Update account display name").requiredOption("--display-name <name>", "Set the display name").option("--json", "Force JSON output").action(async (commandOptions) => {
2074
+ const deps = await commandDeps(program, options, store, commandOptions);
2075
+ const result = await runAccountUpdate(
2076
+ {
2077
+ displayName: commandOptions.displayName,
2078
+ ...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
2079
+ },
2080
+ deps
2081
+ );
2082
+ process.exitCode = result.exitCode;
2083
+ });
2084
+ account.command("delete").description("Delete your account").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(async (commandOptions) => {
2085
+ const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
2086
+ const global = globalOptions(program, commandOptions);
2087
+ const deps = await commandDeps(program, options, store, commandOptions);
2088
+ const result = await runAccountDelete(
2089
+ {
2090
+ ...commandOptions,
2091
+ interactive: isInteractive(stdinIsTTY, deps.env, global)
2092
+ },
2093
+ deps
2094
+ );
2095
+ process.exitCode = result.exitCode;
2096
+ });
2053
2097
  program.command("doctor").description("Report CLI diagnostics").option("--json", "Force JSON output").action(async (commandOptions) => {
2054
2098
  const deps = await commandDeps(
2055
2099
  program,
@@ -2067,7 +2111,7 @@ function buildProgram(options = {}) {
2067
2111
  store,
2068
2112
  commandOptions
2069
2113
  );
2070
- const result = await runCommands(commandOptions, deps);
2114
+ const result = await runCommands(commandOptions, { ...deps, program });
2071
2115
  process.exitCode = result.exitCode;
2072
2116
  });
2073
2117
  return program;
@@ -2196,44 +2240,12 @@ async function resolvePublishInputs(inputs, stdin, stdinIsTTY) {
2196
2240
  }
2197
2241
  return inputs[0];
2198
2242
  }
2199
- const {
2200
- mkdtemp,
2201
- copyFile,
2202
- writeFile: writeFile2,
2203
- stat: fsStat
2204
- } = await import("fs/promises");
2205
- const { join: join2, basename: pathBasename } = await import("path");
2206
- const { tmpdir } = await import("os");
2207
- const tmpDir = await mkdtemp(join2(tmpdir(), "dropthis-multi-"));
2208
- const resolved = [];
2209
- for (const input of inputs) {
2210
- if (input === "-") {
2211
- const buf = await readStdinBytes(stdin ?? process.stdin);
2212
- const tmpPath = join2(tmpDir, `stdin-${Date.now()}`);
2213
- await writeFile2(tmpPath, buf);
2214
- resolved.push(tmpPath);
2215
- } else {
2216
- resolved.push(input);
2217
- }
2218
- }
2219
- const names = resolved.map((f) => pathBasename(f));
2220
- const dupes = names.filter((n, i) => names.indexOf(n) !== i);
2221
- if (dupes.length > 0) {
2243
+ if (inputs.includes("-")) {
2222
2244
  throw new Error(
2223
- `Duplicate file names: ${[...new Set(dupes)].join(", ")}. Rename files to avoid collisions.`
2245
+ "Cannot read stdin (-) alongside multiple file arguments. Pass file paths only."
2224
2246
  );
2225
2247
  }
2226
- for (const filePath of resolved) {
2227
- const info = await fsStat(filePath);
2228
- if (info.isDirectory()) {
2229
- throw new Error(
2230
- `Cannot mix directories with multiple file arguments. Use a single folder instead: dropthis publish ${filePath}`
2231
- );
2232
- }
2233
- const destName = pathBasename(filePath);
2234
- await copyFile(filePath, join2(tmpDir, destName));
2235
- }
2236
- return tmpDir;
2248
+ return inputs;
2237
2249
  }
2238
2250
  async function readStdinBytes(stdin) {
2239
2251
  const chunks = [];
@@ -2246,8 +2258,42 @@ async function readStdinBytes(stdin) {
2246
2258
  }
2247
2259
 
2248
2260
  // src/cli.ts
2261
+ function writeUsageErrorEnvelope(input) {
2262
+ if (input.json) {
2263
+ input.stderr(
2264
+ `${JSON.stringify(errorEnvelope("usage_error", input.message))}
2265
+ `
2266
+ );
2267
+ } else {
2268
+ input.stderr(`${input.message}
2269
+ `);
2270
+ }
2271
+ return 2;
2272
+ }
2273
+ function isCommanderError(err) {
2274
+ return typeof err === "object" && err !== null && typeof err.code === "string" && err.code.startsWith("commander.");
2275
+ }
2276
+ function wantsJson(argv) {
2277
+ return argv.includes("--json") || argv.includes("--quiet") || argv.includes("-q") || process.env.CI === "true" || process.stdout.isTTY !== true;
2278
+ }
2249
2279
  buildProgram({ store: createCredentialStore() }).parseAsync(process.argv).catch((error2) => {
2280
+ if (isCommanderError(error2)) {
2281
+ if (error2.code === "commander.help" || error2.code === "commander.helpDisplayed" || error2.code === "commander.version") {
2282
+ process.exitCode = 0;
2283
+ return;
2284
+ }
2285
+ process.exitCode = writeUsageErrorEnvelope({
2286
+ message: error2.message,
2287
+ json: wantsJson(process.argv.slice(2)),
2288
+ stderr: (value) => process.stderr.write(value)
2289
+ });
2290
+ return;
2291
+ }
2250
2292
  console.error(error2);
2251
2293
  process.exitCode = 1;
2252
2294
  });
2295
+ // Annotate the CommonJS export names for ESM import in node:
2296
+ 0 && (module.exports = {
2297
+ writeUsageErrorEnvelope
2298
+ });
2253
2299
  //# sourceMappingURL=cli.cjs.map