@round2ai/r2-cli 1.0.16 → 1.0.17

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,111 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * R2-CLI 安装脚本
5
+ *
6
+ * 三种调用场景(通过 npm_lifecycle_event + npm_command 环境变量区分):
7
+ * 1. npx @round2ai/r2-cli@latest install — 全局安装 CLI(postinstall 自动装 Skills)
8
+ * 2. npm install -g 触发 postinstall — 安装 Skills
9
+ * 3. npx 下载时触发的 postinstall — 跳过(避免重复安装)
10
+ */
11
+
12
+ import { execSync } from "node:child_process";
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
+ const PKG = "@round2ai/r2-cli@latest";
19
+ const argv = process.argv.slice(2);
20
+ const isJson = argv.includes("--json");
21
+
22
+ /** 根据环境变量判断安装路由(纯函数,供测试使用) */
23
+ export function getInstallRoute(env = process.env) {
24
+ const isPostinstall = env.npm_lifecycle_event === "postinstall";
25
+ const isNpx = env.npm_command === "exec";
26
+
27
+ if (isPostinstall && isNpx) return "skip";
28
+ if (isPostinstall) return "skills-only";
29
+ return "full-install";
30
+ }
31
+
32
+ // ——— Skills 安装 ———
33
+
34
+ function installSkills() {
35
+ const skillsDir = path.join(__dirname, "..", "skills");
36
+ if (!fs.existsSync(skillsDir)) return;
37
+ try {
38
+ execSync(`npx skills add "${skillsDir}" --all -g`, {
39
+ stdio: "inherit",
40
+ timeout: 60_000,
41
+ });
42
+ } catch {
43
+ // 网络不可用或 skills CLI 失败时静默跳过
44
+ }
45
+ }
46
+
47
+ // ——— 主入口(仅直接执行时运行,import 时不触发) ———
48
+
49
+ const scriptPath = path.resolve(process.argv[1] ?? "");
50
+ if (scriptPath.includes(path.basename(fileURLToPath(import.meta.url)))) {
51
+ const route = getInstallRoute();
52
+
53
+ if (route === "skip") {
54
+ process.exit(0);
55
+ }
56
+
57
+ if (route === "skills-only") {
58
+ installSkills();
59
+ process.exit(0);
60
+ }
61
+
62
+ // 完整安装:全局 npm install
63
+ // npm install -g 会触发 postinstall → installSkills()
64
+ function log(msg) {
65
+ if (!isJson) console.log(msg);
66
+ }
67
+
68
+ try {
69
+ log("\x1b[36m正在安装 R2-CLI...\x1b[0m");
70
+ execSync(`npm install -g ${PKG}`, { stdio: "inherit" });
71
+
72
+ let version = "unknown";
73
+ try {
74
+ version = execSync("r2-cli --version", { encoding: "utf-8" }).trim();
75
+ } catch {}
76
+
77
+ if (isJson) {
78
+ console.log(JSON.stringify({
79
+ success: true,
80
+ data: { version, npmInstalled: true, skillsInstalled: true },
81
+ }, null, 2));
82
+ } else {
83
+ console.log(`\n\x1b[32m✓ R2-CLI ${version} 安装完成\x1b[0m`);
84
+ console.log("\x1b[32m✓ Skills 已配置\x1b[0m");
85
+ console.log("\n\x1b[36m快速开始:\x1b[0m");
86
+ console.log(" r2-cli auth login # 扫码登录");
87
+ console.log(" r2-cli goods shops # 查看店铺");
88
+ console.log(" r2-cli goods xianyu up # 开始上架\n");
89
+ }
90
+ } catch {
91
+ if (isJson) {
92
+ console.log(JSON.stringify({
93
+ success: false,
94
+ error: `安装失败`,
95
+ errorType: "unknown",
96
+ suggestion: `手动安装:npm install -g ${PKG}`,
97
+ }));
98
+ } else {
99
+ console.error(`\n\x1b[31m✗ 安装失败\x1b[0m\n`);
100
+ console.error("请尝试以下方案:");
101
+ console.error(" 1. 手动安装:");
102
+ console.error(` npm install -g ${PKG}`);
103
+ console.error(" 2. 使用镜像:");
104
+ console.error(` npm install -g ${PKG} --registry=https://registry.npmmirror.com`);
105
+ console.error(" 3. 检查网络或代理:");
106
+ console.error(" export https_proxy=http://your-proxy:port");
107
+ console.error(` npm install -g ${PKG}\n`);
108
+ }
109
+ process.exit(1);
110
+ }
111
+ }
@@ -17,6 +17,7 @@ metadata:
17
17
  > **Tip**: Agent 获取数据后展示给用户选择,不要让用户自己提供 ID。遵守「友好输出原则」:提取关键字段展示,不丢原始 JSON。
18
18
  > **Tip**: 所有 `--json` 命令统一错误格式 `{ success: false, error: "..." }`,检查 `success` 判断成败。
19
19
  > **Tip**: 查询分页建议使用 `--page 1 --size 50`。若响应含分页信息则继续翻页取完。在查询前提醒用户通过 `--status` 或 `--stock-id` 缩小范围提高效率。
20
+ > **Tip**: **上架、改价、编辑提交前,必须提醒用户可选 `--transport-fee`(运费,默认 0 包邮)和 `--yhb`(验货宝)。不要静默使用默认值。**
20
21
 
21
22
  商品管理专家,指导 AI Agent 完成商品上架、下架、改价、挂售全流程。
22
23
 
@@ -26,19 +27,55 @@ metadata:
26
27
 
27
28
  命令执行规则见 **r2-shared** skill 的「执行规则」。安装、统一错误格式见 **r2-shared** skill。认证登录见 **r2-auth** skill。
28
29
 
29
- ## 上架路由决策
30
+ **Agent 必须使用带平台前缀的新路径**(`goods xianyu up` / `goods taobao up`),不要使用旧路径(`goods up`)。详见 r2-shared「命令路径」。
30
31
 
31
- 用户说"上架"时,按以下规则选择上架方式:
32
+ ## 平台路由决策
33
+
34
+ 闲鱼和淘宝是两套独立体系,ID 互不通用。所有涉及商品操作的命令都需要先确定平台。
35
+
36
+ ### 通用平台判断规则
37
+
38
+ | 条件 | 判断结果 |
39
+ |------|----------|
40
+ | 用户明确说了平台("闲鱼下架"、"淘宝改价") | 用对应平台的命令 |
41
+ | 用户从之前的列表中选了商品 | 从数据推断:有 `jbpSpuId` → 淘宝,有 `stockGoodsId` + `status` → 闲鱼 |
42
+ | 用户未指定且无上下文 | **先查所有平台列表**,让用户选商品,再根据商品所属平台执行 |
43
+
44
+ > **禁止**:凭上下文猜测平台。刚操作过淘宝不意味着"下架"就一定是淘宝。
45
+
46
+ ### 上架路由
32
47
 
33
48
  | 条件 | 上架方式 | 流程 |
34
49
  |------|----------|------|
35
- | 用户明确说"选品上架",或商品**在选品库**中 | `goods up`(普通上架) | 店铺 → 仓库 → 选品商品 → 输入价格 → 提交 |
36
- | 用户明确说"挂售",或用户**提供了图片** | `goods hang-up`(挂售上架) | 上传图片 → AI 读图识别 → 类目/属性 → 提交 |
50
+ | 用户明确说"选品上架",或商品**在选品库**中 | `goods xianyu up`(闲鱼普通上架) | 店铺 → 仓库 → 选品商品 → 输入价格 → 提交 |
51
+ | 用户明确说"挂售",或用户**提供了图片** | `goods xianyu hang-up`(闲鱼挂售上架) | 上传图片 → AI 读图识别 → 类目/属性 → 提交 |
52
+ | 用户明确说"阿里资产"或"alzc" | `goods taobao alzc`(淘宝阿里资产上架) | SPU 查询 → SKU 详情 → 选择 SKU + 价格 → 申请上架 |
53
+
54
+ 用户只说"上架"未指定方式 → **必须询问**:"选品上架、挂售上架还是阿里资产上架?"
55
+
56
+ ### 查询路由
57
+
58
+ 用户说"查上架列表"/"查询上架情况"且未指定平台时:
59
+
60
+ 1. `r2-cli goods shops --json` → 获取所有店铺,按 `platform` 分组
61
+ 2. 有 `xianyu` 店铺 → `r2-cli goods xianyu listing --json`(查闲鱼上架列表)
62
+ 3. 有 `taobao` 店铺 → `r2-cli goods taobao listing --shop-id <id> --json`(每个淘宝店铺都要查)
63
+ 4. 分区块展示:先展示「闲鱼上架列表」,再展示「淘宝上架列表」
37
64
 
38
- **判断方法**:
39
- 1. 用户**明确指定**了上架方式 → 直接走对应流程
40
- 2. 用户提供了图片文件 → 直接走 `goods hang-up`,Agent 用 Read 工具查看图片自动识别商品信息(如果 Read 工具返回 `[Unsupported Image]`,视为不能识别,走询问路径)
41
- 3. 用户只说"上架"未指定方式 → **必须询问用户**:"选品上架还是挂售上架?"
65
+ ### 下架/改价路由
66
+
67
+ 用户说"下架"或"改价"且未指定平台时:
68
+
69
+ 1. **有上下文商品**(用户从之前的列表中选了商品)→ 直接根据商品所属平台执行
70
+ 2. **无上下文** → 先按「查询路由」查所有平台列表 → 用户选择商品 → 根据平台执行对应命令
71
+
72
+ | 操作 | 闲鱼命令 | 淘宝命令 |
73
+ |------|----------|----------|
74
+ | 下架 | `goods xianyu down --id <id>` | `goods taobao down --jbp-spu-id <> --shop-id <>` |
75
+ | 改价 | `goods xianyu price --id <id> --price <>` | `goods taobao price --jbp-spu-id <> --jbp-sku-id <> --shop-id <> --sub-item-id <> --price <>` |
76
+ | 修改信息 | `goods xianyu edit --id <id> ...` | 淘宝不支持独立编辑,需通过 SPU 重新申请 |
77
+
78
+ > **禁止**:凭上下文猜测平台。刚操作过淘宝不意味着"下架"就一定是淘宝。
42
79
 
43
80
  ## 命令概览
44
81
 
@@ -49,31 +86,46 @@ metadata:
49
86
  | `r2-cli goods shops [--json]` | 查看已授权店铺 | [r2-goods-query](references/r2-goods-query.md) |
50
87
  | `r2-cli goods stocks [--json]` | 查看仓库 | [r2-goods-query](references/r2-goods-query.md) |
51
88
  | `r2-cli goods list [--stock-id <id>] [--json]` | 查看选品商品 | [r2-goods-query](references/r2-goods-query.md) |
52
- | `r2-cli goods listing [--status <up/down/sold>] [--json]` | 查询上架列表 | [r2-goods-query](references/r2-goods-query.md) |
89
+ | `r2-cli goods xianyu listing [--status <up/down/sold>] [--json]` | 查询闲鱼上架列表 | [r2-goods-query](references/r2-goods-query.md) |
90
+ | `r2-cli goods taobao listing --shop-id <id> [--json]` | 查询淘宝上架列表 | [r2-goods-alzc](references/r2-goods-alzc.md) |
53
91
 
54
92
  ### 上架/下架/改价/修改
55
93
 
56
94
  | 命令 | 说明 | 详细文档 |
57
95
  |------|------|----------|
58
- | `r2-cli goods up --stock-goods-id <> --shop-id <> --price <> --json` | 普通上架(选品商品) | [r2-goods-listing](references/r2-goods-listing.md) |
59
- | `r2-cli goods down --id <id> [--json]` | 下架商品 | [r2-goods-listing](references/r2-goods-listing.md) |
60
- | `r2-cli goods price --id <id> --price <amount> [--json]` | 修改价格 | [r2-goods-listing](references/r2-goods-listing.md) |
61
- | `r2-cli goods edit --id <id> [--title ...] --json` | 修改商品信息 | [r2-goods-listing](references/r2-goods-listing.md) |
96
+ | `r2-cli goods xianyu up --stock-goods-id <> --shop-id <> --price <> --json` | 普通上架(选品商品) | [r2-goods-listing](references/r2-goods-listing.md) |
97
+ | `r2-cli goods xianyu down --id <id> [--json]` | 下架商品 | [r2-goods-listing](references/r2-goods-listing.md) |
98
+ | `r2-cli goods xianyu price --id <id> --price <amount> [--json]` | 修改价格 | [r2-goods-listing](references/r2-goods-listing.md) |
99
+ | `r2-cli goods xianyu edit --id <id> [--title ...] --json` | 修改商品信息 | [r2-goods-listing](references/r2-goods-listing.md) |
100
+
101
+ ### 淘宝阿里资产管理
102
+
103
+ | 命令 | 说明 | 详细文档 |
104
+ |------|------|----------|
105
+ | `r2-cli goods taobao listing --shop-id <id> [--goods-no <no>] [--json]` | 查询已报名商品 | [r2-goods-alzc](references/r2-goods-alzc.md) |
106
+ | `r2-cli goods taobao alzc spu-query --shop-id <id> --goods-no <no> [--json]` | 查询可申请 SPU | [r2-goods-alzc](references/r2-goods-alzc.md) |
107
+ | `r2-cli goods taobao alzc spu-detail --shop-id <id> --jbp-spu-id <id> [--json]` | 查询 SPU 详情(含 SKU) | [r2-goods-alzc](references/r2-goods-alzc.md) |
108
+ | `r2-cli goods taobao alzc apply --shop-id <id> --jbp-spu-id <id> --apply-skus '<json>' [--json]` | 申请上架 SKU | [r2-goods-alzc](references/r2-goods-alzc.md) |
109
+ | `r2-cli goods taobao price --jbp-spu-id <> --jbp-sku-id <> --shop-id <> --sub-item-id <> --price <> --json` | 修改 SKU 价格 | [r2-goods-alzc](references/r2-goods-alzc.md) |
110
+ | `r2-cli goods taobao stock --jbp-spu-id <> --jbp-sku-id <> --shop-id <> --quantity <> [--json]` | 修改 SKU 库存 | [r2-goods-alzc](references/r2-goods-alzc.md) |
111
+ | `r2-cli goods taobao down --jbp-spu-id <> --shop-id <> [--jbp-sku-id <>] [--sub-item-id <>] [--json]` | 下架商品 | [r2-goods-alzc](references/r2-goods-alzc.md) |
62
112
 
63
113
  ### 选品上架 4 步流程
64
114
 
65
115
  1. `r2-cli goods shops --json` → 展示店铺 → 用户选择 `shopId`
66
116
  2. `r2-cli goods stocks --json` → 展示仓库 → 用户选择 `stockId`
67
117
  3. `r2-cli goods list --stock-id <id> --json` → 展示商品 → 用户选择 `stockGoodsId`
68
- 4. `r2-cli goods up --stock-goods-id <id> --shop-id <id> --price <amount> --json` → 提交
118
+ 4. `r2-cli goods xianyu up --stock-goods-id <id> --shop-id <id> --price <amount> --json` → 提交
69
119
 
70
120
  必填参数:`--stock-goods-id`、`--shop-id`(取 `shopId` 不是 `id`)、`--price`
71
121
 
122
+ > **提交前提醒用户**:运费默认包邮(`--transport-fee 0`),如需收运费请提供金额。可选开启验货宝(`--yhb`),但价格须在品类验货宝价格区间内。
123
+
72
124
  ### 修改商品信息(edit)
73
125
 
74
126
  修改已上架商品的标题、描述、品牌、类目、图片、属性等。
75
127
 
76
- > **注意**:`goods edit` 不支持修改价格。改价需单独使用 `r2-cli goods price --id <id> --price <amount>`。
128
+ > **注意**:`goods xianyu edit` 不支持修改价格。改价需单独使用 `r2-cli goods xianyu price --id <id> --price <amount>`。
77
129
 
78
130
  **路由决策**:
79
131
 
@@ -86,22 +138,23 @@ metadata:
86
138
  **定位商品**:优先使用 `--id <goodsListingId>`(从上架列表获取 `id` 字段),也可用 `--stock-goods-id <id> --account <shopId>`。
87
139
 
88
140
  **关键约束**:
141
+ - **提交前提醒用户**:可同时修改运费(`--transport-fee`,默认 0 包邮)和验货宝(`--yhb`)
89
142
  - `--category-id` 和 `--channel-cat-id` 是**必填的**(后端复用挂售 DTO),即使不改类目也要传当前类目
90
- - **`--item-attrs` 必须包含 props 中所有属性,不只是修改的那一个**:后端替换整个属性列表,漏传的属性会被清除。调 `goods hang-up props --channel-cat-id <id> --json` 获取全部属性后,改目标值,其他保持原样一并传入
143
+ - **`--item-attrs` 必须包含 props 中所有属性,不只是修改的那一个**:后端替换整个属性列表,漏传的属性会被清除。调 `goods xianyu hang-up props --channel-cat-id <id> --json` 获取全部属性后,改目标值,其他保持原样一并传入
91
144
  - Agent 应自动查询类目并匹配,不需要用户手动提供
92
145
  - AI 读图识别后填充的字段需展示给用户确认,不能静默覆盖已有信息
93
146
  - `--image-ids` 接受已上传的图片 ID,用户给图片文件时需先调 `hang-up upload-images` 上传
94
147
 
95
148
  **带图片的全自动流程**(Agent 自动完成,用户只需提供图片并确认):
96
149
 
97
- 1. **展示列表**:`goods listing --json` → 用户选择要修改的商品
150
+ 1. **展示列表**:`goods xianyu listing --json` → 用户选择要修改的商品
98
151
  2. **上传图片**:`hang-up upload-images --shop-id <shopId> --files <paths> --json`
99
152
  3. **AI 读图识别**:Agent 用 Read 工具查看图片,识别品牌/类目/成色/描述等
100
153
  4. **自动匹配类目**:`hang-up categories --json` → 根据识别结果匹配 catId + channelCatId
101
154
  5. **自动查询属性**:`hang-up props --channel-cat-id <id> --json` → 根据识别结果匹配成色/尺码/季节等
102
155
  6. **自动搜索品牌**:`hang-up brands --channel-cat-id <> --prop-id <> --key <品牌名> --json` → 获取品牌 valueId
103
156
  7. **汇总展示**:当前值 vs 变更值,让用户确认
104
- 8. **提交**:`goods edit --id <goodsListingId> --category-id <> --channel-cat-id <> --image-ids <> --item-attrs <> --brand-name <> --json`
157
+ 8. **提交**:`goods xianyu edit --id <goodsListingId> --category-id <> --channel-cat-id <> --image-ids <> --item-attrs <> --brand-name <> --json`
105
158
 
106
159
  **核心原则**:用户只需提供图片 + 确认。类目匹配、属性填充、品牌搜索全部由 Agent 自动完成。
107
160
 
@@ -109,11 +162,11 @@ metadata:
109
162
 
110
163
  | 命令 | 说明 | 详细文档 |
111
164
  |------|------|----------|
112
- | `r2-cli goods hang-up categories [--json]` | 获取闲鱼类目 | [r2-goods-hangup](references/r2-goods-hangup.md) |
113
- | `r2-cli goods hang-up props --channel-cat-id <id> [--json]` | 获取属性列表 | [r2-goods-hangup](references/r2-goods-hangup.md) |
114
- | `r2-cli goods hang-up brands --channel-cat-id <> --prop-id <> --key <> [--json]` | 品牌搜索 | [r2-goods-hangup](references/r2-goods-hangup.md) |
115
- | `r2-cli goods hang-up upload-images --shop-id <> --files <> --json` | 上传图片 | [r2-goods-hangup](references/r2-goods-hangup.md) |
116
- | `r2-cli goods hang-up submit --shop-id <> --title <> ... --json` | 提交挂售上架 | [r2-goods-hangup](references/r2-goods-hangup.md) |
165
+ | `r2-cli goods xianyu hang-up categories [--json]` | 获取闲鱼类目 | [r2-goods-hangup](references/r2-goods-hangup.md) |
166
+ | `r2-cli goods xianyu hang-up props --channel-cat-id <id> [--json]` | 获取属性列表 | [r2-goods-hangup](references/r2-goods-hangup.md) |
167
+ | `r2-cli goods xianyu hang-up brands --channel-cat-id <> --prop-id <> --key <> [--json]` | 品牌搜索 | [r2-goods-hangup](references/r2-goods-hangup.md) |
168
+ | `r2-cli goods xianyu hang-up upload-images --shop-id <> --files <> --json` | 上传图片 | [r2-goods-hangup](references/r2-goods-hangup.md) |
169
+ | `r2-cli goods xianyu hang-up submit --shop-id <> --title <> ... --json` | 提交挂售上架 | [r2-goods-hangup](references/r2-goods-hangup.md) |
117
170
 
118
171
  ### 挂售上架流程
119
172
 
@@ -121,7 +174,7 @@ metadata:
121
174
  2. **识别商品**:Agent 用 Read 工具查看图片,自动识别品牌/成色/类目/描述。不支持读图的 Agent 走询问路径
122
175
  3. **匹配类目**:`hang-up categories --json` → 自动匹配
123
176
  4. **匹配属性**:`hang-up props --channel-cat-id <id> --json` → 自动填充。品牌需调 `hang-up brands` 搜索
124
- 5. **汇总展示**:自动填充的字段标 ✅,缺失字段标 ❓ 让用户补充。**运费默认包邮(`--transport-fee` 默认 0),需告知用户可修改**
177
+ 5. **汇总展示**:自动填充的字段标 ✅,缺失字段标 ❓ 让用户补充。**运费默认包邮(`--transport-fee` 默认 0),可选开启验货宝(`--yhb`),需告知用户可修改**
125
178
  6. **提交**:`hang-up submit` — 必填:`shop-id`、`title`、`price`、`category-id`、`channel-cat-id`、`image-ids`、`stuff-status`、`desc`、`out-item-no`
126
179
 
127
180
  **核心原则**:**图片里能看到的,就别问用户**。只问价格和商家编码(优先用户自定义,不填则推荐自动生成),其他全部从图片自动提取。
@@ -161,7 +214,7 @@ metadata:
161
214
  | 错误信息 | 原因 | 解决方法 |
162
215
  |----------|------|----------|
163
216
  | `请先运行 r2-cli auth login 登录` | 未登录或 Token 过期 | 执行 `r2-cli auth login --json` |
164
- | `Agent 模式需要 --stock-goods-id, --shop-id, --price` | `goods up --json` 缺少必填参数 | 补齐三个参数 |
217
+ | `Agent 模式需要 --stock-goods-id, --shop-id, --price` | `goods xianyu up --json` 缺少必填参数 | 补齐三个参数 |
165
218
  | `请指定下架条件:--id 或 --stock-goods-id + --shop-id` | 下架缺少定位参数 | 补充参数 |
166
219
  | `--price <amount> 为必填参数` | 改价未提供价格 | 询问用户新价格 |
167
220
  | `请提供至少一张图片` | 挂售缺少图片 | 提供本地图片路径 |
@@ -171,4 +224,5 @@ metadata:
171
224
  | `该商品已上架` | 挂售已下架商品重新提交时 out-item-no 被占用 | 更换新的 out-item-no |
172
225
  | `标题过长` | 标题超过 30 单位限制(半角 0.5/全角 1) | 缩短标题,保留品牌和核心款式 |
173
226
  | `ITEM_CONDITION_NOT_SUPPORT_SIGN` | 售后服务未开通或品类不支持 | 默认关闭售后 |
174
- | `轮询超时` | 上架结果查询超时 | 稍后用 `goods listing` 查看 |
227
+ | `YHB_PRICE_NOT_SUPPORT` | 验货宝价格不在该品类允许范围内(区间因品类而异) | 根据错误信息调整价格,或关闭验货宝 |
228
+ | `轮询超时` | 上架结果查询超时 | 稍后用 `goods xianyu listing` 查看 |
@@ -0,0 +1,285 @@
1
+ # R2-Goods 阿里资产(alzc)
2
+
3
+ > **Prerequisite:** 读取 [`../SKILL.md`](../SKILL.md) 了解路由决策和命令概览。
4
+
5
+ 阿里资产是淘宝平台的 SPU/SKU 目录上架模式。商品来自平台目录,不需要上传图片或填写类目属性。
6
+
7
+ ## 业务流程
8
+
9
+ ```
10
+ 1. SPU 查询(szc spu-query) → 选择 SPU,获取 jbpSpuId
11
+ 2. SPU 详情(alzc spu-detail) → 获取可申请 SKU 列表(canApplySkuList)
12
+ 3. 申请上架(alzc apply) → 选择 SKU + 价格 + 库存 → 提交
13
+ 4. 管理已上架商品(改库存 / 改价格 / 下架)
14
+ ```
15
+
16
+ ---
17
+
18
+ ## 第 1 步:查询 SPU 列表
19
+
20
+ ```bash
21
+ r2-cli goods taobao alzc spu-query --shop-id <shopId> --goods-no <no> [--json]
22
+ ```
23
+
24
+ **参数**:
25
+
26
+ | 参数 | 必填 | 说明 |
27
+ |------|------|------|
28
+ | `--shop-id <id>` | 是 | 淘宝店铺 ID |
29
+ | `--goods-no <no>` | **是** | 商品编码(**必填,不传无法查询到商品**) |
30
+ | `--spu-id <id>` | 否 | 精确查询指定 SPU(用户通常不知道,选填) |
31
+ | `--page <n>` | 否 | 页码(从 1 开始,默认 1) |
32
+ | `--size <n>` | 否 | 每页条数(默认 20) |
33
+
34
+ > **重要**:`--goods-no` 实际为必填参数。Agent 在调 SPU 查询前**必须先向用户询问商品编码**。如果用户不知道商品编码,提示用户提供。
35
+
36
+ **响应示例**:
37
+
38
+ ```json
39
+ {
40
+ "items": [{
41
+ "jbpSpuId": 12345,
42
+ "spuTitle": "Nike Air Jordan 1",
43
+ "spuImage": "https://...",
44
+ "itemId": 67890,
45
+ "itemNumber": "SP001",
46
+ "brandName": "Nike",
47
+ "categoryName": "运动鞋",
48
+ "categoryId": 50025445,
49
+ "minPrice": 29900,
50
+ "applyStatus": 1,
51
+ "spuStatus": 1
52
+ }],
53
+ "total": "100",
54
+ "page": 1,
55
+ "perPage": 20
56
+ }
57
+ ```
58
+
59
+ > Agent 展示列表时提取关键字段:`spuTitle`、`brandName`、`categoryName`、`minPrice`(分→元)。让用户选择 `jbpSpuId`。
60
+
61
+ ---
62
+
63
+ ## 第 2 步:查询 SPU 详情(获取可申请 SKU)
64
+
65
+ ```bash
66
+ r2-cli goods taobao alzc spu-detail --shop-id <shopId> --jbp-spu-id <jbpSpuId> --json
67
+ ```
68
+
69
+ **参数**:
70
+
71
+ | 参数 | 必填 | 说明 |
72
+ |------|------|------|
73
+ | `--shop-id <id>` | 是 | 淘宝店铺 ID |
74
+ | `--jbp-spu-id <id>` | 是 | 聚宝盆 SPU ID(从第 1 步获取) |
75
+
76
+ **响应关键字段**:
77
+
78
+ ```json
79
+ {
80
+ "jbpSpuId": 12345,
81
+ "needIdentify": true,
82
+ "identifyOrgId": "100",
83
+ "canApplySkuList": [{
84
+ "jbpSkuId": 1001,
85
+ "skuVersion": 1,
86
+ "minPrice": 29900,
87
+ "maxPrice": 59900,
88
+ "canApply": true,
89
+ "pvs": [{"name": "尺码", "value": "42"}]
90
+ }],
91
+ "haveApplySkuList": [{
92
+ "jbpSkuId": 1001,
93
+ "price": 29900,
94
+ "quantity": 10,
95
+ "sales": 5,
96
+ "auditStatus": 1
97
+ }]
98
+ }
99
+ ```
100
+
101
+ > **关键字段**:
102
+ > - `canApplySkuList` 中 `canApply=true` 的 SKU 才可以申请上架
103
+ > - `needIdentify=true` 时提交申请需传 `--identify-org-id`
104
+ > - 记下 `jbpSkuId` 和 `skuVersion` 传给第 3 步
105
+
106
+ **Agent 展示 SKU 列表**:
107
+
108
+ ```
109
+ 可申请 SKU:
110
+ 1. SKU 1001 | 尺码: 42 | 价格范围: ¥299.00 ~ ¥599.00
111
+ 2. SKU 1002 | 尺码: 43 | 价格范围: ¥299.00 ~ ¥599.00
112
+ ```
113
+
114
+ ---
115
+
116
+ ## 第 3 步:申请上架 SKU
117
+
118
+ ```bash
119
+ r2-cli goods taobao alzc apply \
120
+ --shop-id <shopId> \
121
+ --jbp-spu-id <jbpSpuId> \
122
+ --apply-skus '[{"jbpSkuId":1001,"price":299,"quantity":10,"skuVersion":1}]' \
123
+ --spu-version <n> \
124
+ --delivery-id <id> \
125
+ --city-code <code> \
126
+ --city-name <name> \
127
+ --pro-code <code> \
128
+ --pro-name <name> \
129
+ --json
130
+ ```
131
+
132
+ **参数**:
133
+
134
+ | 参数 | 必填 | 说明 |
135
+ |------|------|------|
136
+ | `--shop-id <id>` | 是 | 淘宝店铺 ID |
137
+ | `--jbp-spu-id <id>` | 是 | 聚宝盆 SPU ID |
138
+ | `--apply-skus <json>` | 是 | SKU 列表 JSON(见下方格式) |
139
+ | `--spu-version <n>` | 否 | SPU 版本号(从 spu-detail 获取,建议传入) |
140
+ | `--delivery-id <id>` | 是 | 发货方式 ID(从 spu-detail.delivery.deliveryId 获取) |
141
+ | `--city-code <code>` | 是 | 城市编码(默认 330100 杭州市) |
142
+ | `--city-name <name>` | 是 | 城市名称(默认"杭州市") |
143
+ | `--pro-code <code>` | 是 | 省份编码(默认 330000 浙江省) |
144
+ | `--pro-name <name>` | 是 | 省份名称(默认"浙江省") |
145
+ | `--sub-item-id <id>` | 否 | 子商品 ID |
146
+ | `--identify-org-id <id>` | **禁止传** | 见下方说明 |
147
+
148
+ > **关于 `--identify-org-id`**:虽然 spu-detail 返回 `needIdentify=true` 和 `identifyOrgList`,但**不要传此参数**。传了会导致"鉴定机构id填写有误"。淘宝内部会自动处理鉴定流程。
149
+
150
+ > **关于城市/省份参数**:虽然 API 文档标注为"否",但淘宝实际要求必填。不传会报 `Missing required arguments:cityCode`。如果用户未指定发货地,默认用杭州。
151
+
152
+ **`--apply-skus` 格式**:
153
+
154
+ ```json
155
+ [
156
+ {"jbpSkuId": 1001, "price": 299, "quantity": 10, "skuVersion": 1},
157
+ {"jbpSkuId": 1002, "price": 399, "quantity": 5, "skuVersion": 1}
158
+ ]
159
+ ```
160
+
161
+ > **价格单位**:CLI 接受**元**(如 `299` = 299 元),内部自动转为分(29900)调 API。`commodityCode` 为商家自定义编码,可选。**`skuVersion` 建议始终传入**,从 canApplySkuList 中获取。
162
+
163
+ **成功返回**:`{ "success": true, "data": "成功" }`
164
+
165
+ **Agent 友好输出**:
166
+
167
+ ```
168
+ 申请上架成功!
169
+ - SPU: [spuTitle] (jbpSpuId: 12345)
170
+ - SKU: 1001 | 极地白/S | ¥299 x 10
171
+ - 店铺: [shopName]
172
+ - 发货: [delivery.name]
173
+ ```
174
+
175
+ > **追加 SKU 限制**:已申请过 SKU 的 SPU,追加新 SKU 可能失败(淘宝返回 `Remote service error`)。如果追加失败,建议一次性选择所有要上架的 SKU。
176
+
177
+ ---
178
+
179
+ ## 已上架商品管理
180
+
181
+ ### 查询已上架列表
182
+
183
+ ```bash
184
+ r2-cli goods taobao listing --shop-id <shopId> [--goods-no <no>] [--page <n>] [--size <n>] [--json]
185
+ ```
186
+
187
+ | 参数 | 必填 | 说明 |
188
+ |------|------|------|
189
+ | `--shop-id <id>` | 是 | 淘宝店铺 ID |
190
+ | `--goods-no <no>` | 否 | 按商品编码过滤 |
191
+ | `--item-id <id>` | 否 | 按淘宝商品 ID 过滤 |
192
+ | `--goods-name <name>` | 否 | 按商品名称过滤 |
193
+ | `--status <n>` | 否 | 按商品状态过滤 |
194
+ | `--code <code>` | 否 | 按商家编码过滤 |
195
+ | `--page <n>` | 否 | 页码(从 1 开始) |
196
+ | `--size <n>` | 否 | 每页条数 |
197
+
198
+ > listing 只返回 SPU 级别信息。查看每个 SKU 的价格和库存需调用 `spu-detail`。
199
+
200
+ ### 修改 SKU 价格
201
+
202
+ ```bash
203
+ r2-cli goods taobao price \
204
+ --jbp-spu-id <jbpSpuId> \
205
+ --jbp-sku-id <jbpSkuId> \
206
+ --shop-id <shopId> \
207
+ --sub-item-id <itemId> \
208
+ --price <amount> \
209
+ --json
210
+ ```
211
+
212
+ | 参数 | 必填 | 说明 |
213
+ |------|------|------|
214
+ | `--jbp-spu-id <id>` | 是 | 聚宝盆 SPU ID |
215
+ | `--jbp-sku-id <id>` | 是 | 聚宝盆 SKU ID |
216
+ | `--shop-id <id>` | 是 | 淘宝店铺 ID |
217
+ | `--sub-item-id <id>` | 否 | 子商品 ID(即已上架列表的 `itemId`,从 listing 获取) |
218
+ | `--price <amount>` | 是 | 新价格,**单位:元**(API 直接传元,不转分) |
219
+
220
+ > **重要**:改价和申请上架的 price 参数单位都是**元**(CLI 直接传元,API 内部转分存储)。`--sub-item-id` 建议传入,从 `goods taobao listing` 的 `itemId` 或 `spu-detail` 的 `haveApplySkuList.subItemId` 获取。
221
+
222
+ ### 修改 SKU 库存
223
+
224
+ ```bash
225
+ r2-cli goods taobao stock \
226
+ --jbp-spu-id <jbpSpuId> \
227
+ --jbp-sku-id <jbpSkuId> \
228
+ --shop-id <shopId> \
229
+ --sub-item-id <itemId> \
230
+ --quantity <n> \
231
+ --json
232
+ ```
233
+
234
+ | 参数 | 必填 | 说明 |
235
+ |------|------|------|
236
+ | `--jbp-spu-id <id>` | 是 | 聚宝盆 SPU ID |
237
+ | `--jbp-sku-id <id>` | 是 | 聚宝盆 SKU ID |
238
+ | `--shop-id <id>` | 是 | 淘宝店铺 ID |
239
+ | `--sub-item-id <id>` | 否 | 子商品 ID(从 listing 的 `itemId` 获取) |
240
+ | `--quantity <n>` | 是 | 新库存数量 |
241
+
242
+ ### 下架
243
+
244
+ ```bash
245
+ # 下架整个 SPU
246
+ r2-cli goods taobao down --jbp-spu-id <jbpSpuId> --shop-id <shopId> --json
247
+
248
+ # 下架单个 SKU(需传 --sub-item-id)
249
+ r2-cli goods taobao down --jbp-spu-id <jbpSpuId> --jbp-sku-id <jbpSkuId> --shop-id <shopId> --sub-item-id <itemId> --json
250
+ ```
251
+
252
+ > **注意**:下架单个 SKU 时 `--sub-item-id` **必传**,不传会报 `Missing required arguments:subItemId:null`。从 `spu-detail` 的 `haveApplySkuList` 中获取 `subItemId`,或从 `goods taobao listing` 的 `itemId` 获取。
253
+
254
+ ---
255
+
256
+ ## Agent 常见错误预防
257
+
258
+ - **`--apply-skus` 传 JSON 字符串**:值必须是 `JSON.stringify()` 后的字符串,不能直接传对象
259
+ - **价格单位统一为元**:apply、price、stock 三个命令 CLI 统一接受元,API 内部自动转分。响应中 price 字段是分(展示时需 /100)
260
+ - **`canApply=false` 的 SKU 不能申请**:提交前确认从 `canApplySkuList` 中选择 `canApply=true` 的 SKU
261
+ - **禁止传 `--identify-org-id`**:即使 `needIdentify=true` 也不要传,否则报"鉴定机构id填写有误"
262
+ - **`jbpSpuId` 和 `jbpSkuId` 是数字**:从 API 返回中直接取,不要转字符串
263
+ - **城市/省份参数实际必填**:`cityCode`/`cityName`/`proCode`/`proName` 不传会报 `Missing required arguments:cityCode`,默认用杭州
264
+ - **`deliveryId` 必传**:从 spu-detail 的 `delivery.deliveryId` 获取
265
+ - **`spuVersion` 和 `skuVersion` 建议传入**:从 spu-detail 获取,避免版本冲突
266
+ - **改价必须传 `--sub-item-id`**:从 `goods taobao listing` 的 `itemId` 字段获取,不传报 `Missing required arguments:subItemId`
267
+ - **追加 SKU 可能失败**:已上架的 SPU 追加新 SKU 时淘宝可能返回 `Remote service error`,建议一次性选完 SKU
268
+
269
+ ## 错误处理
270
+
271
+ | 错误信息 | 原因 | 解决方法 |
272
+ |----------|------|----------|
273
+ | `Missing required arguments:cityCode` | 缺少城市编码 | 传 `--city-code` `--city-name` `--pro-code` `--pro-name`(默认杭州) |
274
+ | `鉴定机构id填写有误` | 传了 `--identify-org-id -1` | **去掉 `--identify-org-id` 参数**,不要传 |
275
+ | `Missing required arguments:subItemId` | 改价/下架缺少子商品 ID | 从 `spu-detail` 的 `haveApplySkuList.subItemId` 或 listing 的 `itemId` 获取 |
276
+ | `Remote service error` | 追加 SKU 或淘宝 API 异常 | 已上架 SPU 追加 SKU 可能不支持,尝试一次性上架所有 SKU |
277
+ | `Cannot invoke getBody() is null` | 淘宝 API 返回空响应 | 检查是否缺少必填参数(如 cityCode),参考上面具体错误 |
278
+ | `暂未开通此业务` | 店铺未开通阿里资产业务权限 | 联系平台小二开通 |
279
+ | `--apply-skus JSON 解析失败` | JSON 格式错误 | 检查 JSON 格式,确保用单引号包裹 |
280
+ | `--jbp-spu-id 必须为有效数字` | SPU ID 格式错误 | 从 spu-query 返回中获取正确的数字 ID |
281
+
282
+ ## References
283
+
284
+ - [r2-goods SKILL.md](../SKILL.md) — 商品管理概览和路由决策
285
+ - [r2-shared](../../r2-shared/SKILL.md) — 认证和全局规则
@@ -20,7 +20,8 @@
20
20
  **上传图片**:
21
21
 
22
22
  ```bash
23
- r2-cli goods hang-up upload-images --shop-id <shopId> --files /path/img1.jpg,/path/img2.jpg --json
23
+ r2-cli goods xianyu hang-up upload-images --shop-id <shopId> --files /path/img1.jpg,/path/img2.jpg --json
24
+ # 或使用 CDN URL:--urls https://cdn.example.com/img1.jpg,https://cdn.example.com/img2.jpg
24
25
  ```
25
26
 
26
27
  返回:
@@ -74,7 +75,7 @@ r2-cli goods hang-up upload-images --shop-id <shopId> --files /path/img1.jpg,/pa
74
75
  **获取类目 → 自动匹配**:
75
76
 
76
77
  ```bash
77
- r2-cli goods hang-up categories --json
78
+ r2-cli goods xianyu hang-up categories --json
78
79
  ```
79
80
 
80
81
  Agent 根据图片识别结果自动匹配类目(不需要用户从列表中选)。只在识别不确定时才展示列表:
@@ -89,7 +90,7 @@ Agent 根据图片识别结果自动匹配类目(不需要用户从列表中
89
90
  **获取属性 → 自动匹配**:
90
91
 
91
92
  ```bash
92
- r2-cli goods hang-up props --channel-cat-id <channelCatId> --json
93
+ r2-cli goods xianyu hang-up props --channel-cat-id <channelCatId> --json
93
94
  ```
94
95
 
95
96
  Agent 遍历所有属性,尽量自动匹配:
@@ -105,7 +106,7 @@ Agent 遍历所有属性,尽量自动匹配:
105
106
  **品牌精确匹配规则**:brands 搜索结果中必须选**完全匹配**的官方名称(如搜 Nike → 只选 `Nike/耐克`,忽略 BACHNIKE、NIKE 7 等)。**支持大小写模糊搜索**。
106
107
 
107
108
  ```bash
108
- r2-cli goods hang-up brands --channel-cat-id <id> --prop-id <品牌propId> --key "Nike" --json
109
+ r2-cli goods xianyu hang-up brands --channel-cat-id <id> --prop-id <品牌propId> --key "Nike" --json
109
110
  ```
110
111
 
111
112
  最终构建 `--item-attrs`(**5 个字段:valueName、valueId、propId、propName、channelCatId**):
@@ -150,7 +151,7 @@ Agent 将所有自动填充和识别结果汇总展示给用户,**一次确认
150
151
  **所有参数就绪后提交**:
151
152
 
152
153
  ```bash
153
- r2-cli goods hang-up submit \
154
+ r2-cli goods xianyu hang-up submit \
154
155
  --shop-id <shopId> \
155
156
  --title "商品标题" \
156
157
  --price 599 \
@@ -166,7 +167,7 @@ r2-cli goods hang-up submit \
166
167
  --json
167
168
  ```
168
169
 
169
- 成功返回:`{ "success": true, "data": "上架成功" }`
170
+ 成功返回:`{ "success": true, "data": "挂售提交成功" }`
170
171
 
171
172
  ### 友好输出指引
172
173