@rankwrangler/cli 0.8.0 → 0.10.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/README.md CHANGED
@@ -7,6 +7,7 @@ npm install -g @rankwrangler/cli
7
7
 
8
8
  rw auth set ak_...
9
9
  rw product get B0DV53VS61
10
+ rw product get B0DV53VS61 --shortName
10
11
  rw product search "retro gardening shirt"
11
12
  rw product history B0DV53VS61 --bucket week
12
13
  rw keyword get "retro gardening shirt"
@@ -20,5 +21,7 @@ data and expose no refresh control; Product search retains its separate search c
20
21
  data contains `keyword`, `searchedAt`, and compact results with `organicSearchPlacement`. Output is
21
22
  a JSON `{ ok, data }` envelope; failures use `{ ok: false, error }` on stderr.
22
23
  The CLI does not expose Catalog, Operation, provider status, or polling commands.
24
+ `--shortName` adds a nullable image-informed `listing.shortName` to a single Product get, waiting
25
+ up to 20 seconds for generation and returning `null` if it is still running.
23
26
 
24
27
  See the [CLI reference](../../docs/reference/cli.md) for options and release workflow.
package/dist/CHANGELOG.md CHANGED
@@ -2,6 +2,61 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## v0.10.0 - 2026-10-20
6
+
7
+ ### Added
8
+
9
+ - Add optional `include` on `product.get` for `marketData`, `shortName`, and `cutoutThumbnail`.
10
+ The default remains `marketData`.
11
+ - Add image-informed design short names. A Product get that includes `shortName` waits up to 20
12
+ seconds. `rw product get <asin> --shortName` requests that include together with `marketData`.
13
+ The response carries `listing.shortName`, or `null` when no name is ready.
14
+ - Add on-demand transparent 128×128 cutout thumbnails through `cutoutThumbnail` on that same
15
+ `include` list. RankWrangler centers the subject and reuses the cutout until the listing image
16
+ changes.
17
+ - Advertise the website URL and a 128px icon in hosted MCP server info.
18
+ - Name the stale ingestion check on `GET /api/health` when the service is degraded, and include
19
+ the deployed commit as `revision` on both health responses.
20
+
21
+ ### Changed
22
+
23
+ - Breaking: replace `isUnavailable` with `amazonListingStatus` (`active` or `deleted`) on Product
24
+ listings, search results, and basic `getMany` results. A deleted listing keeps its last-known
25
+ title and thumbnail. `active` means the Amazon detail page exists. The dashboard marks deleted
26
+ listings.
27
+ - Return last-known `getMany` listings immediately and refresh stale listings in the background.
28
+ Short names and cutouts stay on single Product get.
29
+
30
+ ### Fixed
31
+
32
+ - Show the server error when the dashboard Products read fails, and reserve the empty catalog
33
+ state for a successful read with no rows.
34
+ - Load the API usage card across the UTC day boundary.
35
+ - Fail an Amazon Catalog read that does not start within 2 minutes with a retryable capacity
36
+ error.
37
+ - Require a second overdue Product before Keepa or SP-API freshness degrades `GET /api/health`,
38
+ and wait out a top search terms report that is still pending.
39
+
40
+ ## v0.9.0 - 2026-08-09
41
+
42
+ ### Added
43
+
44
+ - Add short-lived typed Provider-attempt telemetry for Keepa and SP-API operations, including
45
+ outcome, latency, and error context for operator diagnostics.
46
+
47
+ ### Changed
48
+
49
+ - Breaking: replace the `product.getMany` available/unavailable result union with one fixed shape
50
+ containing identity, nullable title, resolved thumbnail, and `isUnavailable`. Unavailable Amazon
51
+ listings retain their last-known title and thumbnail data.
52
+
53
+ ### Fixed
54
+
55
+ - Advertise Claude-compatible MCP Product and keyword schemas so fresh chats can discover and call
56
+ `getMany` directly, with clear unavailable-listing semantics in the Product tool description.
57
+ - Stop unavailable Products from triggering automatic Keepa synchronization when their dashboard
58
+ drawer opens.
59
+
5
60
  ## v0.8.0 - 2026-08-09
6
61
 
7
62
  ### Added
@@ -13,6 +13,7 @@ export interface CliOptionValues {
13
13
  bucket?: string;
14
14
  cursor?: string;
15
15
  refresh?: boolean;
16
+ shortName?: boolean;
16
17
  help?: boolean;
17
18
  version?: boolean;
18
19
  }
@@ -3,6 +3,9 @@ export const runProductCommand = async (command, client, config, options, fail)
3
3
  if (command.verb !== 'search' && options.refresh) {
4
4
  fail('INVALID_INPUT', '--refresh is only supported for product search');
5
5
  }
6
+ if (command.verb !== 'get' && options.shortName) {
7
+ fail('INVALID_INPUT', '--shortName is only supported for product get');
8
+ }
6
9
  if (command.verb === 'get') {
7
10
  return await runProductGet(command.args, client, config, options, fail);
8
11
  }
@@ -19,10 +22,14 @@ export const runProductCommand = async (command, client, config, options, fail)
19
22
  const runProductGet = async (args, client, config, options, fail) => {
20
23
  const marketplaceId = requireMarketplaceId(options, config);
21
24
  const asins = requireAsins(args, fail);
25
+ if (asins.length > 1 && options.shortName) {
26
+ fail('INVALID_INPUT', '--shortName requires exactly one ASIN');
27
+ }
22
28
  if (asins.length === 1) {
23
29
  return await client.product.get.mutate({
24
30
  marketplaceId,
25
31
  asin: asins[0],
32
+ ...(options.shortName ? { include: ['marketData', 'shortName'] } : {}),
26
33
  });
27
34
  }
28
35
  return await client.product.getMany.mutate({
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ const { positionals, values } = parseArgs({
42
42
  bucket: { type: 'string' },
43
43
  cursor: { type: 'string' },
44
44
  refresh: { type: 'boolean' },
45
+ shortName: { type: 'boolean' },
45
46
  stdin: { type: 'boolean' },
46
47
  },
47
48
  allowPositionals: true,
package/dist/usage.js CHANGED
@@ -39,6 +39,7 @@ export const printUsage = (paths) => {
39
39
  ' --baseUrl <origin> Override API origin',
40
40
  ` -m, --marketplace <id> Override marketplace (default: ${DEFAULT_MARKETPLACE_ID})`,
41
41
  ' --refresh Product search refresh (separate Search contract)',
42
+ ' --shortName Generate a design name for one Merch Product',
42
43
  ' --metrics <list> Product history metrics: salesRank,price (default: salesRank,price)',
43
44
  ' --bucket <unit> Product history buckets: auto,day,week,month (default: auto)',
44
45
  ' --days <N> Product history lookback (30-3650, default: 365)',
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@rankwrangler/cli",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Official RankWrangler command line interface",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/merchbaseco/rankwrangler.git",
8
+ "directory": "packages/cli"
9
+ },
5
10
  "type": "module",
6
11
  "bin": {
7
12
  "rw": "dist/index.js",
@@ -24,8 +29,8 @@
24
29
  "provenance": true
25
30
  },
26
31
  "dependencies": {
27
- "@merchbaseco/access": "0.3.0",
28
- "@rankwrangler/http-client": "^0.8.0",
32
+ "@merchbaseco/access": "0.4.0",
33
+ "@rankwrangler/http-client": "^0.10.0",
29
34
  "keytar": "7.9.0"
30
35
  },
31
36
  "devDependencies": {
@@ -1,41 +0,0 @@
1
- export declare const HISTORY_METRIC_ALIASES: readonly ["bsr", "price"];
2
- export type HistoryMetricAlias = (typeof HISTORY_METRIC_ALIASES)[number];
3
- type HistoryPointTuple = [string, number | null] | [string, null, 1];
4
- export type AgentHistorySeries = {
5
- bsr?: {
6
- unit: 'rank';
7
- category: {
8
- id: number;
9
- name: string | null;
10
- } | null;
11
- points: HistoryPointTuple[];
12
- };
13
- price?: {
14
- unit: 'minorCurrency';
15
- currencyCode: 'USD';
16
- valueScale: 100;
17
- points: HistoryPointTuple[];
18
- };
19
- };
20
- export type AgentHistoryResponse = {
21
- schemaVersion?: number;
22
- status?: string;
23
- syncTriggered: boolean;
24
- latestImportAt: string | null;
25
- series?: AgentHistorySeries;
26
- };
27
- export declare const buildCliHistoryResponse: ({ asin, marketplaceId, metrics, response, }: {
28
- asin: string;
29
- marketplaceId: string;
30
- metrics: HistoryMetricAlias[];
31
- response: AgentHistoryResponse;
32
- }) => {
33
- schemaVersion: number;
34
- asin: string;
35
- marketplaceId: string;
36
- status: string;
37
- latestImportAt: string | null;
38
- syncTriggered: boolean;
39
- series: AgentHistorySeries;
40
- };
41
- export {};
@@ -1,26 +0,0 @@
1
- export const HISTORY_METRIC_ALIASES = ['bsr', 'price'];
2
- export const buildCliHistoryResponse = ({ asin, marketplaceId, metrics, response, }) => {
3
- const series = {
4
- ...(metrics.includes('bsr') && response.series?.bsr ? { bsr: response.series.bsr } : {}),
5
- ...(metrics.includes('price') && response.series?.price
6
- ? { price: response.series.price }
7
- : {}),
8
- };
9
- const hasAnyPoints = Object.values(series).some(metricSeries => metricSeries.points.length > 0);
10
- const status = normalizeHistoryStatus(response.status);
11
- return {
12
- schemaVersion: response.schemaVersion ?? 1,
13
- asin,
14
- marketplaceId,
15
- status: status ?? (response.syncTriggered ? 'collecting' : hasAnyPoints ? 'ready' : 'empty'),
16
- latestImportAt: response.latestImportAt,
17
- syncTriggered: response.syncTriggered,
18
- series,
19
- };
20
- };
21
- const normalizeHistoryStatus = (status) => {
22
- if (status === 'ready' || status === 'collecting' || status === 'empty') {
23
- return status;
24
- }
25
- return null;
26
- };