@round2ai/r2-cli 1.0.12 → 1.0.13-beta.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/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@round2ai/r2-cli",
3
- "version": "1.0.12",
3
+ "version": "1.0.13-beta.0",
4
4
  "description": "R2-CLI,向 AI 开放二手潮奢交易全链路能力",
5
5
  "main": "dist/r2-cli.js",
6
6
  "type": "module",
7
7
  "bin": {
8
- "r2-cli": "./dist/r2-cli.js"
8
+ "r2-cli": "dist/r2-cli.js"
9
9
  },
10
10
  "scripts": {
11
11
  "postinstall": "node scripts/install-skills.js",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "repository": {
41
41
  "type": "git",
42
- "url": "https://github.com/Round2AI/r2-cli"
42
+ "url": "git+https://github.com/Round2AI/r2-cli.git"
43
43
  },
44
44
  "dependencies": {
45
45
  "@inquirer/prompts": "^8.4.2",
@@ -1,63 +1,20 @@
1
1
  /**
2
- * postinstall: skills/ 复制到 ~/.agents/skills/
2
+ * postinstall: 通过 skills CLI 将本地 skills 安装到所有 Agent 目录
3
+ * 自动适配 Claude Code / Codex / Gemini CLI 等所有 Agent
3
4
  */
4
5
 
5
- import fs from "node:fs";
6
+ import { execSync } from "node:child_process";
6
7
  import path from "node:path";
7
- import os from "node:os";
8
8
  import { fileURLToPath } from "node:url";
9
9
 
10
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
- const pkgSkillsDir = path.join(__dirname, "..", "skills");
12
- const agentsDir = path.join(os.homedir(), ".agents", "skills");
13
-
14
- if (!fs.existsSync(pkgSkillsDir)) process.exit(0);
15
-
16
- fs.mkdirSync(agentsDir, { recursive: true });
17
-
18
- for (const name of fs.readdirSync(pkgSkillsDir)) {
19
- const rawSrc = path.join(pkgSkillsDir, name);
20
- let src;
21
- try { src = fs.realpathSync(rawSrc); } catch { continue; }
22
- if (!fs.statSync(src).isDirectory()) continue;
23
-
24
- const dest = path.join(agentsDir, name);
25
- if (fs.existsSync(dest)) {
26
- for (const old of fs.readdirSync(dest)) {
27
- const oldPath = path.join(dest, old);
28
- fs.statSync(oldPath).isDirectory()
29
- ? fs.rmSync(oldPath, { recursive: true })
30
- : fs.unlinkSync(oldPath);
31
- }
32
- }
33
- fs.mkdirSync(dest, { recursive: true });
34
-
35
- for (const file of fs.readdirSync(src)) {
36
- const fileSrc = path.join(src, file);
37
- const fileDest = path.join(dest, file);
38
- if (fs.statSync(fileSrc).isDirectory()) {
39
- copyDir(fileSrc, fileDest);
40
- } else {
41
- fs.copyFileSync(fileSrc, fileDest);
42
- }
43
- }
44
- }
45
-
46
- function copyDir(src, dest) {
47
- if (fs.existsSync(dest)) {
48
- for (const old of fs.readdirSync(dest)) {
49
- const oldPath = path.join(dest, old);
50
- fs.statSync(oldPath).isDirectory()
51
- ? fs.rmSync(oldPath, { recursive: true })
52
- : fs.unlinkSync(oldPath);
53
- }
54
- }
55
- fs.mkdirSync(dest, { recursive: true });
56
- for (const file of fs.readdirSync(src)) {
57
- const fileSrc = path.join(src, file);
58
- const fileDest = path.join(dest, file);
59
- fs.statSync(fileSrc).isDirectory()
60
- ? copyDir(fileSrc, fileDest)
61
- : fs.copyFileSync(fileSrc, fileDest);
62
- }
11
+ const skillsDir = path.join(__dirname, "..", "skills");
12
+
13
+ try {
14
+ execSync(`npx skills add "${skillsDir}" --all -g`, {
15
+ stdio: "inherit",
16
+ timeout: 60_000,
17
+ });
18
+ } catch {
19
+ // 网络不可用或 skills CLI 失败时静默跳过
63
20
  }
@@ -60,6 +60,8 @@ r2-cli auth login --json
60
60
 
61
61
  ### Agent 操作步骤
62
62
 
63
+ > **注意**:不要在命令末尾加 `&`。`run_in_background: true` 已处理后台运行,加 `&` 会导致 shell 立即返回,无法捕获后续输出。
64
+
63
65
  1. 用 Bash 工具 `run_in_background: true` 启动命令
64
66
  2. 用 `TaskOutput(block=true, timeout=5000)` 获取第 1 段 JSON
65
67
  3. **必须先**将 `qrUrl` 以醒目格式单独一行展示给用户:
@@ -46,7 +46,7 @@ metadata:
46
46
  | `r2-cli goods shops [--json]` | 查看已授权店铺 | [r2-goods-query](references/r2-goods-query.md) |
47
47
  | `r2-cli goods stocks [--json]` | 查看仓库 | [r2-goods-query](references/r2-goods-query.md) |
48
48
  | `r2-cli goods list [--stock-id <id>] [--json]` | 查看选品商品 | [r2-goods-query](references/r2-goods-query.md) |
49
- | `r2-cli goods listing [--json]` | 查询上架列表 | [r2-goods-query](references/r2-goods-query.md) |
49
+ | `r2-cli goods listing [--status <up/down/sold>] [--json]` | 查询上架列表 | [r2-goods-query](references/r2-goods-query.md) |
50
50
 
51
51
  ### 上架/下架/改价/修改
52
52
 
@@ -118,7 +118,7 @@ metadata:
118
118
  5. **汇总展示**:自动填充的字段标 ✅,缺失字段标 ❓ 让用户补充
119
119
  6. **提交**:`hang-up submit` — 必填:`shop-id`、`title`、`price`、`category-id`、`channel-cat-id`、`image-ids`、`stuff-status`、`desc`、`out-item-no`
120
120
 
121
- **核心原则**:**图片里能看到的,就别问用户**。只问价格和商家编码,其他全部从图片自动提取。
121
+ **核心原则**:**图片里能看到的,就别问用户**。只问价格和商家编码(优先用户自定义,不填则推荐自动生成),其他全部从图片自动提取。
122
122
 
123
123
  **关键注意事项**:
124
124
  - **品牌必须双传**:`--brand-name` + itemAttrs 中的一项(含 propId/valueId/valueName),缺一不可
@@ -4,13 +4,14 @@
4
4
 
5
5
  挂售模式支持完整商品信息:图片、类目、属性等。与普通上架(`goods up`)是不同流程。
6
6
 
7
- **核心理念**:**图片里能看到的,就别问用户**。Agent 从图片中提取一切可识别的信息,用户只需要提供价格和商家编码。
7
+ **核心理念**:**图片里能看到的,就别问用户**。Agent 从图片中提取一切可识别的信息,用户只需要提供价格。
8
8
 
9
9
  ## 核心原则
10
10
 
11
11
  - **图片优先**:所有字段优先从图片提取,图片无法识别时才问用户
12
- - 必须问用户的只有:**价格、商家编码**
13
- - **必须问用户的条件**:价格(永远无法从图片判断)和商家编码(用户自定义)。其他一切字段都应尝试从图片获取
12
+ - 必须问用户的只有:**价格**
13
+ - 商家编码(`out-item-no`)**优先让用户自定义**,用户不填则推荐自动生成编码(如 `GS20260512-0005`)
14
+ - **必须问用户的条件**:价格(永远无法从图片判断)。其他一切字段都应尝试从图片获取。商家编码优先用户自定义,不填则推荐自动生成
14
15
  - **描述必须自动生成**:基于 AI 识别的品牌+款式+颜色+材质+货号自动组合,不要标记为"需要补充"
15
16
  - **品牌必须双传**:`--brand-name`(文本字段)+ itemAttrs 中的一项(含 propId/valueId/valueName),缺一不可
16
17
  - **季节自动推断**:根据商品类型推断适用季节(夹克/风衣→春秋季,羽绒服→秋冬季,T恤/短裤→夏季),不需要问用户
@@ -69,7 +70,7 @@ r2-cli goods hang-up upload-images --shop-id <shopId> --files /path/img1.jpg,/pa
69
70
  | `--goods-no`(货号) | ⚠️ | 有标签则读取,无则留空 |
70
71
  | 款式/颜色/材质属性 | ⚠️ | 能识别则自动匹配 propsValues,不能则汇总时问 |
71
72
  | `--price`(售价) | ❌ | **必须问用户** |
72
- | `--out-item-no`(商家编码) | | **必须问用户** |
73
+ | `--out-item-no`(商家编码) | ⚠️ | 先问用户自定义编码,不填则推荐自动生成(如 `GS20260512-0005`) |
73
74
  | `--shop-id`(店铺) | ❌ | 只有一个店铺时自动选,多个则问 |
74
75
 
75
76
  **成色判断映射**:
@@ -155,7 +156,7 @@ Agent 将所有自动填充和识别结果汇总展示给用户,**一次确认
155
156
  ✅ 鞋码:42(图片识别)
156
157
  ❓ 季节:?(无法识别,请选择:春季/夏季/秋季/冬季/四季)
157
158
  💰 价格:?(必填)
158
- 📋 商家编码:?(必填)
159
+ 📋 商家编码:?(优先自定义,不填自动生成)
159
160
  ```
160
161
 
161
162
  **处理顺序**:
@@ -163,7 +164,7 @@ Agent 将所有自动填充和识别结果汇总展示给用户,**一次确认
163
164
  2. 让用户补充缺失字段(价格、商家编码、无法识别的属性)
164
165
  3. 用户确认后直接提交
165
166
 
166
- **所有参数就绪后直接提交,不需要用户确认**:
167
+ **所有参数就绪后提交**:
167
168
 
168
169
  ```bash
169
170
  r2-cli goods hang-up submit \
@@ -209,11 +210,19 @@ r2-cli goods hang-up submit \
209
210
  | 缺失字段 | 何时询问 | 询问方式 |
210
211
  |----------|----------|----------|
211
212
  | `--price`(售价) | 上传图片时 | "这个商品上架价格是多少?" |
212
- | `--out-item-no`(商家编码) | 上传图片时 | "商家编码是什么?(同店铺唯一标识)" |
213
+ | `--out-item-no`(商家编码) | 上传图片时 | 先问:"商家编码是什么?"用户不填则推荐自动生成编码 |
213
214
  | `--shop-id`(店铺) | 流程开始时 | 展示店铺列表让用户选择 |
214
215
  | `--title`(标题) | 图片识别无法生成时 | "商品标题用什么?" |
215
216
  | `--desc`(描述) | 图片识别无法生成时 | "商品描述?" |
216
217
 
218
+ ## Agent 常见错误预防
219
+
220
+ - **不要在命令末尾加 `&`**:如果用 `run_in_background: true` 启动命令,不要额外加 `&`,否则 shell 立即返回,无法捕获后续输出
221
+ - **`--image-ids` 保持字符串**:图片 ID 是 19 位数字(如 `"1086608743767730915"`),JavaScript `Number()` 会精度丢失。拼接时用字符串拼接,不要 `parseInt`/`Number`
222
+ - **`--stuff-status` 准新是数字 `-1`**:不是字符串 `"-1"`,直接传 `--stuff-status -1`
223
+ - **`--item-attrs` 传 JSON 字符串**:值必须是 `JSON.stringify()` 后的字符串,不能直接传对象。命令行示例:`--item-attrs '[{"propId":"x","valueId":"y"}]'`
224
+ - **`--files` 和 `--image-ids` 都是逗号分隔**:不要多次传 `--files`,用逗号拼成单个值:`--files a.jpg,b.jpg`
225
+
217
226
  ## 必填参数
218
227
 
219
228
  | 参数 | 说明 |
@@ -23,7 +23,24 @@
23
23
  }
24
24
  ```
25
25
 
26
- 状态值:`init`(处理中)、`up`(已上架)、`down`(已下架)、`fail`(失败,查看 `errorMsg`)
26
+ 状态值:`init`(处理中)、`up`(已上架)、`down`(已下架)、`fail`(失败,查看 `errorMsg`)、`sold`(已售出)
27
+
28
+ ## 上架列表返回字段
29
+
30
+ | 字段 | 说明 |
31
+ |------|------|
32
+ | `id` | 上架记录 ID(edit/down/price 的 `--id` 取这个值) |
33
+ | `stockGoodsId` | 库存商品 ID(挂售商品可能为 0) |
34
+ | `shopId` | 店铺 ID |
35
+ | `goodsName` | 商品名称 |
36
+ | `brandName` | 品牌 |
37
+ | `price` | 上架价格 |
38
+ | `status` | 状态:`init`/`up`/`down`/`fail`/`sold` |
39
+ | `thirdItemNo` | 平台商品 ID |
40
+ | `outItemNo` | 商家编码 |
41
+ | `spec` | 规格(尺码) |
42
+ | `platform` | 平台(xianyu) |
43
+ | `gmtCreate` / `gmtModified` | 创建/修改时间戳 |
27
44
 
28
45
  ## 上架参数
29
46
 
@@ -71,6 +88,12 @@ r2-cli goods price --stock-goods-id <id> --shop-id <id> --price <新价格> --js
71
88
  | 上架记录 ID | `--id <goodsListingId>` | 推荐,从 listing 的 id 字段取 |
72
89
  | 库存商品 + 店铺 | `--stock-goods-id <id> --account <shopId>` | 备选,挂售商品 stockGoodsId 可能为 0 |
73
90
 
91
+ ### Agent 注意事项
92
+
93
+ - **`--image-ids` 保持字符串**:图片 ID 是 19 位数字,`Number()` 会精度丢失
94
+ - **`--item-attrs` 传 JSON 字符串**:必须是 `JSON.stringify()` 后的结果,不能直接传对象
95
+ - **即使不改类目也要传 `--category-id` 和 `--channel-cat-id`**:后端必填,缺少会报 `getCategoryId() is null`
96
+
74
97
  ### 必填参数
75
98
 
76
99
  | 参数 | 说明 |
@@ -126,7 +149,7 @@ r2-cli goods edit \
126
149
 
127
150
  ```bash
128
151
  # 改标题
129
- r2-cli goods goods edit --id 5 \
152
+ r2-cli goods edit --id 5 \
130
153
  --category-id 50106003 --channel-cat-id "f4718bbb04d7ed1facde29f76907b07f" \
131
154
  --title "新标题" --json
132
155
 
@@ -36,7 +36,7 @@ r2-cli goods list --stock-id <stockId> --json
36
36
  r2-cli goods list --stock-goods-id <id> --json
37
37
 
38
38
  # 翻页
39
- r2-cli goods list --stock-id <stockId> --page 2 --size 20 --json
39
+ r2-cli goods list --stock-id <stockId> --page 2 --size 50 --json
40
40
  ```
41
41
 
42
42
  返回字段:
@@ -54,10 +54,12 @@ r2-cli goods list --stock-id <stockId> --page 2 --size 20 --json
54
54
 
55
55
  ```bash
56
56
  r2-cli goods listing --json
57
- r2-cli goods listing --status up --json # 只看已上架
57
+ r2-cli goods listing --status up --json # 只看已上架
58
+ r2-cli goods listing --status sold --json # 只看已售出
58
59
  r2-cli goods listing --shop-id <id> --json # 按店铺过滤
59
60
  r2-cli goods listing --stock-goods-id <id> --json # 按商品过滤
60
61
  r2-cli goods listing --id <id> --json # 精确查询
62
+ r2-cli goods listing --page 2 --size 50 --json # 翻页
61
63
  ```
62
64
 
63
- 过滤参数:`--id`、`--stock-goods-id`、`--shop-id`、`--stock-id`、`--status`(init/up/down/fail)、`--platform`
65
+ 过滤参数:`--id`、`--stock-goods-id`、`--shop-id`、`--stock-id`、`--status`(init/up/down/fail/sold)、`--platform`、`--page`(默认 1)、`--size`(默认 20,最大 50)
@@ -28,6 +28,7 @@ metadata:
28
28
  - 所有命令**必须**通过已安装的 `r2-cli` 二进制执行(`r2-cli goods ...`、`r2-cli auth ...`)
29
29
  - **禁止**读取项目源码或用 `tsx`/`node` 直接运行源文件
30
30
  - 如果 `r2-cli` 命令不可用,提示用户先安装:`npm install -g @round2ai/r2-cli@latest`
31
+ - **不要在命令末尾加 `&`**:如果用 Bash 工具的 `run_in_background: true`,不要额外加 `&`,否则 shell 立即返回导致输出丢失
31
32
 
32
33
  **版本检查**:
33
34
  - 首次使用时,Agent 应运行 `r2-cli --version` 检查当前版本
@@ -66,7 +67,7 @@ npm install -g @round2ai/r2-cli@latest
66
67
  | 查询 | `r2-cli goods shops [--json]` | 查看已授权店铺 |
67
68
  | | `r2-cli goods stocks [--json]` | 查看仓库 |
68
69
  | | `r2-cli goods list [--stock-id <id>] [--json]` | 查看选品商品 |
69
- | | `r2-cli goods listing [--json]` | 查询上架列表 |
70
+ | | `r2-cli goods listing [--status <up/down/sold>] [--json]` | 查询上架列表 |
70
71
  | 上架 | `r2-cli goods up --stock-goods-id <> --shop-id <> --price <> --json` | 普通上架(选品商品) |
71
72
  | | `r2-cli goods down --id <id> [--json]` | 下架商品 |
72
73
  | | `r2-cli goods price --id <id> --price <amount> [--json]` | 修改价格 |