stow-cli 2.2.3 → 2.3.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.
@@ -0,0 +1,318 @@
1
+ // src/lib/cli-docs.ts
2
+ var CLI_DOCS = {
3
+ root: {
4
+ description: "CLI for Stow file storage",
5
+ usage: "stow [command] [options]",
6
+ examples: [
7
+ "stow whoami",
8
+ "stow upload ./photo.jpg --bucket photos",
9
+ "stow drop ./screenshot.png",
10
+ "stow buckets",
11
+ "stow files photos --limit 50",
12
+ "stow search text 'sunset beach'",
13
+ "stow admin health"
14
+ ],
15
+ notes: [
16
+ "Set STOW_API_KEY before running commands that call the API.",
17
+ "Set STOW_API_URL to target a non-default environment.",
18
+ "Set STOW_ADMIN_SECRET for admin commands."
19
+ ]
20
+ },
21
+ drop: {
22
+ description: "Upload a file and get a short URL (quick share)",
23
+ usage: "stow drop <file> [options]",
24
+ examples: ["stow drop ./video.mp4", "stow drop ./notes.txt --quiet"]
25
+ },
26
+ upload: {
27
+ description: "Upload a file to a bucket",
28
+ usage: "stow upload <file> [options]",
29
+ examples: ["stow upload ./logo.png --bucket brand-assets", "stow upload ./clip.mov --quiet"]
30
+ },
31
+ buckets: {
32
+ description: "List your buckets",
33
+ usage: "stow buckets",
34
+ examples: ["stow buckets"]
35
+ },
36
+ bucketsCreate: {
37
+ description: "Create a new bucket",
38
+ usage: "stow buckets create <name> [options]",
39
+ examples: [
40
+ "stow buckets create photos",
41
+ 'stow buckets create docs --description "Product docs"',
42
+ "stow buckets create public-media --public"
43
+ ]
44
+ },
45
+ bucketsRename: {
46
+ description: "Rename a bucket",
47
+ usage: "stow buckets rename <name> <new-name> [options]",
48
+ examples: ["stow buckets rename old-name new-name --yes"],
49
+ notes: ["Renaming a bucket can break existing public URLs."]
50
+ },
51
+ bucketsDelete: {
52
+ description: "Delete a bucket by ID",
53
+ usage: "stow buckets delete <id>",
54
+ examples: ["stow buckets delete 8f3d1ab4-..."]
55
+ },
56
+ files: {
57
+ description: "List files in a bucket",
58
+ usage: "stow files <bucket> [options]",
59
+ examples: [
60
+ "stow files photos",
61
+ "stow files photos --search avatars/ --limit 100",
62
+ "stow files photos --json"
63
+ ]
64
+ },
65
+ filesGet: {
66
+ description: "Get details for a single file",
67
+ usage: "stow files get <bucket> <key>",
68
+ examples: ["stow files get photos hero.png", "stow files get photos hero.png --json"]
69
+ },
70
+ filesUpdate: {
71
+ description: "Update file metadata",
72
+ usage: "stow files update <bucket> <key> -m key=value",
73
+ examples: [
74
+ "stow files update photos hero.png -m alt='Hero image'",
75
+ "stow files update photos hero.png -m category=banner -m priority=high"
76
+ ]
77
+ },
78
+ filesMissing: {
79
+ description: "List files missing processing data",
80
+ usage: "stow files missing <bucket> <type>",
81
+ examples: [
82
+ "stow files missing brera dimensions",
83
+ "stow files missing brera embeddings --limit 200",
84
+ "stow files missing brera colors --json"
85
+ ],
86
+ notes: ["Valid types: dimensions, embeddings, colors"]
87
+ },
88
+ filesEnrich: {
89
+ description: "Generate title, description, and alt text for an image",
90
+ usage: "stow files enrich <bucket> <key>",
91
+ examples: ["stow files enrich photos hero.jpg", "stow files enrich next l5igro4iutep3"],
92
+ notes: [
93
+ "Triggers title, description, and alt text generation in parallel.",
94
+ "Requires a searchable bucket with image files."
95
+ ]
96
+ },
97
+ drops: {
98
+ description: "List your drops with usage info",
99
+ usage: "stow drops",
100
+ examples: ["stow drops"]
101
+ },
102
+ dropsDelete: {
103
+ description: "Delete a drop by ID",
104
+ usage: "stow drops delete <id>",
105
+ examples: ["stow drops delete drop_abc123"]
106
+ },
107
+ delete: {
108
+ description: "Delete a file from a bucket",
109
+ usage: "stow delete <bucket> <key>",
110
+ examples: ["stow delete photos hero/banner.png"]
111
+ },
112
+ whoami: {
113
+ description: "Show account info, usage stats, and API key details",
114
+ usage: "stow whoami",
115
+ examples: ["stow whoami"]
116
+ },
117
+ open: {
118
+ description: "Open a bucket in the browser",
119
+ usage: "stow open <bucket>",
120
+ examples: ["stow open photos"]
121
+ },
122
+ interactive: {
123
+ description: "Launch interactive TUI mode",
124
+ usage: "stow --interactive",
125
+ examples: ["stow", "stow --interactive"]
126
+ },
127
+ search: {
128
+ description: "Search files across buckets",
129
+ usage: "stow search <subcommand>",
130
+ examples: [
131
+ "stow search text 'sunset beach' -b photos",
132
+ "stow search similar --file hero.png -b photos",
133
+ 'stow search color --hex "#ff0000" -b photos',
134
+ "stow search diverse -b photos"
135
+ ]
136
+ },
137
+ searchText: {
138
+ description: "Semantic text search",
139
+ usage: "stow search text <query> [options]",
140
+ examples: ["stow search text 'sunset beach' -b photos --limit 10 --json"]
141
+ },
142
+ searchSimilar: {
143
+ description: "Find files similar to a given file",
144
+ usage: "stow search similar --file <key> [options]",
145
+ examples: ["stow search similar --file hero.png -b photos"]
146
+ },
147
+ searchColor: {
148
+ description: "Search by color (hex, name, palette, or mood)",
149
+ usage: "stow search color [--hex|--name|--palette|--mood-temp + --mood-light] [options]",
150
+ examples: [
151
+ 'stow search color --hex "#ff6b35" -b photos',
152
+ "stow search color --name terracotta --limit 20",
153
+ 'stow search color --palette "#d94e1f" "#264066" -b products',
154
+ "stow search color --mood-temp 0.8 --mood-light 0.4",
155
+ 'stow search color --hex "#336633" --dominant-only --min-proportion 0.2'
156
+ ]
157
+ },
158
+ searchDiverse: {
159
+ description: "Diversity-aware search",
160
+ usage: "stow search diverse [options]",
161
+ examples: ["stow search diverse -b photos --limit 20"]
162
+ },
163
+ tags: {
164
+ description: "Manage tags",
165
+ usage: "stow tags",
166
+ examples: ["stow tags", "stow tags create 'Hero Images'", "stow tags delete <id>"]
167
+ },
168
+ tagsCreate: {
169
+ description: "Create a new tag",
170
+ usage: "stow tags create <name> [options]",
171
+ examples: ['stow tags create "Hero Images"', 'stow tags create "Featured" --color "#ff6600"']
172
+ },
173
+ tagsDelete: {
174
+ description: "Delete a tag by ID",
175
+ usage: "stow tags delete <id>",
176
+ examples: ["stow tags delete tag_abc123"]
177
+ },
178
+ profiles: {
179
+ description: "Manage taste profiles",
180
+ usage: "stow profiles <subcommand>",
181
+ examples: [
182
+ 'stow profiles create --name "My Profile"',
183
+ "stow profiles get <id>",
184
+ "stow profiles delete <id>"
185
+ ]
186
+ },
187
+ profilesCreate: {
188
+ description: "Create a taste profile",
189
+ usage: 'stow profiles create --name "My Profile" [options]',
190
+ examples: ['stow profiles create --name "My Profile" -b photos']
191
+ },
192
+ profilesGet: {
193
+ description: "Get a taste profile with clusters",
194
+ usage: "stow profiles get <id>",
195
+ examples: ["stow profiles get profile_abc123 --json"]
196
+ },
197
+ profilesDelete: {
198
+ description: "Delete a taste profile",
199
+ usage: "stow profiles delete <id>",
200
+ examples: ["stow profiles delete profile_abc123"]
201
+ },
202
+ jobs: {
203
+ description: "List processing jobs for a bucket",
204
+ usage: "stow jobs --bucket <id> [options]",
205
+ examples: [
206
+ "stow jobs --bucket <id>",
207
+ "stow jobs --bucket <id> --status failed",
208
+ "stow jobs --bucket <id> --queue extract-colors --json"
209
+ ]
210
+ },
211
+ jobsRetry: {
212
+ description: "Retry a failed job",
213
+ usage: "stow jobs retry <id> --queue <name> --bucket <id>",
214
+ examples: ["stow jobs retry job123 --queue generate-title --bucket <id>"]
215
+ },
216
+ jobsDelete: {
217
+ description: "Remove a job",
218
+ usage: "stow jobs delete <id> --queue <name> --bucket <id>",
219
+ examples: ["stow jobs delete job123 --queue extract-colors --bucket <id>"]
220
+ },
221
+ admin: {
222
+ description: "Admin commands (requires STOW_ADMIN_SECRET)",
223
+ usage: "stow admin <subcommand>",
224
+ examples: [
225
+ "stow admin health",
226
+ "stow admin backfill dimensions --bucket <id> --dry-run",
227
+ "stow admin cleanup-drops --dry-run"
228
+ ],
229
+ notes: ["Requires STOW_ADMIN_SECRET environment variable."]
230
+ },
231
+ adminHealth: {
232
+ description: "Check system health and queue depths",
233
+ usage: "stow admin health",
234
+ examples: ["stow admin health", "stow admin health --json"]
235
+ },
236
+ adminBackfill: {
237
+ description: "Backfill processing data for files",
238
+ usage: "stow admin backfill <type> [options]",
239
+ examples: [
240
+ "stow admin backfill dimensions --bucket <id> --dry-run",
241
+ "stow admin backfill colors --bucket <id> --limit 200",
242
+ "stow admin backfill embeddings --bucket <id> --limit 100 --json"
243
+ ],
244
+ notes: ["Valid types: dimensions, colors, embeddings"]
245
+ },
246
+ adminCleanupDrops: {
247
+ description: "Remove expired drops",
248
+ usage: "stow admin cleanup-drops [options]",
249
+ examples: ["stow admin cleanup-drops --max-age-hours 24 --dry-run"]
250
+ },
251
+ adminPurgeEvents: {
252
+ description: "Purge old webhook events",
253
+ usage: "stow admin purge-events [options]",
254
+ examples: ["stow admin purge-events --dry-run"]
255
+ },
256
+ adminReconcileFiles: {
257
+ description: "Reconcile files between R2 and database",
258
+ usage: "stow admin reconcile-files --bucket <id>",
259
+ examples: ["stow admin reconcile-files --bucket <id> --dry-run"]
260
+ },
261
+ adminRetrySyncFailures: {
262
+ description: "Retry failed S3 sync operations",
263
+ usage: "stow admin retry-sync-failures",
264
+ examples: ["stow admin retry-sync-failures"]
265
+ },
266
+ adminJobs: {
267
+ description: "List and manage processing jobs",
268
+ usage: "stow admin jobs [options]",
269
+ examples: [
270
+ "stow admin jobs",
271
+ "stow admin jobs --status failed",
272
+ "stow admin jobs --org <id> --queue generate-title",
273
+ "stow admin jobs --json"
274
+ ]
275
+ },
276
+ adminJobsRetry: {
277
+ description: "Retry a failed job",
278
+ usage: "stow admin jobs retry <id> --queue <name>",
279
+ examples: ["stow admin jobs retry job123 --queue generate-title"]
280
+ },
281
+ adminJobsDelete: {
282
+ description: "Remove a job",
283
+ usage: "stow admin jobs delete <id> --queue <name>",
284
+ examples: ["stow admin jobs delete job123 --queue extract-colors"]
285
+ },
286
+ adminQueues: {
287
+ description: "Show queue depths and counts",
288
+ usage: "stow admin queues",
289
+ examples: ["stow admin queues", "stow admin queues --json"]
290
+ },
291
+ adminQueuesClean: {
292
+ description: "Clean jobs from a queue",
293
+ usage: "stow admin queues clean <name> --failed|--completed",
294
+ examples: [
295
+ "stow admin queues clean generate-title --failed",
296
+ "stow admin queues clean extract-colors --completed --grace 3600"
297
+ ]
298
+ }
299
+ };
300
+ function renderCommandHelp(key) {
301
+ const doc = CLI_DOCS[key];
302
+ const lines = [
303
+ "",
304
+ `Usage: ${doc.usage}`,
305
+ "",
306
+ "Examples:",
307
+ ...doc.examples.map((example) => ` ${example}`)
308
+ ];
309
+ if (doc.notes?.length) {
310
+ lines.push("", "Notes:", ...doc.notes.map((note) => ` ${note}`));
311
+ }
312
+ return lines.join("\n");
313
+ }
314
+
315
+ export {
316
+ CLI_DOCS,
317
+ renderCommandHelp
318
+ };
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CLI_DOCS,
4
4
  renderCommandHelp
5
- } from "./chunk-MYFLRBWC.js";
5
+ } from "./chunk-JXITFFWI.js";
6
6
  import {
7
7
  InputValidationError
8
8
  } from "./chunk-NBHBVKP5.js";
@@ -163,7 +163,7 @@ dropsCmd.command("delete").description(CLI_DOCS.dropsDelete.description).argumen
163
163
  var searchCmd = program.command("search").description(CLI_DOCS.search.description).addHelpText("after", renderCommandHelp("search"));
164
164
  searchCmd.command("text").description(CLI_DOCS.searchText.description).argument("<query>", "Search query").option("-b, --bucket <name>", "Bucket name").option("-l, --limit <count>", "Max results").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("searchText")).action(async (query, options) => {
165
165
  try {
166
- const { textSearch } = await import("./search-UWLK4OL2.js");
166
+ const { textSearch } = await import("./search-KBJSWH35.js");
167
167
  await textSearch(query, options);
168
168
  } catch (error) {
169
169
  handleError(error);
@@ -171,23 +171,25 @@ searchCmd.command("text").description(CLI_DOCS.searchText.description).argument(
171
171
  });
172
172
  searchCmd.command("similar").description(CLI_DOCS.searchSimilar.description).requiredOption("--file <key>", "File key to search from").option("-b, --bucket <name>", "Bucket name").option("-l, --limit <count>", "Max results").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("searchSimilar")).action(async (options) => {
173
173
  try {
174
- const { similarSearch } = await import("./search-UWLK4OL2.js");
174
+ const { similarSearch } = await import("./search-KBJSWH35.js");
175
175
  await similarSearch(options);
176
176
  } catch (error) {
177
177
  handleError(error);
178
178
  }
179
179
  });
180
- searchCmd.command("color").description(CLI_DOCS.searchColor.description).requiredOption("--hex <color>", "Hex color code").option("-b, --bucket <name>", "Bucket name").option("-l, --limit <count>", "Max results").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("searchColor")).action(async (options) => {
181
- try {
182
- const { colorSearch } = await import("./search-UWLK4OL2.js");
183
- await colorSearch(options);
184
- } catch (error) {
185
- handleError(error);
180
+ searchCmd.command("color").description(CLI_DOCS.searchColor.description).option("--hex <color>", "Hex color code (e.g. #ff6b35)").option("--name <name>", "Color name (e.g. terracotta, sage, navy)").option("--palette <colors...>", "2-5 hex colors for palette search").option("--mood-temp <value>", "Mood temperature: -1 (cool) to 1 (warm)").option("--mood-light <value>", "Mood lightness: 0 (dark) to 1 (light)").option("-b, --bucket <name>", "Bucket name").option("-l, --limit <count>", "Max results").option("--dominant-only", "Only match dominant color per file").option("--min-proportion <value>", "Minimum color proportion (0-1)").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("searchColor")).action(
181
+ async (options) => {
182
+ try {
183
+ const { colorSearch } = await import("./search-KBJSWH35.js");
184
+ await colorSearch(options);
185
+ } catch (error) {
186
+ handleError(error);
187
+ }
186
188
  }
187
- });
189
+ );
188
190
  searchCmd.command("diverse").description(CLI_DOCS.searchDiverse.description).option("-b, --bucket <name>", "Bucket name").option("-l, --limit <count>", "Max results").option("--json", "Output as JSON").addHelpText("after", renderCommandHelp("searchDiverse")).action(async (options) => {
189
191
  try {
190
- const { diverseSearch } = await import("./search-UWLK4OL2.js");
192
+ const { diverseSearch } = await import("./search-KBJSWH35.js");
191
193
  await diverseSearch(options);
192
194
  } catch (error) {
193
195
  handleError(error);
@@ -412,7 +414,7 @@ program.command("open").description(CLI_DOCS.open.description).argument("<bucket
412
414
  });
413
415
  program.command("describe").argument("[command]", "Command path (dot notation, e.g. search.text)").description("Show command schema for AI agents").action(async (command) => {
414
416
  try {
415
- const { describeCommand } = await import("./describe-NH3K3LLW.js");
417
+ const { describeCommand } = await import("./describe-TGIXQHN6.js");
416
418
  describeCommand(command ?? "");
417
419
  } catch (error) {
418
420
  handleError(error);
@@ -0,0 +1,79 @@
1
+ import {
2
+ CLI_DOCS
3
+ } from "./chunk-JXITFFWI.js";
4
+ import {
5
+ output
6
+ } from "./chunk-KPIQZBTO.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
+ output({
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
+ output({
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
+ };
@@ -0,0 +1,134 @@
1
+ import {
2
+ isJsonOutput,
3
+ output
4
+ } from "./chunk-KPIQZBTO.js";
5
+ import {
6
+ formatBytes,
7
+ formatTable
8
+ } from "./chunk-PE6V3MVP.js";
9
+ import {
10
+ createStow
11
+ } from "./chunk-5LU25QZK.js";
12
+ import "./chunk-TOADDO2F.js";
13
+
14
+ // src/commands/search.ts
15
+ async function textSearch(query, options) {
16
+ const stow = createStow();
17
+ const parsedLimit = options.limit ? Number.parseInt(options.limit, 10) : null;
18
+ const data = await stow.search.text({
19
+ query,
20
+ ...options.bucket ? { bucket: options.bucket } : {},
21
+ ...parsedLimit && parsedLimit > 0 ? { limit: parsedLimit } : {}
22
+ });
23
+ if (data.results.length === 0) {
24
+ if (isJsonOutput() || options.json) {
25
+ output(data);
26
+ } else {
27
+ console.log("No results found.");
28
+ }
29
+ return;
30
+ }
31
+ output(
32
+ data,
33
+ () => {
34
+ const rows = data.results.map((r) => [r.key, formatBytes(r.size), r.similarity.toFixed(3)]);
35
+ return formatTable(["Key", "Size", "Similarity"], rows);
36
+ },
37
+ { json: options.json }
38
+ );
39
+ }
40
+ async function similarSearch(options) {
41
+ const stow = createStow();
42
+ const parsedLimit = options.limit ? Number.parseInt(options.limit, 10) : null;
43
+ const data = await stow.search.similar({
44
+ fileKey: options.file,
45
+ ...options.bucket ? { bucket: options.bucket } : {},
46
+ ...parsedLimit && parsedLimit > 0 ? { limit: parsedLimit } : {}
47
+ });
48
+ if (data.results.length === 0) {
49
+ if (isJsonOutput() || options.json) {
50
+ output(data);
51
+ } else {
52
+ console.log("No similar files found.");
53
+ }
54
+ return;
55
+ }
56
+ output(
57
+ data,
58
+ () => {
59
+ const rows = data.results.map((r) => [r.key, formatBytes(r.size), r.similarity.toFixed(3)]);
60
+ return formatTable(["Key", "Size", "Similarity"], rows);
61
+ },
62
+ { json: options.json }
63
+ );
64
+ }
65
+ async function colorSearch(options) {
66
+ const hasInput = options.hex || options.name || options.palette || options.moodTemp && options.moodLight;
67
+ if (!hasInput) {
68
+ console.error("Provide one of: --hex, --name, --palette, or --mood-temp + --mood-light");
69
+ process.exit(1);
70
+ }
71
+ const stow = createStow();
72
+ const parsedLimit = options.limit ? Number.parseInt(options.limit, 10) : null;
73
+ const mood = options.moodTemp !== void 0 && options.moodLight !== void 0 ? {
74
+ temperature: Number.parseFloat(options.moodTemp),
75
+ lightness: Number.parseFloat(options.moodLight)
76
+ } : void 0;
77
+ const minProportion = options.minProportion ? Number.parseFloat(options.minProportion) : void 0;
78
+ const data = await stow.search.color({
79
+ ...options.hex ? { hex: options.hex } : {},
80
+ ...options.name ? { name: options.name } : {},
81
+ ...options.palette ? { palette: options.palette } : {},
82
+ ...mood ? { mood } : {},
83
+ ...options.bucket ? { bucket: options.bucket } : {},
84
+ ...parsedLimit && parsedLimit > 0 ? { limit: parsedLimit } : {},
85
+ ...options.dominantOnly ? { dominantOnly: true } : {},
86
+ ...minProportion !== void 0 ? { minProportion } : {}
87
+ });
88
+ if (data.results.length === 0) {
89
+ if (isJsonOutput() || options.json) {
90
+ output(data);
91
+ } else {
92
+ console.log("No results found.");
93
+ }
94
+ return;
95
+ }
96
+ output(
97
+ data,
98
+ () => {
99
+ const rows = data.results.map((r) => [r.key, r.contentType, r.colorDistance.toFixed(3)]);
100
+ return formatTable(["Key", "Type", "Distance"], rows);
101
+ },
102
+ { json: options.json }
103
+ );
104
+ }
105
+ async function diverseSearch(options) {
106
+ const stow = createStow();
107
+ const parsedLimit = options.limit ? Number.parseInt(options.limit, 10) : null;
108
+ const data = await stow.search.diverse({
109
+ ...options.bucket ? { bucket: options.bucket } : {},
110
+ ...parsedLimit && parsedLimit > 0 ? { limit: parsedLimit } : {}
111
+ });
112
+ if (data.results.length === 0) {
113
+ if (isJsonOutput() || options.json) {
114
+ output(data);
115
+ } else {
116
+ console.log("No results found.");
117
+ }
118
+ return;
119
+ }
120
+ output(
121
+ data,
122
+ () => {
123
+ const rows = data.results.map((r) => [r.key, formatBytes(r.size), r.similarity.toFixed(3)]);
124
+ return formatTable(["Key", "Size", "Similarity"], rows);
125
+ },
126
+ { json: options.json }
127
+ );
128
+ }
129
+ export {
130
+ colorSearch,
131
+ diverseSearch,
132
+ similarSearch,
133
+ textSearch
134
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stow-cli",
3
- "version": "2.2.3",
3
+ "version": "2.3.0",
4
4
  "description": "CLI for Stow file storage",
5
5
  "keywords": [
6
6
  "cli",