@dropthis/cli 0.3.5 → 0.4.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.
package/README.md CHANGED
@@ -14,7 +14,7 @@ Requires Node.js >= 20.
14
14
 
15
15
  ```bash
16
16
  dropthis login
17
- dropthis publish index.html
17
+ dropthis ./index.html # publish is the default command
18
18
  ```
19
19
 
20
20
  ## Authentication
@@ -47,6 +47,8 @@ Credentials resolve in this order:
47
47
  2. `DROPTHIS_API_KEY` environment variable
48
48
  3. Stored credential from `dropthis login`
49
49
 
50
+ If you run `dropthis publish` without credentials in an interactive terminal, the CLI prompts you to log in inline — no separate `dropthis login` step needed. Disable with `--no-interactive`.
51
+
50
52
  ```bash
51
53
  dropthis whoami # Check current auth status
52
54
  dropthis logout # Remove stored credentials
@@ -55,21 +57,29 @@ dropthis logout --revoke # Remove and revoke the key on the server
55
57
 
56
58
  ## Publish
57
59
 
60
+ `publish` is the default command — you can omit it and pass files directly:
61
+
62
+ ```bash
63
+ # These are equivalent:
64
+ dropthis ./report.html
65
+ dropthis publish ./report.html
66
+ ```
67
+
58
68
  ```bash
59
69
  # HTML file
60
- dropthis publish report.html
70
+ dropthis ./report.html
61
71
 
62
72
  # Directory (static site)
63
- dropthis publish ./dist
73
+ dropthis ./dist
64
74
 
65
75
  # Stdin
66
76
  echo "<h1>Hello</h1>" | dropthis publish - --content-type text/html --path index.html
67
77
 
68
78
  # Multiple files bundled into one drop
69
- dropthis publish index.html styles.css app.js
79
+ dropthis index.html styles.css app.js
70
80
 
71
81
  # Print only the URL (recommended for agents)
72
- dropthis publish ./dist --url
82
+ dropthis ./dist --url
73
83
  ```
74
84
 
75
85
  ### Publish options
@@ -90,9 +100,7 @@ All publish flags:
90
100
  | `--title <title>` | Drop title |
91
101
  | `--visibility <public\|unlisted>` | Drop visibility |
92
102
  | `--password <password>` | Set password protection |
93
- | `--no-password` | Clear password |
94
103
  | `--noindex` | Prevent search indexing |
95
- | `--index` | Allow indexing |
96
104
  | `--entry <path>` | Entry file for directories |
97
105
  | `--content-type <mime>` | MIME type (required for stdin) |
98
106
  | `--path <path>` | Filename (required for stdin) |
@@ -113,35 +121,39 @@ These flags are inherited by all commands:
113
121
  |------|-------------|
114
122
  | `--api-key <key>` | Override API key for this invocation |
115
123
  | `--api-url <url>` | Override API base URL |
124
+ | `--json` | Force JSON output |
116
125
  | `-q, --quiet` | Suppress status output and imply JSON |
126
+ | `--no-interactive` | Disable interactive prompts (inline auth, confirmations) |
117
127
 
118
128
  ## Update
119
129
 
130
+ Update an existing drop's content, metadata, or both via `drops update`:
131
+
120
132
  ```bash
121
133
  # Replace content
122
- dropthis update drop_abc123 ./dist-v2
134
+ dropthis drops update drop_abc123 ./dist-v2
123
135
 
124
136
  # Update metadata only
125
- dropthis update drop_abc123 --title "New title"
137
+ dropthis drops update drop_abc123 --title "New title"
126
138
 
127
139
  # Optimistic concurrency
128
- dropthis update drop_abc123 ./dist-v2 --if-revision 1
140
+ dropthis drops update drop_abc123 ./dist-v2 --if-revision 1
129
141
 
130
142
  # Change vanity slug
131
- dropthis update drop_abc123 --slug new-slug
143
+ dropthis drops update drop_abc123 --slug new-slug
132
144
  ```
133
145
 
134
- The `update` command supports all publish flags plus `--slug` and `--if-revision`.
146
+ `drops update` supports all publish flags plus `--slug` and `--if-revision`.
135
147
 
136
148
  ## Commands
137
149
 
138
150
  ```bash
139
- dropthis publish [input...] # Publish content, get a URL
140
- dropthis update <drop-id> [input] # Update an existing drop
151
+ dropthis [input...] # Publish content (default command)
152
+ dropthis publish [input...] # Same as above, explicit form
141
153
 
142
154
  dropthis drops list # List your drops
143
155
  dropthis drops get <drop-id> # Get drop details
144
- dropthis drops update <drop-id> # Update drop metadata
156
+ dropthis drops update <drop-id> [input] # Update content or metadata
145
157
  dropthis drops delete <drop-id> # Delete a drop
146
158
 
147
159
  dropthis login # Authenticate with email OTP
@@ -166,10 +178,15 @@ dropthis commands # Machine-readable command metadata
166
178
 
167
179
  The CLI is designed for non-interactive use. In non-TTY environments (pipes, CI, agents), output defaults to JSON automatically.
168
180
 
169
- **Environment variable auth (recommended for CI):**
181
+ **Environment variables:**
182
+
183
+ ```bash
184
+ export DROPTHIS_API_KEY=sk_live_... # API key (same as --api-key)
185
+ export DROPTHIS_API_URL=https://... # Override API base URL (same as --api-url)
186
+ export DROPTHIS_NON_INTERACTIVE=1 # Disable interactive prompts (same as --no-interactive)
187
+ ```
170
188
 
171
189
  ```bash
172
- export DROPTHIS_API_KEY=sk_live_...
173
190
  dropthis publish ./dist --url
174
191
  ```
175
192
 
@@ -178,6 +195,7 @@ dropthis publish ./dist --url
178
195
  - Use `--url` to get only the published URL (cleanest for agents)
179
196
  - Use `--json` for the full structured response
180
197
  - Use `--yes` for destructive commands (`drops delete`, `api-keys delete`)
198
+ - Use `--no-interactive` to disable inline auth prompts
181
199
  - All errors write to stderr as JSON with a `next_action` field
182
200
 
183
201
  **Exit codes:**
@@ -211,18 +229,18 @@ Run diagnostics to verify CLI health:
211
229
  dropthis doctor
212
230
  ```
213
231
 
214
- Reports CLI version, auth source (`env`, `flag`, `stored`, or `missing`), and credential storage backend (`keyring`, `file`, or `none`).
232
+ Reports CLI version, auth source (`env`, `flag`, `storage`, or `missing`), and credential storage backend (`secure`, `insecure`, or `none`).
215
233
 
216
234
  ```json
217
- {"ok":true,"version":"0.2.4","auth":{"source":"env"},"storage":{"backend":"keyring"}}
235
+ {"ok":true,"version":"0.4.1","auth":{"source":"env"},"storage":{"backend":"secure"}}
218
236
  ```
219
237
 
220
238
  ## Agent skills
221
239
 
222
- This CLI ships with an [agent skill](https://skills.sh) that teaches AI coding agents (Cursor, Claude Code, Windsurf, etc.) how to use the dropthis CLI effectively, including non-interactive flags, output formats, and common pitfalls.
240
+ For AI coding agents (Cursor, Claude Code, Windsurf, etc.), install the [dropthis-skills](https://github.com/dropthis-dev/dropthis-skills) package:
223
241
 
224
242
  ```bash
225
- npx skills add dropthis-dev/dropthis-cli
243
+ npx skills add dropthis-dev/dropthis-skills
226
244
  ```
227
245
 
228
246
  ## Links
package/dist/cli.cjs CHANGED
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
9
16
  var __copyProps = (to, from, except, desc) => {
10
17
  if (from && typeof from === "object" || typeof from === "function") {
11
18
  for (let key of __getOwnPropNames(from))
@@ -23,6 +30,126 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
30
  mod
24
31
  ));
25
32
 
33
+ // src/inline-auth.ts
34
+ var inline_auth_exports = {};
35
+ __export(inline_auth_exports, {
36
+ runInlineAuth: () => runInlineAuth
37
+ });
38
+ async function runInlineAuth(deps) {
39
+ try {
40
+ const prompt = deps.prompt ?? defaultPrompts();
41
+ deps.stderr("\nNot logged in. Let's fix that:\n");
42
+ const emailResult = await prompt.email();
43
+ if (typeof emailResult === "symbol") {
44
+ return null;
45
+ }
46
+ const email = emailResult;
47
+ const otpRequest = await deps.client.auth.requestEmailOtp({ email });
48
+ if (otpRequest.error) {
49
+ deps.stderr(`${otpRequest.error.message}
50
+ `);
51
+ return null;
52
+ }
53
+ deps.stderr("Code sent! Check your inbox.\n");
54
+ const maxAttempts = 3;
55
+ let session = null;
56
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
57
+ const codeResult = await prompt.code(attempt, maxAttempts);
58
+ if (typeof codeResult === "symbol") {
59
+ return null;
60
+ }
61
+ const code = codeResult;
62
+ const verifyResult = await deps.client.auth.verifyEmailOtp({
63
+ email,
64
+ code
65
+ });
66
+ if (!verifyResult.error) {
67
+ session = verifyResult.data;
68
+ break;
69
+ }
70
+ if (attempt < maxAttempts) {
71
+ deps.stderr(`${verifyResult.error.message}
72
+ `);
73
+ } else {
74
+ deps.stderr(
75
+ "Too many attempts. Run `dropthis login` to request a new code.\n"
76
+ );
77
+ return null;
78
+ }
79
+ }
80
+ if (!session) {
81
+ return null;
82
+ }
83
+ const authedClient = deps.createClient(session.token);
84
+ const apiKeyResult = await authedClient.apiKeys.create({
85
+ label: `CLI on ${deps.hostname ?? (0, import_node_os2.hostname)()}`
86
+ });
87
+ if (apiKeyResult.error) {
88
+ deps.stderr(`${apiKeyResult.error.message}
89
+ `);
90
+ return null;
91
+ }
92
+ const { id: keyId, key: apiKey, keyLast4, accountId } = apiKeyResult.data;
93
+ try {
94
+ await deps.store.save({
95
+ apiKey,
96
+ keyId,
97
+ keyLast4,
98
+ accountId: accountId ?? session.accountId,
99
+ email,
100
+ storage: "secure"
101
+ });
102
+ } catch (err) {
103
+ const message = err instanceof Error ? err.message : String(err);
104
+ deps.stderr(`Failed to save credentials: ${message}
105
+ `);
106
+ return null;
107
+ }
108
+ deps.stderr("\u2713 Logged in\n\n");
109
+ return {
110
+ apiKey,
111
+ source: "storage",
112
+ keyId,
113
+ keyLast4,
114
+ accountId: accountId ?? session.accountId,
115
+ email
116
+ };
117
+ } catch (err) {
118
+ const message = err instanceof Error ? err.message : String(err);
119
+ deps.stderr(`Login failed: ${message}
120
+ `);
121
+ return null;
122
+ }
123
+ }
124
+ function defaultPrompts() {
125
+ return {
126
+ email: () => readlineQuestion("Email: "),
127
+ code: (attempt) => readlineQuestion(
128
+ attempt === 1 ? "Code: " : "Try again \u2014 enter the code: "
129
+ )
130
+ };
131
+ }
132
+ function readlineQuestion(question) {
133
+ const rl = (0, import_node_readline.createInterface)({
134
+ input: process.stdin,
135
+ output: process.stderr
136
+ });
137
+ return new Promise((resolve) => {
138
+ rl.question(question, (answer) => {
139
+ rl.close();
140
+ resolve(answer);
141
+ });
142
+ });
143
+ }
144
+ var import_node_os2, import_node_readline;
145
+ var init_inline_auth = __esm({
146
+ "src/inline-auth.ts"() {
147
+ "use strict";
148
+ import_node_os2 = require("os");
149
+ import_node_readline = require("readline");
150
+ }
151
+ });
152
+
26
153
  // src/program.ts
27
154
  var import_commander = require("commander");
28
155
  var import_picocolors4 = __toESM(require("picocolors"), 1);
@@ -93,11 +220,14 @@ function apiErrorEnvelope(error2) {
93
220
  ...error2.param ? { param: error2.param } : {},
94
221
  ...error2.currentRevision !== void 0 ? { current_revision: error2.currentRevision } : {},
95
222
  ...error2.requestId ? { request_id: error2.requestId } : {},
223
+ ...error2.suggestion ? { suggestion: error2.suggestion } : {},
224
+ ...error2.retryable !== void 0 && error2.retryable !== null ? { retryable: error2.retryable } : {},
96
225
  next_action: nextActionForApiError(error2)
97
226
  }
98
227
  };
99
228
  }
100
229
  function nextActionForApiError(error2) {
230
+ if (error2.suggestion) return error2.suggestion;
101
231
  const uploadNextAction = error2.code ? UPLOAD_NEXT_ACTIONS[error2.code] : void 0;
102
232
  if (uploadNextAction) return uploadNextAction;
103
233
  if (error2.code === "revision_conflict") {
@@ -221,8 +351,11 @@ function writeApiError(deps, details) {
221
351
  if (deps.outputMode === "human") {
222
352
  deps.stderr(`${error(details.message)}
223
353
  `);
224
- const nextAction = details.requestId ? `Request ID: ${details.requestId}` : void 0;
354
+ const nextAction = nextActionForApiError(details);
225
355
  if (nextAction) deps.stderr(`${hint(nextAction)}
356
+ `);
357
+ if (details.requestId)
358
+ deps.stderr(`${import_picocolors2.default.dim(`Request ID: ${details.requestId}`)}
226
359
  `);
227
360
  } else {
228
361
  deps.stderr(`${JSON.stringify(apiErrorEnvelope(details))}
@@ -394,6 +527,7 @@ var COMMAND_CATALOG = [
394
527
  arguments: ["input"],
395
528
  options: ["--json", "--url", "--dry-run", "--title", "--metadata"],
396
529
  examples: [
530
+ "dropthis ./file.html",
397
531
  "dropthis publish ./site --json",
398
532
  "dropthis publish ./site --url",
399
533
  "dropthis publish ./dist --dry-run"
@@ -555,13 +689,13 @@ async function runDoctor(_input, deps) {
555
689
  const authSource = credential?.source ?? "missing";
556
690
  const storageBackend = stored?.storage ?? "none";
557
691
  const pairs = [
558
- ["Version", "0.3.5"],
692
+ ["Version", "0.4.1"],
559
693
  ["Auth", authSource],
560
694
  ["Storage", storageBackend]
561
695
  ];
562
696
  writeKv(deps, pairs, {
563
697
  ok: true,
564
- version: "0.3.5",
698
+ version: "0.4.1",
565
699
  auth: { source: authSource },
566
700
  storage: { backend: storageBackend }
567
701
  });
@@ -991,8 +1125,9 @@ async function readJsonObjectFile(path) {
991
1125
 
992
1126
  // src/commands/publish.ts
993
1127
  async function runPublish(input, raw, deps) {
1128
+ let credential;
994
1129
  try {
995
- await requireCredential({
1130
+ credential = await resolveCredential({
996
1131
  ...raw.apiKey ?? deps.apiKey ? { apiKey: raw.apiKey ?? deps.apiKey } : {},
997
1132
  env: deps.env,
998
1133
  store: deps.store
@@ -1000,8 +1135,26 @@ async function runPublish(input, raw, deps) {
1000
1135
  } catch {
1001
1136
  return writeAuthError(deps);
1002
1137
  }
1138
+ let didInlineAuth = false;
1139
+ if (!credential) {
1140
+ if (deps.interactive && deps.inlineAuth) {
1141
+ try {
1142
+ credential = await deps.inlineAuth();
1143
+ } catch {
1144
+ return writeAuthError(deps);
1145
+ }
1146
+ if (!credential) return writeAuthError(deps);
1147
+ didInlineAuth = true;
1148
+ } else {
1149
+ return writeAuthError(deps);
1150
+ }
1151
+ }
1152
+ let client = deps.client;
1153
+ if (didInlineAuth && deps.createClient) {
1154
+ client = deps.createClient(credential.apiKey);
1155
+ }
1003
1156
  if (raw.dryRun) {
1004
- return handlePublishDryRun(input, raw, deps);
1157
+ return handlePublishDryRun(input, raw, deps, client);
1005
1158
  }
1006
1159
  const singleInput = Array.isArray(input) ? input[0] : input;
1007
1160
  const spin = shouldSpin(deps.outputMode) ? createSpinner("Publishing\u2026", deps.stderr) : void 0;
@@ -1010,13 +1163,44 @@ async function runPublish(input, raw, deps) {
1010
1163
  throw new Error("Use either <input> or --from-json, not both.");
1011
1164
  }
1012
1165
  const options = withIdempotencyKey(await parseDropOptions(raw), "pub");
1013
- const result = raw.fromJson ? await deps.client.drops.createRaw(
1014
- await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson),
1015
- options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}
1016
- ) : singleInput ? await deps.client.publish(singleInput, options) : (() => {
1166
+ const jsonBody = raw.fromJson ? await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson) : void 0;
1167
+ const idempotencyOpt = options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {};
1168
+ const doPublish = (c) => jsonBody ? c.drops.createRaw(jsonBody, idempotencyOpt) : singleInput ? c.publish(singleInput, options) : (() => {
1017
1169
  throw new Error("Publish requires <input> or --from-json.");
1018
1170
  })();
1171
+ const result = await doPublish(client);
1019
1172
  if (result.error) {
1173
+ if (result.error.statusCode === 401 && deps.interactive && deps.inlineAuth && !didInlineAuth) {
1174
+ spin?.stop();
1175
+ const newCredential = await deps.inlineAuth();
1176
+ if (newCredential && deps.createClient) {
1177
+ client = deps.createClient(newCredential.apiKey);
1178
+ const retrySpin = shouldSpin(deps.outputMode) ? createSpinner("Publishing\u2026", deps.stderr) : void 0;
1179
+ try {
1180
+ const retryResult = await doPublish(client);
1181
+ if (retryResult.error) {
1182
+ retrySpin?.fail();
1183
+ return writeApiError(deps, retryResult.error);
1184
+ }
1185
+ retrySpin?.stop();
1186
+ if (raw.url) deps.stdout(`${retryResult.data.url}
1187
+ `);
1188
+ else
1189
+ writeResult(
1190
+ deps,
1191
+ retryResult.data.url,
1192
+ "Published",
1193
+ retryResult.data
1194
+ );
1195
+ return { exitCode: 0 };
1196
+ } catch (retryError) {
1197
+ retrySpin?.fail();
1198
+ const message = retryError instanceof Error ? retryError.message : "Publish failed.";
1199
+ const code = isFileSystemError(retryError) ? "local_input_error" : "invalid_usage";
1200
+ return writeError(deps, code, message);
1201
+ }
1202
+ }
1203
+ }
1020
1204
  spin?.fail();
1021
1205
  return writeApiError(deps, result.error);
1022
1206
  }
@@ -1032,7 +1216,7 @@ async function runPublish(input, raw, deps) {
1032
1216
  return writeError(deps, code, message);
1033
1217
  }
1034
1218
  }
1035
- async function handlePublishDryRun(input, raw, deps) {
1219
+ async function handlePublishDryRun(input, raw, deps, client) {
1036
1220
  if (raw.url) {
1037
1221
  return writeError(
1038
1222
  deps,
@@ -1061,10 +1245,10 @@ async function handlePublishDryRun(input, raw, deps) {
1061
1245
  if (Array.isArray(input)) {
1062
1246
  return dryRunMultiFile(input, options, deps);
1063
1247
  }
1064
- if (!deps.client.prepare) {
1248
+ if (!client.prepare) {
1065
1249
  throw new Error("Client does not support dry-run.");
1066
1250
  }
1067
- const prepared = await deps.client.prepare(input, options);
1251
+ const prepared = await client.prepare(input, options);
1068
1252
  const output = formatDryRunManifest(prepared);
1069
1253
  validateManifestFileCount(
1070
1254
  output.manifest.files.length
@@ -1396,11 +1580,13 @@ async function readJsonFile(path) {
1396
1580
  }
1397
1581
  async function writeCredentialFile(path, credential) {
1398
1582
  await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
1399
- await (0, import_promises4.writeFile)(path, `${JSON.stringify(credential, null, 2)}
1583
+ const tmpPath = `${path}.${process.pid}.tmp`;
1584
+ await (0, import_promises4.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
1400
1585
  `, {
1401
1586
  mode: 384
1402
1587
  });
1403
- await (0, import_promises4.chmod)(path, 384);
1588
+ await (0, import_promises4.chmod)(tmpPath, 384);
1589
+ await (0, import_promises4.rename)(tmpPath, path);
1404
1590
  }
1405
1591
 
1406
1592
  // src/program.ts
@@ -1415,7 +1601,7 @@ function buildProgram(options = {}) {
1415
1601
  ` ${import_picocolors4.default.cyan("dropthis login")}`,
1416
1602
  ` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
1417
1603
  ].join("\n")
1418
- ).version("0.3.5").configureHelp({
1604
+ ).version("0.4.1").configureHelp({
1419
1605
  subcommandTerm(cmd) {
1420
1606
  const args = cmd.registeredArguments.map((a) => {
1421
1607
  const name = a.name();
@@ -1433,7 +1619,8 @@ function buildProgram(options = {}) {
1433
1619
  program.option("--api-url <url>", "Override API base URL");
1434
1620
  program.option("--json", "Force JSON output");
1435
1621
  program.option("-q, --quiet", "Suppress status output and imply JSON");
1436
- program.command("publish [input...]").description(
1622
+ program.option("--no-interactive", "Disable interactive prompts");
1623
+ program.command("publish [input...]", { isDefault: true }).description(
1437
1624
  "Publish files, folders, URLs, strings, or stdin.\nMultiple files are bundled into one drop.\nUse - to read stdin explicitly, or pipe without args."
1438
1625
  ).option("--title <title>", "Drop title").option("--visibility <v>", "public or unlisted (default: public)").option("--password <password>", "Require password to view").option("--noindex", "Prevent search-engine indexing").option("--expires-at <datetime>", "Auto-delete after this ISO 8601 date").option(
1439
1626
  "--content-type <mime>",
@@ -1448,8 +1635,18 @@ function buildProgram(options = {}) {
1448
1635
  "--idempotency-key <key>",
1449
1636
  "Prevent duplicate publishes on retry (auto-generated)"
1450
1637
  ).action(async (inputs, commandOptions) => {
1451
- const deps = await commandDeps(program, options, store, commandOptions);
1452
1638
  const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
1639
+ if (inputs.length === 0 && stdinIsTTY && !commandOptions.fromJson) {
1640
+ program.outputHelp();
1641
+ return;
1642
+ }
1643
+ const { deps } = await buildPublishDeps(
1644
+ program,
1645
+ options,
1646
+ store,
1647
+ commandOptions,
1648
+ stdinIsTTY
1649
+ );
1453
1650
  let publishInput;
1454
1651
  try {
1455
1652
  if (commandOptions.dryRun && inputs.length > 1) {
@@ -1538,10 +1735,15 @@ function buildProgram(options = {}) {
1538
1735
  );
1539
1736
  drops.command("delete <dropId>").description("Delete a drop").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
1540
1737
  async (dropId, commandOptions) => {
1738
+ const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
1739
+ const global = globalOptions(program, commandOptions);
1541
1740
  const deps = await commandDeps(program, options, store, commandOptions);
1542
1741
  const result = await runDropsDelete(
1543
1742
  dropId,
1544
- { ...commandOptions, interactive: deps.outputMode === "human" },
1743
+ {
1744
+ ...commandOptions,
1745
+ interactive: isInteractive(stdinIsTTY, deps.env, global)
1746
+ },
1545
1747
  deps
1546
1748
  );
1547
1749
  process.exitCode = result.exitCode;
@@ -1560,10 +1762,15 @@ function buildProgram(options = {}) {
1560
1762
  });
1561
1763
  apiKeys.command("delete <keyId>").description("Delete an API key").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
1562
1764
  async (keyId, commandOptions) => {
1765
+ const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
1766
+ const global = globalOptions(program, commandOptions);
1563
1767
  const deps = await commandDeps(program, options, store, commandOptions);
1564
1768
  const result = await runApiKeysDelete(
1565
1769
  keyId,
1566
- { ...commandOptions, interactive: deps.outputMode === "human" },
1770
+ {
1771
+ ...commandOptions,
1772
+ interactive: isInteractive(stdinIsTTY, deps.env, global)
1773
+ },
1567
1774
  deps
1568
1775
  );
1569
1776
  process.exitCode = result.exitCode;
@@ -1708,13 +1915,56 @@ async function commandDeps(program, options, store, commandOptions) {
1708
1915
  outputMode: context.output.mode
1709
1916
  };
1710
1917
  }
1918
+ async function buildPublishDeps(program, options, store, commandOptions, stdinIsTTY) {
1919
+ const global = globalOptions(program, commandOptions);
1920
+ const context = createContext({
1921
+ global,
1922
+ ...options.env !== void 0 ? { env: options.env } : {},
1923
+ ...options.stdout !== void 0 ? { stdout: options.stdout } : {},
1924
+ ...options.stderr !== void 0 ? { stderr: options.stderr } : {},
1925
+ ...options.stdoutIsTTY !== void 0 ? { stdoutIsTTY: options.stdoutIsTTY } : {}
1926
+ });
1927
+ const credential = await resolveCredential({
1928
+ ...global.apiKey ? { apiKey: global.apiKey } : {},
1929
+ env: context.env,
1930
+ store
1931
+ });
1932
+ const interactive = isInteractive(stdinIsTTY, context.env, global);
1933
+ const inlineAuth = async () => {
1934
+ const { runInlineAuth: runInlineAuth2 } = await Promise.resolve().then(() => (init_inline_auth(), inline_auth_exports));
1935
+ return runInlineAuth2({
1936
+ client: context.createClient(),
1937
+ createClient: (apiKey) => context.createClient(apiKey),
1938
+ store,
1939
+ stderr: context.stderr
1940
+ });
1941
+ };
1942
+ return {
1943
+ deps: {
1944
+ store,
1945
+ client: options.client ?? context.createClient(credential?.apiKey),
1946
+ ...global.apiKey ? { apiKey: global.apiKey } : {},
1947
+ env: context.env,
1948
+ stdout: context.stdout,
1949
+ stderr: context.stderr,
1950
+ outputMode: context.output.mode,
1951
+ interactive,
1952
+ inlineAuth,
1953
+ createClient: (apiKey) => context.createClient(apiKey)
1954
+ }
1955
+ };
1956
+ }
1957
+ function isInteractive(stdinIsTTY, env, global) {
1958
+ return stdinIsTTY && !env.CI && !env.DROPTHIS_NON_INTERACTIVE && global.interactive !== false;
1959
+ }
1711
1960
  function globalOptions(program, commandOptions) {
1712
1961
  const opts = program.opts();
1713
1962
  return {
1714
1963
  ...opts.apiKey ? { apiKey: opts.apiKey } : {},
1715
1964
  ...opts.apiUrl ? { apiUrl: opts.apiUrl } : {},
1716
1965
  ...commandOptions.json !== void 0 ? { json: commandOptions.json } : opts.json !== void 0 ? { json: opts.json } : {},
1717
- ...commandOptions.quiet !== void 0 ? { quiet: commandOptions.quiet } : opts.quiet !== void 0 ? { quiet: opts.quiet } : {}
1966
+ ...commandOptions.quiet !== void 0 ? { quiet: commandOptions.quiet } : opts.quiet !== void 0 ? { quiet: opts.quiet } : {},
1967
+ ...opts.interactive !== void 0 ? { interactive: opts.interactive } : {}
1718
1968
  };
1719
1969
  }
1720
1970
  function toDropOptions(options) {