@rankwrangler/cli 0.11.0 → 0.12.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 +1 -2
- package/dist/CHANGELOG.md +17 -0
- package/dist/cli-keyword-command.js +15 -28
- package/dist/index.js +0 -2
- package/dist/usage.js +1 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,10 +13,9 @@ rw keyword results "retro gardening shirt"
|
|
|
13
13
|
rw product history B0DV53VS61 --bucket week
|
|
14
14
|
rw keyword get "retro gardening shirt"
|
|
15
15
|
rw keyword search "retro gardening"
|
|
16
|
-
rw keyword history "retro gardening shirt" --rangeDays 90
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
The public command surface is Product `get/search/history`, keyword `get/search/
|
|
18
|
+
The public command surface is Product `get/search/history`, keyword `get/search/results`,
|
|
20
19
|
auth, config, version, and changelog. Product search reads the collected database immediately and
|
|
21
20
|
supports filters, sorting, and cursor pagination. Keyword results returns dated Amazon search
|
|
22
21
|
results with placement and accepts `--refresh` to replace the observed Search run.
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## v0.12.0 - 2026-10-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Collect keyword candidates once per Merch ASIN through Amazon Ads and once per tracked keyword
|
|
10
|
+
through autocomplete, sharing cached Jev decisions and popularity-based discovery scheduling.
|
|
11
|
+
- Add a persistent pause/resume control for the keyword pipeline, initialized paused on rollout.
|
|
12
|
+
- Show the live keyword directory with plain status badges, work-priority ordering, BSR popularity
|
|
13
|
+
and refresh cadence in a Products-style table. Record keyword lifecycle events in Logs.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Breaking: keyword get/search now read the stored keyword directory; keyword search uses an opaque
|
|
18
|
+
cursor object. Remove Brand Analytics keyword history and its CLI/MCP operation.
|
|
19
|
+
- Retire Search Terms, Brand Analytics report ingestion, metrics and health checks. Migration drops
|
|
20
|
+
obsolete report tables and demand fields while retaining canonical keywords and product evidence.
|
|
21
|
+
|
|
5
22
|
## v0.11.0 - 2026-10-23
|
|
6
23
|
|
|
7
24
|
### Changed
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { parseIntegerOption } from './cli-options.js';
|
|
2
|
-
const KEYWORD_MARKETPLACE_ID = 'ATVPDKIKX0DER';
|
|
3
2
|
export const runKeywordCommand = async (command, client, options, fail) => {
|
|
4
3
|
if (command.verb !== 'results' && options.refresh) {
|
|
5
4
|
fail('INVALID_INPUT', '--refresh is only supported for keyword results');
|
|
@@ -16,9 +15,6 @@ export const runKeywordCommand = async (command, client, options, fail) => {
|
|
|
16
15
|
if (command.verb === 'search') {
|
|
17
16
|
return await runKeywordSearch(command.args, client, options, fail);
|
|
18
17
|
}
|
|
19
|
-
if (command.verb === 'history') {
|
|
20
|
-
return await runKeywordHistory(command.args, client, options, fail);
|
|
21
|
-
}
|
|
22
18
|
fail('UNKNOWN_COMMAND', 'Unknown Keyword command', {
|
|
23
19
|
command: `keyword ${command.verb}`,
|
|
24
20
|
});
|
|
@@ -27,21 +23,13 @@ const runKeywordGet = async (args, client, fail) => {
|
|
|
27
23
|
const keyword = requireKeyword(args, fail, 'keyword get');
|
|
28
24
|
return await client.keyword.get.query({
|
|
29
25
|
keyword,
|
|
30
|
-
marketplaceId: KEYWORD_MARKETPLACE_ID,
|
|
31
26
|
});
|
|
32
27
|
};
|
|
33
28
|
const runKeywordSearch = async (args, client, options, fail) => {
|
|
34
29
|
const text = requireKeyword(args, fail, 'keyword search');
|
|
35
30
|
return await client.keyword.search.query({
|
|
36
31
|
text,
|
|
37
|
-
|
|
38
|
-
cursor: parseIntegerOption({
|
|
39
|
-
value: options.cursor,
|
|
40
|
-
optionName: 'cursor',
|
|
41
|
-
min: 0,
|
|
42
|
-
max: 1_000_000,
|
|
43
|
-
defaultValue: 0,
|
|
44
|
-
}, fail),
|
|
32
|
+
cursor: options.cursor ? parseKeywordCursor(options.cursor, fail) : undefined,
|
|
45
33
|
limit: parseIntegerOption({
|
|
46
34
|
value: options.limit,
|
|
47
35
|
optionName: 'limit',
|
|
@@ -49,21 +37,6 @@ const runKeywordSearch = async (args, client, options, fail) => {
|
|
|
49
37
|
max: 100,
|
|
50
38
|
defaultValue: 25,
|
|
51
39
|
}, fail),
|
|
52
|
-
merchOnly: true,
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
const runKeywordHistory = async (args, client, options, fail) => {
|
|
56
|
-
const keyword = requireKeyword(args, fail, 'keyword history');
|
|
57
|
-
return await client.keyword.history.query({
|
|
58
|
-
keyword,
|
|
59
|
-
marketplaceId: KEYWORD_MARKETPLACE_ID,
|
|
60
|
-
rangeDays: parseIntegerOption({
|
|
61
|
-
value: options.rangeDays ?? options.days,
|
|
62
|
-
optionName: 'rangeDays',
|
|
63
|
-
min: 7,
|
|
64
|
-
max: 365,
|
|
65
|
-
defaultValue: 90,
|
|
66
|
-
}, fail),
|
|
67
40
|
});
|
|
68
41
|
};
|
|
69
42
|
const requireKeyword = (args, fail, commandName) => {
|
|
@@ -73,3 +46,17 @@ const requireKeyword = (args, fail, commandName) => {
|
|
|
73
46
|
}
|
|
74
47
|
return keyword;
|
|
75
48
|
};
|
|
49
|
+
const parseKeywordCursor = (value, fail) => {
|
|
50
|
+
try {
|
|
51
|
+
const parsed = JSON.parse(value);
|
|
52
|
+
const key = parsed?.key;
|
|
53
|
+
if (!Array.isArray(key) || key.length !== 7 || !key.slice(0, 6).every(part => typeof part === 'number' && Number.isFinite(part))
|
|
54
|
+
|| typeof key[6] !== 'string' || typeof parsed.asOf !== 'string' || typeof parsed.trialTurn !== 'boolean'
|
|
55
|
+
|| (parsed.sort !== 'work' && parsed.sort !== 'newest'))
|
|
56
|
+
return fail('INVALID_INPUT', '--cursor must be the JSON nextCursor from keyword search');
|
|
57
|
+
return { key: [key[0], key[1], key[2], key[3], key[4], key[5], key[6]], asOf: parsed.asOf, trialTurn: parsed.trialTurn, sort: parsed.sort };
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return fail('INVALID_INPUT', '--cursor must be valid JSON');
|
|
61
|
+
}
|
|
62
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,6 @@ const SUPPORTED_COMMANDS = new Set([
|
|
|
16
16
|
'product:history',
|
|
17
17
|
'keyword:get',
|
|
18
18
|
'keyword:search',
|
|
19
|
-
'keyword:history',
|
|
20
19
|
'keyword:results',
|
|
21
20
|
'auth:status',
|
|
22
21
|
'auth:set',
|
|
@@ -38,7 +37,6 @@ const { positionals, values } = parseArgs({
|
|
|
38
37
|
startAt: { type: 'string' },
|
|
39
38
|
endAt: { type: 'string' },
|
|
40
39
|
days: { type: 'string' },
|
|
41
|
-
rangeDays: { type: 'string' },
|
|
42
40
|
limit: { type: 'string' },
|
|
43
41
|
bucket: { type: 'string' },
|
|
44
42
|
cursor: { type: 'string' },
|
package/dist/usage.js
CHANGED
|
@@ -20,7 +20,6 @@ export const printUsage = (paths) => {
|
|
|
20
20
|
' product history <ASIN>',
|
|
21
21
|
' keyword get <keyword>',
|
|
22
22
|
' keyword search <text>',
|
|
23
|
-
' keyword history <keyword>',
|
|
24
23
|
' keyword results <keyword>',
|
|
25
24
|
' auth status',
|
|
26
25
|
' auth set [apiKey]',
|
|
@@ -44,11 +43,10 @@ export const printUsage = (paths) => {
|
|
|
44
43
|
' --metrics <list> Product history metrics: salesRank,price (default: salesRank,price)',
|
|
45
44
|
' --bucket <unit> Product history buckets: auto,day,week,month (default: auto)',
|
|
46
45
|
' --days <N> Product history lookback (30-3650, default: 365)',
|
|
47
|
-
' --rangeDays <N> Keyword history lookback (7-365, default: 90)',
|
|
48
46
|
' --startAt <ISO> Product history range start (ISO date/time)',
|
|
49
47
|
' --endAt <ISO> Product history range end (ISO date/time)',
|
|
50
48
|
' --limit <N> Result limit',
|
|
51
|
-
' --cursor <value> Product search cursor or keyword
|
|
49
|
+
' --cursor <value> Product search cursor or keyword nextCursor JSON',
|
|
52
50
|
' --sort <order> Product search order (default: relevance)',
|
|
53
51
|
' --textFields <scope> Product search text: all,title (default: all)',
|
|
54
52
|
' --minBsr/--maxBsr <N> Product sales-rank bounds',
|
|
@@ -87,7 +85,6 @@ export const printUsage = (paths) => {
|
|
|
87
85
|
' rw product history B0DV53VS61 --bucket week',
|
|
88
86
|
' rw keyword get "retro gardening shirt"',
|
|
89
87
|
' rw keyword search "retro gardening" --limit 10',
|
|
90
|
-
' rw keyword history "retro gardening shirt" --rangeDays 90',
|
|
91
88
|
' RR_STORAGE_DIR=~/.config/rankwrangler rw config show',
|
|
92
89
|
' rw --version',
|
|
93
90
|
' rw changelog',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rankwrangler/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Official RankWrangler command line interface",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@merchbaseco/access": "0.4.0",
|
|
33
|
-
"@rankwrangler/http-client": "^0.
|
|
33
|
+
"@rankwrangler/http-client": "^0.12.0",
|
|
34
34
|
"keytar": "7.9.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|