stow-cli 2.0.3 → 2.1.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.js CHANGED
@@ -1,334 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ CLI_DOCS,
4
+ renderCommandHelp
5
+ } from "./chunk-XJDK2CBE.js";
2
6
 
3
7
  // src/cli.ts
4
8
  import { StowError } from "@howells/stow-server";
5
9
  import { Command } from "commander";
6
-
7
- // src/lib/cli-docs.ts
8
- var CLI_DOCS = {
9
- root: {
10
- description: "CLI for Stow file storage",
11
- usage: "stow [command] [options]",
12
- examples: [
13
- "stow whoami",
14
- "stow upload ./photo.jpg --bucket photos",
15
- "stow drop ./screenshot.png",
16
- "stow buckets",
17
- "stow files photos --limit 50",
18
- "stow search text 'sunset beach'",
19
- "stow admin health"
20
- ],
21
- notes: [
22
- "Set STOW_API_KEY before running commands that call the API.",
23
- "Set STOW_API_URL to target a non-default environment.",
24
- "Set STOW_ADMIN_SECRET for admin commands."
25
- ]
26
- },
27
- drop: {
28
- description: "Upload a file and get a short URL (quick share)",
29
- usage: "stow drop <file> [options]",
30
- examples: ["stow drop ./video.mp4", "stow drop ./notes.txt --quiet"]
31
- },
32
- upload: {
33
- description: "Upload a file to a bucket",
34
- usage: "stow upload <file> [options]",
35
- examples: [
36
- "stow upload ./logo.png --bucket brand-assets",
37
- "stow upload ./clip.mov --quiet"
38
- ]
39
- },
40
- buckets: {
41
- description: "List your buckets",
42
- usage: "stow buckets",
43
- examples: ["stow buckets"]
44
- },
45
- bucketsCreate: {
46
- description: "Create a new bucket",
47
- usage: "stow buckets create <name> [options]",
48
- examples: [
49
- "stow buckets create photos",
50
- 'stow buckets create docs --description "Product docs"',
51
- "stow buckets create public-media --public"
52
- ]
53
- },
54
- bucketsRename: {
55
- description: "Rename a bucket",
56
- usage: "stow buckets rename <name> <new-name> [options]",
57
- examples: ["stow buckets rename old-name new-name --yes"],
58
- notes: ["Renaming a bucket can break existing public URLs."]
59
- },
60
- bucketsDelete: {
61
- description: "Delete a bucket by ID",
62
- usage: "stow buckets delete <id>",
63
- examples: ["stow buckets delete 8f3d1ab4-..."]
64
- },
65
- files: {
66
- description: "List files in a bucket",
67
- usage: "stow files <bucket> [options]",
68
- examples: [
69
- "stow files photos",
70
- "stow files photos --search avatars/ --limit 100",
71
- "stow files photos --json"
72
- ]
73
- },
74
- filesGet: {
75
- description: "Get details for a single file",
76
- usage: "stow files get <bucket> <key>",
77
- examples: [
78
- "stow files get photos hero.png",
79
- "stow files get photos hero.png --json"
80
- ]
81
- },
82
- filesUpdate: {
83
- description: "Update file metadata",
84
- usage: "stow files update <bucket> <key> -m key=value",
85
- examples: [
86
- "stow files update photos hero.png -m alt='Hero image'",
87
- "stow files update photos hero.png -m category=banner -m priority=high"
88
- ]
89
- },
90
- filesMissing: {
91
- description: "List files missing processing data",
92
- usage: "stow files missing <bucket> <type>",
93
- examples: [
94
- "stow files missing brera dimensions",
95
- "stow files missing brera embeddings --limit 200",
96
- "stow files missing brera colors --json"
97
- ],
98
- notes: ["Valid types: dimensions, embeddings, colors"]
99
- },
100
- filesEnrich: {
101
- description: "Generate title, description, and alt text for an image",
102
- usage: "stow files enrich <bucket> <key>",
103
- examples: [
104
- "stow files enrich photos hero.jpg",
105
- "stow files enrich next l5igro4iutep3"
106
- ],
107
- notes: [
108
- "Triggers title, description, and alt text generation in parallel.",
109
- "Requires a searchable bucket with image files."
110
- ]
111
- },
112
- drops: {
113
- description: "List your drops with usage info",
114
- usage: "stow drops",
115
- examples: ["stow drops"]
116
- },
117
- dropsDelete: {
118
- description: "Delete a drop by ID",
119
- usage: "stow drops delete <id>",
120
- examples: ["stow drops delete drop_abc123"]
121
- },
122
- delete: {
123
- description: "Delete a file from a bucket",
124
- usage: "stow delete <bucket> <key>",
125
- examples: ["stow delete photos hero/banner.png"]
126
- },
127
- whoami: {
128
- description: "Show account info, usage stats, and API key details",
129
- usage: "stow whoami",
130
- examples: ["stow whoami"]
131
- },
132
- open: {
133
- description: "Open a bucket in the browser",
134
- usage: "stow open <bucket>",
135
- examples: ["stow open photos"]
136
- },
137
- interactive: {
138
- description: "Launch interactive TUI mode",
139
- usage: "stow --interactive",
140
- examples: ["stow", "stow --interactive"]
141
- },
142
- search: {
143
- description: "Search files across buckets",
144
- usage: "stow search <subcommand>",
145
- examples: [
146
- "stow search text 'sunset beach' -b photos",
147
- "stow search similar --file hero.png -b photos",
148
- 'stow search color --hex "#ff0000" -b photos',
149
- "stow search diverse -b photos"
150
- ]
151
- },
152
- searchText: {
153
- description: "Semantic text search",
154
- usage: "stow search text <query> [options]",
155
- examples: ["stow search text 'sunset beach' -b photos --limit 10 --json"]
156
- },
157
- searchSimilar: {
158
- description: "Find files similar to a given file",
159
- usage: "stow search similar --file <key> [options]",
160
- examples: ["stow search similar --file hero.png -b photos"]
161
- },
162
- searchColor: {
163
- description: "Search by color",
164
- usage: 'stow search color --hex "#ff0000" [options]',
165
- examples: ['stow search color --hex "#ff0000" -b photos --limit 20']
166
- },
167
- searchDiverse: {
168
- description: "Diversity-aware search",
169
- usage: "stow search diverse [options]",
170
- examples: ["stow search diverse -b photos --limit 20"]
171
- },
172
- tags: {
173
- description: "Manage tags",
174
- usage: "stow tags",
175
- examples: [
176
- "stow tags",
177
- "stow tags create 'Hero Images'",
178
- "stow tags delete <id>"
179
- ]
180
- },
181
- tagsCreate: {
182
- description: "Create a new tag",
183
- usage: "stow tags create <name> [options]",
184
- examples: [
185
- 'stow tags create "Hero Images"',
186
- 'stow tags create "Featured" --color "#ff6600"'
187
- ]
188
- },
189
- tagsDelete: {
190
- description: "Delete a tag by ID",
191
- usage: "stow tags delete <id>",
192
- examples: ["stow tags delete tag_abc123"]
193
- },
194
- profiles: {
195
- description: "Manage taste profiles",
196
- usage: "stow profiles <subcommand>",
197
- examples: [
198
- 'stow profiles create --name "My Profile"',
199
- "stow profiles get <id>",
200
- "stow profiles delete <id>"
201
- ]
202
- },
203
- profilesCreate: {
204
- description: "Create a taste profile",
205
- usage: 'stow profiles create --name "My Profile" [options]',
206
- examples: ['stow profiles create --name "My Profile" -b photos']
207
- },
208
- profilesGet: {
209
- description: "Get a taste profile with clusters",
210
- usage: "stow profiles get <id>",
211
- examples: ["stow profiles get profile_abc123 --json"]
212
- },
213
- profilesDelete: {
214
- description: "Delete a taste profile",
215
- usage: "stow profiles delete <id>",
216
- examples: ["stow profiles delete profile_abc123"]
217
- },
218
- jobs: {
219
- description: "List processing jobs for a bucket",
220
- usage: "stow jobs --bucket <id> [options]",
221
- examples: [
222
- "stow jobs --bucket <id>",
223
- "stow jobs --bucket <id> --status failed",
224
- "stow jobs --bucket <id> --queue extract-colors --json"
225
- ]
226
- },
227
- jobsRetry: {
228
- description: "Retry a failed job",
229
- usage: "stow jobs retry <id> --queue <name> --bucket <id>",
230
- examples: ["stow jobs retry job123 --queue generate-title --bucket <id>"]
231
- },
232
- jobsDelete: {
233
- description: "Remove a job",
234
- usage: "stow jobs delete <id> --queue <name> --bucket <id>",
235
- examples: ["stow jobs delete job123 --queue extract-colors --bucket <id>"]
236
- },
237
- admin: {
238
- description: "Admin commands (requires STOW_ADMIN_SECRET)",
239
- usage: "stow admin <subcommand>",
240
- examples: [
241
- "stow admin health",
242
- "stow admin backfill dimensions --bucket <id> --dry-run",
243
- "stow admin cleanup-drops --dry-run"
244
- ],
245
- notes: ["Requires STOW_ADMIN_SECRET environment variable."]
246
- },
247
- adminHealth: {
248
- description: "Check system health and queue depths",
249
- usage: "stow admin health",
250
- examples: ["stow admin health", "stow admin health --json"]
251
- },
252
- adminBackfill: {
253
- description: "Backfill processing data for files",
254
- usage: "stow admin backfill <type> [options]",
255
- examples: [
256
- "stow admin backfill dimensions --bucket <id> --dry-run",
257
- "stow admin backfill colors --bucket <id> --limit 200",
258
- "stow admin backfill embeddings --bucket <id> --limit 100 --json"
259
- ],
260
- notes: ["Valid types: dimensions, colors, embeddings"]
261
- },
262
- adminCleanupDrops: {
263
- description: "Remove expired drops",
264
- usage: "stow admin cleanup-drops [options]",
265
- examples: ["stow admin cleanup-drops --max-age-hours 24 --dry-run"]
266
- },
267
- adminPurgeEvents: {
268
- description: "Purge old webhook events",
269
- usage: "stow admin purge-events [options]",
270
- examples: ["stow admin purge-events --dry-run"]
271
- },
272
- adminReconcileFiles: {
273
- description: "Reconcile files between R2 and database",
274
- usage: "stow admin reconcile-files --bucket <id>",
275
- examples: ["stow admin reconcile-files --bucket <id> --dry-run"]
276
- },
277
- adminRetrySyncFailures: {
278
- description: "Retry failed S3 sync operations",
279
- usage: "stow admin retry-sync-failures",
280
- examples: ["stow admin retry-sync-failures"]
281
- },
282
- adminJobs: {
283
- description: "List and manage processing jobs",
284
- usage: "stow admin jobs [options]",
285
- examples: [
286
- "stow admin jobs",
287
- "stow admin jobs --status failed",
288
- "stow admin jobs --org <id> --queue generate-title",
289
- "stow admin jobs --json"
290
- ]
291
- },
292
- adminJobsRetry: {
293
- description: "Retry a failed job",
294
- usage: "stow admin jobs retry <id> --queue <name>",
295
- examples: ["stow admin jobs retry job123 --queue generate-title"]
296
- },
297
- adminJobsDelete: {
298
- description: "Remove a job",
299
- usage: "stow admin jobs delete <id> --queue <name>",
300
- examples: ["stow admin jobs delete job123 --queue extract-colors"]
301
- },
302
- adminQueues: {
303
- description: "Show queue depths and counts",
304
- usage: "stow admin queues",
305
- examples: ["stow admin queues", "stow admin queues --json"]
306
- },
307
- adminQueuesClean: {
308
- description: "Clean jobs from a queue",
309
- usage: "stow admin queues clean <name> --failed|--completed",
310
- examples: [
311
- "stow admin queues clean generate-title --failed",
312
- "stow admin queues clean extract-colors --completed --grace 3600"
313
- ]
314
- }
315
- };
316
- function renderCommandHelp(key) {
317
- const doc = CLI_DOCS[key];
318
- const lines = [
319
- "",
320
- `Usage: ${doc.usage}`,
321
- "",
322
- "Examples:",
323
- ...doc.examples.map((example) => ` ${example}`)
324
- ];
325
- if (doc.notes?.length) {
326
- lines.push("", "Notes:", ...doc.notes.map((note) => ` ${note}`));
327
- }
328
- return lines.join("\n");
329
- }
330
-
331
- // src/cli.ts
332
10
  var VERSION = "1.0.0";
333
11
  function handleError(err) {
334
12
  if (err instanceof StowError) {
@@ -344,16 +22,16 @@ var program = new Command();
344
22
  program.name("stow").description(CLI_DOCS.root.description).version(VERSION).addHelpText("after", renderCommandHelp("root"));
345
23
  program.command("drop").description(CLI_DOCS.drop.description).argument("<file>", "File to upload").option("-q, --quiet", "Only output the URL").addHelpText("after", renderCommandHelp("drop")).action(async (file, options) => {
346
24
  try {
347
- const { uploadDrop } = await import("./upload-5RIDB2C5.js");
25
+ const { uploadDrop } = await import("./upload-5TAWJU5N.js");
348
26
  await uploadDrop(file, options);
349
27
  } catch (err) {
350
28
  handleError(err);
351
29
  }
352
30
  });
353
- program.command("upload").description(CLI_DOCS.upload.description).argument("<file>", "File to upload").option("-b, --bucket <name>", "Bucket name or ID").option("-q, --quiet", "Only output the URL").addHelpText("after", renderCommandHelp("upload")).action(
31
+ program.command("upload").description(CLI_DOCS.upload.description).argument("<file>", "File to upload").option("-b, --bucket <name>", "Bucket name or ID").option("-q, --quiet", "Only output the URL").option("--dry-run", "Preview without uploading").addHelpText("after", renderCommandHelp("upload")).action(
354
32
  async (file, options) => {
355
33
  try {
356
- const { uploadFile } = await import("./upload-5RIDB2C5.js");
34
+ const { uploadFile } = await import("./upload-5TAWJU5N.js");
357
35
  await uploadFile(file, options);
358
36
  } catch (err) {
359
37
  handleError(err);
@@ -362,34 +40,36 @@ program.command("upload").description(CLI_DOCS.upload.description).argument("<fi
362
40
  );
363
41
  var bucketsCmd = program.command("buckets").description(CLI_DOCS.buckets.description).addHelpText("after", renderCommandHelp("buckets")).action(async () => {
364
42
  try {
365
- const { listBuckets } = await import("./buckets-NXIVHPW5.js");
43
+ const { listBuckets } = await import("./buckets-ESAOL6CH.js");
366
44
  await listBuckets();
367
45
  } catch (err) {
368
46
  handleError(err);
369
47
  }
370
48
  });
371
- bucketsCmd.command("create").description(CLI_DOCS.bucketsCreate.description).argument("<name>", "Bucket name").option("-d, --description <text>", "Bucket description").option("--public", "Make bucket public").addHelpText("after", renderCommandHelp("bucketsCreate")).action(
49
+ bucketsCmd.command("create").description(CLI_DOCS.bucketsCreate.description).argument("<name>", "Bucket name").option("-d, --description <text>", "Bucket description").option("--public", "Make bucket public").option("--dry-run", "Preview without creating").addHelpText("after", renderCommandHelp("bucketsCreate")).action(
372
50
  async (name, options) => {
373
51
  try {
374
- const { createBucket } = await import("./buckets-NXIVHPW5.js");
52
+ const { createBucket } = await import("./buckets-ESAOL6CH.js");
375
53
  await createBucket(name, options);
376
54
  } catch (err) {
377
55
  handleError(err);
378
56
  }
379
57
  }
380
58
  );
381
- bucketsCmd.command("rename").description(CLI_DOCS.bucketsRename.description).argument("<name>", "Current bucket name").argument("<new-name>", "New bucket name").option("-y, --yes", "Skip confirmation warning").addHelpText("after", renderCommandHelp("bucketsRename")).action(async (name, newName, options) => {
382
- try {
383
- const { renameBucket } = await import("./buckets-NXIVHPW5.js");
384
- await renameBucket(name, newName, options);
385
- } catch (err) {
386
- handleError(err);
59
+ bucketsCmd.command("rename").description(CLI_DOCS.bucketsRename.description).argument("<name>", "Current bucket name").argument("<new-name>", "New bucket name").option("-y, --yes", "Skip confirmation warning").option("--dry-run", "Preview without renaming").addHelpText("after", renderCommandHelp("bucketsRename")).action(
60
+ async (name, newName, options) => {
61
+ try {
62
+ const { renameBucket } = await import("./buckets-ESAOL6CH.js");
63
+ await renameBucket(name, newName, options);
64
+ } catch (err) {
65
+ handleError(err);
66
+ }
387
67
  }
388
- });
389
- bucketsCmd.command("delete").description(CLI_DOCS.bucketsDelete.description).argument("<id>", "Bucket ID").addHelpText("after", renderCommandHelp("bucketsDelete")).action(async (id) => {
68
+ );
69
+ bucketsCmd.command("delete").description(CLI_DOCS.bucketsDelete.description).argument("<id>", "Bucket ID").option("--dry-run", "Preview without deleting").addHelpText("after", renderCommandHelp("bucketsDelete")).action(async (id, options) => {
390
70
  try {
391
- const { deleteBucket } = await import("./buckets-NXIVHPW5.js");
392
- await deleteBucket(id);
71
+ const { deleteBucket } = await import("./buckets-ESAOL6CH.js");
72
+ await deleteBucket(id, options);
393
73
  } catch (err) {
394
74
  handleError(err);
395
75
  }
@@ -401,7 +81,7 @@ var filesCmd = program.command("files").description(CLI_DOCS.files.description).
401
81
  return;
402
82
  }
403
83
  try {
404
- const { listFiles } = await import("./files-E662TXUP.js");
84
+ const { listFiles } = await import("./files-TDIGJDN3.js");
405
85
  await listFiles(bucket, options);
406
86
  } catch (err) {
407
87
  handleError(err);
@@ -410,16 +90,16 @@ var filesCmd = program.command("files").description(CLI_DOCS.files.description).
410
90
  );
411
91
  filesCmd.command("get").description(CLI_DOCS.filesGet.description).argument("<bucket>", "Bucket name").argument("<key>", "File key").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("filesGet")).action(async (bucket, key, options) => {
412
92
  try {
413
- const { getFile } = await import("./files-E662TXUP.js");
93
+ const { getFile } = await import("./files-TDIGJDN3.js");
414
94
  await getFile(bucket, key, options);
415
95
  } catch (err) {
416
96
  handleError(err);
417
97
  }
418
98
  });
419
- filesCmd.command("update").description(CLI_DOCS.filesUpdate.description).argument("<bucket>", "Bucket name").argument("<key>", "File key").option("-m, --metadata <kv...>", "Metadata key=value pairs").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("filesUpdate")).action(
99
+ filesCmd.command("update").description(CLI_DOCS.filesUpdate.description).argument("<bucket>", "Bucket name").argument("<key>", "File key").option("-m, --metadata <kv...>", "Metadata key=value pairs").option("--json", "Output as JSON").option("--dry-run", "Preview without updating").addHelpText("after", renderCommandHelp("filesUpdate")).action(
420
100
  async (bucket, key, options) => {
421
101
  try {
422
- const { updateFile } = await import("./files-E662TXUP.js");
102
+ const { updateFile } = await import("./files-TDIGJDN3.js");
423
103
  await updateFile(bucket, key, options);
424
104
  } catch (err) {
425
105
  handleError(err);
@@ -428,7 +108,7 @@ filesCmd.command("update").description(CLI_DOCS.filesUpdate.description).argumen
428
108
  );
429
109
  filesCmd.command("enrich").description(CLI_DOCS.filesEnrich.description).argument("<bucket>", "Bucket name").argument("<key>", "File key").addHelpText("after", renderCommandHelp("filesEnrich")).action(async (bucket, key) => {
430
110
  try {
431
- const { enrichFile } = await import("./files-E662TXUP.js");
111
+ const { enrichFile } = await import("./files-TDIGJDN3.js");
432
112
  await enrichFile(bucket, key);
433
113
  } catch (err) {
434
114
  handleError(err);
@@ -437,7 +117,7 @@ filesCmd.command("enrich").description(CLI_DOCS.filesEnrich.description).argumen
437
117
  filesCmd.command("missing").description(CLI_DOCS.filesMissing.description).argument("<bucket>", "Bucket name").argument("<type>", "dimensions | embeddings | colors").option("-l, --limit <count>", "Max files to return").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("filesMissing")).action(
438
118
  async (bucket, type, options) => {
439
119
  try {
440
- const { listMissing } = await import("./files-E662TXUP.js");
120
+ const { listMissing } = await import("./files-TDIGJDN3.js");
441
121
  await listMissing(bucket, type, options);
442
122
  } catch (err) {
443
123
  handleError(err);
@@ -503,24 +183,26 @@ searchCmd.command("diverse").description(CLI_DOCS.searchDiverse.description).opt
503
183
  );
504
184
  var tagsCmd = program.command("tags").description(CLI_DOCS.tags.description).option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("tags")).action(async (options) => {
505
185
  try {
506
- const { listTags } = await import("./tags-URHK2YH5.js");
186
+ const { listTags } = await import("./tags-MCFL5M2J.js");
507
187
  await listTags(options);
508
188
  } catch (err) {
509
189
  handleError(err);
510
190
  }
511
191
  });
512
- tagsCmd.command("create").description(CLI_DOCS.tagsCreate.description).argument("<name>", "Tag name").option("--color <hex>", "Tag color (hex)").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("tagsCreate")).action(async (name, options) => {
513
- try {
514
- const { createTag } = await import("./tags-URHK2YH5.js");
515
- await createTag(name, options);
516
- } catch (err) {
517
- handleError(err);
192
+ tagsCmd.command("create").description(CLI_DOCS.tagsCreate.description).argument("<name>", "Tag name").option("--color <hex>", "Tag color (hex)").option("--json", "Output as JSON").option("--dry-run", "Preview without creating").addHelpText("after", renderCommandHelp("tagsCreate")).action(
193
+ async (name, options) => {
194
+ try {
195
+ const { createTag } = await import("./tags-MCFL5M2J.js");
196
+ await createTag(name, options);
197
+ } catch (err) {
198
+ handleError(err);
199
+ }
518
200
  }
519
- });
520
- tagsCmd.command("delete").description(CLI_DOCS.tagsDelete.description).argument("<id>", "Tag ID").addHelpText("after", renderCommandHelp("tagsDelete")).action(async (id) => {
201
+ );
202
+ tagsCmd.command("delete").description(CLI_DOCS.tagsDelete.description).argument("<id>", "Tag ID").option("--dry-run", "Preview without deleting").addHelpText("after", renderCommandHelp("tagsDelete")).action(async (id, options) => {
521
203
  try {
522
- const { deleteTag } = await import("./tags-URHK2YH5.js");
523
- await deleteTag(id);
204
+ const { deleteTag } = await import("./tags-MCFL5M2J.js");
205
+ await deleteTag(id, options);
524
206
  } catch (err) {
525
207
  handleError(err);
526
208
  }
@@ -698,14 +380,16 @@ adminQueuesCmd.command("clean").description(CLI_DOCS.adminQueuesClean.descriptio
698
380
  }
699
381
  }
700
382
  );
701
- program.command("delete").description(CLI_DOCS.delete.description).argument("<bucket>", "Bucket name").argument("<key>", "File key").addHelpText("after", renderCommandHelp("delete")).action(async (bucket, key) => {
702
- try {
703
- const { deleteFile } = await import("./delete-GEX3O7YS.js");
704
- await deleteFile(bucket, key);
705
- } catch (err) {
706
- handleError(err);
383
+ program.command("delete").description(CLI_DOCS.delete.description).argument("<bucket>", "Bucket name").argument("<key>", "File key").option("--dry-run", "Preview without deleting").addHelpText("after", renderCommandHelp("delete")).action(
384
+ async (bucket, key, options) => {
385
+ try {
386
+ const { deleteFile } = await import("./delete-4JSVNETO.js");
387
+ await deleteFile(bucket, key, options);
388
+ } catch (err) {
389
+ handleError(err);
390
+ }
707
391
  }
708
- });
392
+ );
709
393
  program.command("whoami").description(CLI_DOCS.whoami.description).addHelpText("after", renderCommandHelp("whoami")).action(async () => {
710
394
  try {
711
395
  const { whoami } = await import("./whoami-5IYRZKWS.js");
@@ -722,6 +406,22 @@ program.command("open").description(CLI_DOCS.open.description).argument("<bucket
722
406
  handleError(err);
723
407
  }
724
408
  });
409
+ program.command("describe").argument("[command]", "Command path (dot notation, e.g. search.text)").description("Show command schema for AI agents").action(async (command) => {
410
+ try {
411
+ const { describeCommand } = await import("./describe-UFMXNNUB.js");
412
+ describeCommand(command ?? "");
413
+ } catch (err) {
414
+ handleError(err);
415
+ }
416
+ });
417
+ program.command("mcp").description("Start MCP stdio server for AI agent integration").action(async () => {
418
+ try {
419
+ const { startMcpServer } = await import("./mcp-RZT4TJEX.js");
420
+ await startMcpServer();
421
+ } catch (err) {
422
+ handleError(err);
423
+ }
424
+ });
725
425
  program.option("-i, --interactive", CLI_DOCS.interactive.description).addHelpText("after", renderCommandHelp("interactive"));
726
426
  program.parse();
727
427
  var opts = program.opts();
@@ -0,0 +1,34 @@
1
+ import {
2
+ validateBucketName,
3
+ validateFileKey
4
+ } from "./chunk-OHAFRKN5.js";
5
+ import {
6
+ createStow
7
+ } from "./chunk-5LU25QZK.js";
8
+ import "./chunk-TOADDO2F.js";
9
+
10
+ // src/commands/delete.ts
11
+ async function deleteFile(bucket, key, options = {}) {
12
+ validateBucketName(bucket);
13
+ validateFileKey(key);
14
+ if (options.dryRun) {
15
+ console.log(
16
+ JSON.stringify(
17
+ {
18
+ dryRun: true,
19
+ action: "deleteFile",
20
+ details: { bucket, key }
21
+ },
22
+ null,
23
+ 2
24
+ )
25
+ );
26
+ return;
27
+ }
28
+ const stow = createStow();
29
+ await stow.deleteFile(key, { bucket });
30
+ console.log(`Deleted: ${key} from ${bucket}`);
31
+ }
32
+ export {
33
+ deleteFile
34
+ };
@@ -0,0 +1,79 @@
1
+ import {
2
+ CLI_DOCS
3
+ } from "./chunk-XJDK2CBE.js";
4
+ import {
5
+ outputJson
6
+ } from "./chunk-ELSDWMEB.js";
7
+
8
+ // src/commands/describe.ts
9
+ var COMMAND_MAP = {
10
+ upload: "upload",
11
+ drop: "drop",
12
+ delete: "delete",
13
+ whoami: "whoami",
14
+ open: "open",
15
+ buckets: "buckets",
16
+ "buckets.create": "bucketsCreate",
17
+ "buckets.rename": "bucketsRename",
18
+ "buckets.delete": "bucketsDelete",
19
+ files: "files",
20
+ "files.get": "filesGet",
21
+ "files.update": "filesUpdate",
22
+ "files.enrich": "filesEnrich",
23
+ "files.missing": "filesMissing",
24
+ search: "search",
25
+ "search.text": "searchText",
26
+ "search.similar": "searchSimilar",
27
+ "search.color": "searchColor",
28
+ "search.diverse": "searchDiverse",
29
+ tags: "tags",
30
+ "tags.create": "tagsCreate",
31
+ "tags.delete": "tagsDelete",
32
+ drops: "drops",
33
+ "drops.delete": "dropsDelete",
34
+ profiles: "profiles",
35
+ "profiles.create": "profilesCreate",
36
+ "profiles.get": "profilesGet",
37
+ "profiles.delete": "profilesDelete",
38
+ jobs: "jobs",
39
+ "jobs.retry": "jobsRetry",
40
+ "jobs.delete": "jobsDelete",
41
+ admin: "admin",
42
+ "admin.health": "adminHealth",
43
+ "admin.backfill": "adminBackfill",
44
+ "admin.cleanup-drops": "adminCleanupDrops",
45
+ "admin.purge-events": "adminPurgeEvents",
46
+ "admin.reconcile-files": "adminReconcileFiles",
47
+ "admin.retry-sync-failures": "adminRetrySyncFailures",
48
+ "admin.jobs": "adminJobs",
49
+ "admin.jobs.retry": "adminJobsRetry",
50
+ "admin.jobs.delete": "adminJobsDelete",
51
+ "admin.queues": "adminQueues",
52
+ "admin.queues.clean": "adminQueuesClean"
53
+ };
54
+ function describeCommand(commandPath) {
55
+ if (!commandPath) {
56
+ outputJson({
57
+ commands: Object.keys(COMMAND_MAP).sort()
58
+ });
59
+ return;
60
+ }
61
+ const docKey = COMMAND_MAP[commandPath];
62
+ if (!docKey || !CLI_DOCS[docKey]) {
63
+ console.error(`Unknown command: ${commandPath}`);
64
+ console.error(`Available: ${Object.keys(COMMAND_MAP).sort().join(", ")}`);
65
+ process.exit(1);
66
+ return;
67
+ }
68
+ const doc = CLI_DOCS[docKey];
69
+ outputJson({
70
+ command: commandPath,
71
+ description: doc.description,
72
+ usage: doc.usage,
73
+ examples: doc.examples,
74
+ notes: doc.notes ?? []
75
+ });
76
+ }
77
+ export {
78
+ describeCommand
79
+ };