@round2ai/r2-cli 1.0.14 → 1.0.15
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 +22 -3
- package/dist/README.md +22 -3
- package/dist/r2-cli.js +39 -38
- package/package.json +3 -2
- package/skills/r2-auth/SKILL.md +17 -13
- package/skills/r2-goods/SKILL.md +59 -12
- package/skills/r2-goods/references/r2-goods-hangup.md +34 -8
- package/skills/r2-goods/references/r2-goods-listing.md +9 -2
- package/skills/r2-shared/SKILL.md +2 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
R2-CLI — 二手潮奢交易命令行工具,由 [Round2AI](https://github.com/Round2AI) 团队维护 — 让人类和 AI Agent 都能在终端中完成商品上架等交易操作。
|
|
7
7
|
|
|
8
|
-
覆盖商品上架、挂售、商品信息修改、认证登录等核心业务域,提供
|
|
8
|
+
覆盖商品上架、挂售、商品信息修改、认证登录等核心业务域,提供 19 个命令及 3 个 AI Agent [Skills](./skills/)。
|
|
9
9
|
|
|
10
10
|
[安装](#安装与快速开始) · [AI Agent 快速开始](#快速开始ai-agent) · [Agent Skills](#agent-skills) · [认证](#认证) · [命令](#命令参考) · [安全](#安全与风险提示)
|
|
11
11
|
|
|
@@ -21,8 +21,8 @@ R2-CLI — 二手潮奢交易命令行工具,由 [Round2AI](https://github.com
|
|
|
21
21
|
| 类别 | 能力 |
|
|
22
22
|
|------|------|
|
|
23
23
|
| 认证登录 | 扫码登录(第二回合 APP / 微信 / 支付宝)、闲鱼店铺授权、状态查询、登出(Agent 一步式流程) |
|
|
24
|
-
| 商品管理 | 商品上架(4 步流程:获取店铺 → 获取仓库 → 获取选品商品 → 提交上架 +
|
|
25
|
-
| 闲鱼挂售 |
|
|
24
|
+
| 商品管理 | 商品上架(4 步流程:获取店铺 → 获取仓库 → 获取选品商品 → 提交上架 + 自动轮询上架结果)、商品信息修改(AI 读图识别 → 自动匹配类目/属性 → 提交修改)、店铺查看、仓库查看、选品商品查看、上架列表查询、下架、改价 |
|
|
25
|
+
| 闲鱼挂售 | 图片上传(自动压缩大图、并行上传、失败重试)→ AI 读图识别商品信息 → 自动匹配类目/属性 → 提交挂售 |
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -158,6 +158,24 @@ Token 存储在 `~/.r2-cli/config.json`(原子写入防丢失),过期后
|
|
|
158
158
|
| `r2-cli goods down --id <id> [--json]` | 下架商品(也可用 `--stock-goods-id <id> --shop-id <id>`) |
|
|
159
159
|
| `r2-cli goods price --id <id> --price <amount> [--json]` | 修改上架价格(也可用 `--stock-goods-id <id> --shop-id <id>`) |
|
|
160
160
|
|
|
161
|
+
### 修改商品信息
|
|
162
|
+
|
|
163
|
+
修改已上架商品的标题、描述、品牌、类目、图片、属性等。Agent 可自动读图识别并填充商品信息。
|
|
164
|
+
|
|
165
|
+
| 命令 | 说明 |
|
|
166
|
+
|------|------|
|
|
167
|
+
| `r2-cli goods edit --id <id> --category-id <id> --channel-cat-id <id> --json` | 修改商品信息(必填:定位参数 + 类目) |
|
|
168
|
+
| `r2-cli goods edit --id <id> --category-id <id> --channel-cat-id <id> --image-ids <ids> --item-attrs <json> --brand-name <name> --json` | 带图片和属性修改 |
|
|
169
|
+
|
|
170
|
+
**定位商品**:优先使用 `--id <goodsListingId>`(从上架列表 `id` 字段获取),也可用 `--stock-goods-id <id> --account <shopId>`。**必填参数**:定位参数(二选一)+ `--category-id` + `--channel-cat-id`(后端必填)
|
|
171
|
+
|
|
172
|
+
**关键约束**:
|
|
173
|
+
- **类目 ID 必须传**:即使不改类目也要传 `--category-id` 和 `--channel-cat-id`,后端复用挂售 DTO,缺少会报 `getCategoryId() is null`
|
|
174
|
+
- **`--item-attrs` 必须包含所有属性**:后端替换整个属性列表,漏传的属性会被清除。从 `goods hang-up props --channel-cat-id <id> --json` 获取全部属性后,修改目标值,其他保持原样一并传入
|
|
175
|
+
- **品牌必须双传**:`--brand-name`(文本字段)+ itemAttrs 中的品牌项(含 propId/valueId/valueName/propName/channelCatId 五个字段),缺一不可
|
|
176
|
+
|
|
177
|
+
**可选参数**:`--title`、`--desc`、`--image-ids`(需先通过 `hang-up upload-images` 上传)、`--item-attrs`(JSON,5 字段格式)、`--brand-name`、`--stuff-status`、`--goods-no`、`--original-price`、`--size`
|
|
178
|
+
|
|
161
179
|
### 闲鱼挂售(完整商品信息模式)
|
|
162
180
|
|
|
163
181
|
挂售模式支持完整的商品信息:图片、类目、属性、品牌等。Agent 可自动识别图片内容填充商品信息,流程:上传图片 → AI 识别 → 匹配类目/属性 → 提交。
|
|
@@ -167,6 +185,7 @@ Token 存储在 `~/.r2-cli/config.json`(原子写入防丢失),过期后
|
|
|
167
185
|
| `r2-cli goods hang-up categories [--json]` | 获取闲鱼类目列表(大分类 → 小分类) |
|
|
168
186
|
| `r2-cli goods hang-up props --channel-cat-id <id> [--json]` | 获取指定类目下的属性列表(含可选值) |
|
|
169
187
|
| `r2-cli goods hang-up brands --channel-cat-id <id> --prop-id <id> --key <keyword> [--json]` | 品牌搜索 |
|
|
188
|
+
| `r2-cli goods hang-up upload-images --shop-id <id> --files <paths> --json` | 批量上传图片到闲鱼(挂售前必须先上传) |
|
|
170
189
|
| `r2-cli goods hang-up submit --shop-id <id> --title <> --price <> --category-id <> --channel-cat-id <> --image-ids <> --stuff-status <> --desc <> --out-item-no <> --json` | 提交挂售上架 |
|
|
171
190
|
|
|
172
191
|
**挂售必填参数**:`--shop-id`、`--title`、`--price`、`--category-id`(大分类 ID)、`--channel-cat-id`(小分类 ID)、`--image-ids`(图片 ID,逗号分隔)、`--stuff-status`(成色:100 全新 / -1 准新 / 99 99新 / 95 95新 / 90 9新)、`--desc`(商品描述)、`--out-item-no`(商家编码,同店铺唯一)
|
package/dist/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
R2-CLI — 二手潮奢交易命令行工具,由 [Round2AI](https://github.com/Round2AI) 团队维护 — 让人类和 AI Agent 都能在终端中完成商品上架等交易操作。
|
|
7
7
|
|
|
8
|
-
覆盖商品上架、挂售、商品信息修改、认证登录等核心业务域,提供
|
|
8
|
+
覆盖商品上架、挂售、商品信息修改、认证登录等核心业务域,提供 19 个命令及 3 个 AI Agent [Skills](./skills/)。
|
|
9
9
|
|
|
10
10
|
[安装](#安装与快速开始) · [AI Agent 快速开始](#快速开始ai-agent) · [Agent Skills](#agent-skills) · [认证](#认证) · [命令](#命令参考) · [安全](#安全与风险提示)
|
|
11
11
|
|
|
@@ -21,8 +21,8 @@ R2-CLI — 二手潮奢交易命令行工具,由 [Round2AI](https://github.com
|
|
|
21
21
|
| 类别 | 能力 |
|
|
22
22
|
|------|------|
|
|
23
23
|
| 认证登录 | 扫码登录(第二回合 APP / 微信 / 支付宝)、闲鱼店铺授权、状态查询、登出(Agent 一步式流程) |
|
|
24
|
-
| 商品管理 | 商品上架(4 步流程:获取店铺 → 获取仓库 → 获取选品商品 → 提交上架 +
|
|
25
|
-
| 闲鱼挂售 |
|
|
24
|
+
| 商品管理 | 商品上架(4 步流程:获取店铺 → 获取仓库 → 获取选品商品 → 提交上架 + 自动轮询上架结果)、商品信息修改(AI 读图识别 → 自动匹配类目/属性 → 提交修改)、店铺查看、仓库查看、选品商品查看、上架列表查询、下架、改价 |
|
|
25
|
+
| 闲鱼挂售 | 图片上传(自动压缩大图、并行上传、失败重试)→ AI 读图识别商品信息 → 自动匹配类目/属性 → 提交挂售 |
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -158,6 +158,24 @@ Token 存储在 `~/.r2-cli/config.json`(原子写入防丢失),过期后
|
|
|
158
158
|
| `r2-cli goods down --id <id> [--json]` | 下架商品(也可用 `--stock-goods-id <id> --shop-id <id>`) |
|
|
159
159
|
| `r2-cli goods price --id <id> --price <amount> [--json]` | 修改上架价格(也可用 `--stock-goods-id <id> --shop-id <id>`) |
|
|
160
160
|
|
|
161
|
+
### 修改商品信息
|
|
162
|
+
|
|
163
|
+
修改已上架商品的标题、描述、品牌、类目、图片、属性等。Agent 可自动读图识别并填充商品信息。
|
|
164
|
+
|
|
165
|
+
| 命令 | 说明 |
|
|
166
|
+
|------|------|
|
|
167
|
+
| `r2-cli goods edit --id <id> --category-id <id> --channel-cat-id <id> --json` | 修改商品信息(必填:定位参数 + 类目) |
|
|
168
|
+
| `r2-cli goods edit --id <id> --category-id <id> --channel-cat-id <id> --image-ids <ids> --item-attrs <json> --brand-name <name> --json` | 带图片和属性修改 |
|
|
169
|
+
|
|
170
|
+
**定位商品**:优先使用 `--id <goodsListingId>`(从上架列表 `id` 字段获取),也可用 `--stock-goods-id <id> --account <shopId>`。**必填参数**:定位参数(二选一)+ `--category-id` + `--channel-cat-id`(后端必填)
|
|
171
|
+
|
|
172
|
+
**关键约束**:
|
|
173
|
+
- **类目 ID 必须传**:即使不改类目也要传 `--category-id` 和 `--channel-cat-id`,后端复用挂售 DTO,缺少会报 `getCategoryId() is null`
|
|
174
|
+
- **`--item-attrs` 必须包含所有属性**:后端替换整个属性列表,漏传的属性会被清除。从 `goods hang-up props --channel-cat-id <id> --json` 获取全部属性后,修改目标值,其他保持原样一并传入
|
|
175
|
+
- **品牌必须双传**:`--brand-name`(文本字段)+ itemAttrs 中的品牌项(含 propId/valueId/valueName/propName/channelCatId 五个字段),缺一不可
|
|
176
|
+
|
|
177
|
+
**可选参数**:`--title`、`--desc`、`--image-ids`(需先通过 `hang-up upload-images` 上传)、`--item-attrs`(JSON,5 字段格式)、`--brand-name`、`--stuff-status`、`--goods-no`、`--original-price`、`--size`
|
|
178
|
+
|
|
161
179
|
### 闲鱼挂售(完整商品信息模式)
|
|
162
180
|
|
|
163
181
|
挂售模式支持完整的商品信息:图片、类目、属性、品牌等。Agent 可自动识别图片内容填充商品信息,流程:上传图片 → AI 识别 → 匹配类目/属性 → 提交。
|
|
@@ -167,6 +185,7 @@ Token 存储在 `~/.r2-cli/config.json`(原子写入防丢失),过期后
|
|
|
167
185
|
| `r2-cli goods hang-up categories [--json]` | 获取闲鱼类目列表(大分类 → 小分类) |
|
|
168
186
|
| `r2-cli goods hang-up props --channel-cat-id <id> [--json]` | 获取指定类目下的属性列表(含可选值) |
|
|
169
187
|
| `r2-cli goods hang-up brands --channel-cat-id <id> --prop-id <id> --key <keyword> [--json]` | 品牌搜索 |
|
|
188
|
+
| `r2-cli goods hang-up upload-images --shop-id <id> --files <paths> --json` | 批量上传图片到闲鱼(挂售前必须先上传) |
|
|
170
189
|
| `r2-cli goods hang-up submit --shop-id <id> --title <> --price <> --category-id <> --channel-cat-id <> --image-ids <> --stuff-status <> --desc <> --out-item-no <> --json` | 提交挂售上架 |
|
|
171
190
|
|
|
172
191
|
**挂售必填参数**:`--shop-id`、`--title`、`--price`、`--category-id`(大分类 ID)、`--channel-cat-id`(小分类 ID)、`--image-ids`(图片 ID,逗号分隔)、`--stuff-status`(成色:100 全新 / -1 准新 / 99 99新 / 95 95新 / 90 9新)、`--desc`(商品描述)、`--out-item-no`(商家编码,同店铺唯一)
|
package/dist/r2-cli.js
CHANGED
|
@@ -1,49 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
`;process.stdout.write(a)}finally{
|
|
3
|
+
var ge=Object.defineProperty;var ct=(o,t)=>()=>(o&&(t=o(o=0)),t);var lt=(o,t)=>{for(var e in t)ge(o,e,{get:t[e],enumerable:!0})};var fo={};lt(fo,{UserInfoCard:()=>Ne});import{Box as K,Text as G}from"ink";import{jsx as J,jsxs as Y}from"react/jsx-runtime";function Ne({userInfo:o,lastLogin:t,daysSinceLogin:e}){let r=o.mobile?o.mobile.replace(/(\d{3})\d{4}(\d{4})/,"$1****$2"):"-";return Y(K,{flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"gray",paddingX:1,children:[J(G,{bold:!0,color:"cyan",children:"\u7528\u6237\u4FE1\u606F"}),Y(K,{flexDirection:"row",marginTop:1,children:[J(K,{width:10,children:J(G,{color:"gray",children:"\u6635\u79F0"})}),J(G,{color:"yellow",children:o.nickname})]}),Y(K,{flexDirection:"row",children:[J(K,{width:10,children:J(G,{color:"gray",children:"\u624B\u673A\u53F7"})}),J(G,{color:"yellow",children:r})]}),t&&Y(K,{flexDirection:"column",marginTop:1,children:[Y(G,{color:"gray",children:["\u6700\u540E\u767B\u5F55: ",t.toLocaleString()]}),e!==void 0&&Y(G,{color:"gray",children:[" \u8DDD\u4ECA: ",e," \u5929"]})]})]})}var ho=ct(()=>{"use strict"});var ft={};lt(ft,{renderComponent:()=>Bt,renderOnce:()=>yo});import De from"react";import $t from"chalk";import{render as Oe}from"ink";import{Writable as Ue}from"node:stream";function yo(o){let t=$t.level;process.env.NO_COLOR||($t.level=3);try{let e=[],r=new Ue({write(c,h,u){e.push(Buffer.from(c)),u()}});r.isTTY=!0,r.columns=process.stdout.columns||80,r.rows=process.stdout.rows||24,Oe(o,{stdout:r,patchConsole:!1}).unmount();let s=Buffer.concat(e).toString("utf8"),a=(s.split(/\x1B\[2J\x1B\[3J\x1B\[H/).at(-1)||s).replace(/\x1B\[\?[\d;]+[hl]/g,"").trimEnd()+`
|
|
4
|
+
`;process.stdout.write(a)}finally{$t.level=t}}function Bt(o,t){yo(De.createElement(o,t))}var st=ct(()=>{"use strict"});var Go={};lt(Go,{ShopsTable:()=>Ye});import{Box as A,Text as R}from"ink";import{jsx as f,jsxs as Z}from"react/jsx-runtime";function He(o){return o.map(t=>"shopName"in t?{id:t.shopId,name:t.shopName,platform:t.platform,expiresIn:t.expiresIn}:{id:t.id,name:t.name,platform:t.thirdUserId,expiresIn:t.expiresIn})}function Ve({hasPlatform:o,fillWidth:t}){return Z(A,{flexDirection:"row",paddingBottom:0,children:[o&&f(A,{width:Wt,children:f(R,{bold:!0,color:"white",children:"\u5E73\u53F0"})}),f(A,{width:t,children:f(R,{bold:!0,color:"white",children:"\u5E97\u94FA\u540D"})}),f(A,{width:Ht,children:f(R,{bold:!0,color:"white",children:"ID"})}),f(A,{width:Vt,children:f(R,{bold:!0,color:"white",children:"\u72B6\u6001"})})]})}function Ke({shop:o,hasPlatform:t,fillWidth:e}){let r=qo[o.platform]??o.platform;return Z(A,{flexDirection:"row",children:[t&&f(A,{width:Wt,children:f(R,{color:"cyan",children:r})}),f(A,{width:e,children:f(R,{bold:!0,children:o.name})}),f(A,{width:Ht,children:f(R,{color:"gray",children:o.id})}),f(A,{width:Vt,children:f(R,{color:"green",children:"\u25CF \u6388\u6743\u4E2D"})})]})}function Ye({shops:o,platform:t}){let e=He(o),r=t==="all",n=t==="all"?"\u6240\u6709\u6388\u6743\u5E97\u94FA":`${qo[t]??t}\u6388\u6743\u5E97\u94FA`,s=process.stdout.columns||80,i=4,a=Ht+Vt+(r?Wt:0),c=Math.max(s-i-a,20),h=a+c;return Z(A,{flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"gray",paddingX:1,children:[Z(A,{flexDirection:"row",children:[f(R,{bold:!0,color:"cyan",children:n}),Z(R,{color:"gray",children:[" \xB7 ",e.length," \u5BB6"]})]}),Z(A,{flexDirection:"column",marginTop:1,children:[f(Ve,{hasPlatform:r,fillWidth:c}),f(R,{color:"gray",children:"\u2500".repeat(h)}),e.map(u=>f(Ke,{shop:u,hasPlatform:r,fillWidth:c},u.id))]})]})}var qo,Wt,Ht,Vt,Jo=ct(()=>{"use strict";qo={xianyu:"\u95F2\u9C7C",douyin:"\u6296\u97F3"},Wt=8,Ht=16,Vt=10});var _o={};lt(_o,{StocksTable:()=>er});import{Box as I,Text as v}from"ink";import{jsx as g,jsxs as tt}from"react/jsx-runtime";function tr({fillWidth:o}){return tt(I,{flexDirection:"row",paddingBottom:0,children:[g(I,{width:Kt,children:g(v,{bold:!0,color:"white",children:"ID"})}),g(I,{width:Yt,children:g(v,{bold:!0,color:"white",children:"\u7528\u6237ID"})}),g(I,{width:Zt,children:g(v,{bold:!0,color:"white",children:"\u4ED3\u5E93ID"})}),g(I,{width:o,children:g(v,{bold:!0,color:"white",children:"\u4ED3\u5E93\u540D\u79F0"})}),g(I,{width:to,children:g(v,{bold:!0,color:"white",children:"\u521B\u5EFA\u65F6\u95F4"})})]})}function or({stock:o,fillWidth:t}){let e=new Date(o.gmtCreate).toLocaleString("zh-CN");return tt(I,{flexDirection:"row",children:[g(I,{width:Kt,children:g(v,{color:"gray",children:o.id})}),g(I,{width:Yt,children:g(v,{color:"gray",children:o.userId})}),g(I,{width:Zt,children:g(v,{color:"gray",children:o.stockId})}),g(I,{width:t,children:g(v,{bold:!0,children:o.stockName})}),g(I,{width:to,children:g(v,{color:"gray",children:e})})]})}function er({stocks:o}){let t=process.stdout.columns||80,e=4,r=Kt+Yt+Zt+to,n=Math.max(t-e-r,20),s=r+n;return tt(I,{flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"gray",paddingX:1,children:[tt(I,{flexDirection:"row",children:[g(v,{bold:!0,color:"cyan",children:"\u4ED3\u5E93\u5217\u8868"}),tt(v,{color:"gray",children:[" \xB7 ",o.length," \u4E2A"]})]}),tt(I,{flexDirection:"column",marginTop:1,children:[g(tr,{fillWidth:n}),g(v,{color:"gray",children:"\u2500".repeat(s)}),o.map(i=>g(or,{stock:i,fillWidth:n},i.id))]})]})}var Kt,Yt,Zt,to,Mo=ct(()=>{"use strict";Kt=6,Yt=10,Zt=10,to=22});import{Command as $r}from"commander";import rt from"chalk";import"commander";import{Command as To}from"commander";import x from"chalk";var F=class o extends Error{constructor(e,r,n){super(e);this.code=r;this.details=n;this.name="R2Error",Error.captureStackTrace&&Error.captureStackTrace(this,o)}code;details},b=class extends F{constructor(e,r,n){super(e,"API_ERROR",n);this.status=r;this.response=n;this.name="ApiError"}status;response},B=class extends F{constructor(e,r,n){super(e,"STORAGE_ERROR",{path:r,code:n});this.path=r;this.code=n;this.name="StorageError"}path;code},C=class extends F{constructor(t){super(t,"AUTH_ERROR"),this.name="AuthError"}},E=class extends F{constructor(e,r,n){super(e,"POLLING_ERROR",{attempts:r,timeout:n});this.attempts=r;this.timeout=n;this.name="PollingError"}attempts;timeout};async function pe(o,t,e){let r=new AbortController,n=()=>r.abort();e?.addEventListener("abort",n,{once:!0});let s=setTimeout(()=>r.abort(),t);try{return await o()}catch(i){throw r.signal.aborted&&!e?.aborted?new E("\u5355\u6B21\u8F6E\u8BE2\u8BF7\u6C42\u8D85\u65F6"):i}finally{clearTimeout(s),e?.removeEventListener("abort",n)}}async function W(o,t,e){let{interval:r,timeout:n,condition:s}=t,i=Date.now(),a=0;for(;Date.now()-i<n;){if(e?.aborted)throw new E("\u8F6E\u8BE2\u88AB\u4E2D\u6B62");a++;let c=n-(Date.now()-i),h=await pe(o,c,e);if(s(h,a))return h;await fe(r,e)}throw new E(`\u8F6E\u8BE2\u8D85\u65F6 (\u5DF2\u7B49\u5F85 ${Date.now()-i}ms, \u5171 ${a} \u6B21)`)}function fe(o,t){return new Promise((e,r)=>{if(t?.aborted){r(new E("\u8F6E\u8BE2\u88AB\u4E2D\u6B62"));return}let n=()=>{clearTimeout(s),r(new E("\u8F6E\u8BE2\u88AB\u4E2D\u6B62"))},s=setTimeout(()=>{t?.removeEventListener("abort",n),e()},o);t?.addEventListener("abort",n,{once:!0})})}import we from"node:fs";import{fileURLToPath as xe}from"node:url";import{createRequire as Ie}from"node:module";import co from"node:path";import{exec as Se}from"node:child_process";import he from"node:http";var kt=class o{server=null;pages=new Map;port=0;idleTimer=null;static IDLE_TIMEOUT_MS=1e4;async start(){return this.server?this.port:new Promise((t,e)=>{this.server=he.createServer((r,n)=>this.handleRequest(r,n)),this.server.listen(0,"127.0.0.1",()=>{let r=this.server.address();typeof r=="object"&&r?(this.port=r.port,t(this.port)):e(new Error("Failed to get server address"))}),this.server.on("error",e)})}registerPage(t,e,r,n){let s=this.pages.get(t);if(s){s.qrBuffer=r,s.status="waiting",s.config=n;let i=`data: ${JSON.stringify({status:"waiting"})}
|
|
5
5
|
|
|
6
6
|
`;for(let a of s.sseClients)a.write(i)}else this.pages.set(t,{html:e,qrBuffer:r,status:"waiting",sseClients:[],config:n});this.resetIdleTimer()}unregisterPage(t){let e=this.pages.get(t);if(e){for(let r of e.sseClients)r.end();e.sseClients.length=0,this.pages.delete(t),this.pages.size===0&&this.close()}}setStatus(t,e){let r=this.pages.get(t);if(!r)return;r.status=e;let n=`data: ${JSON.stringify({status:e})}
|
|
7
7
|
|
|
8
|
-
`;for(let s of r.sseClients)s.write(n)}close(){if(this.server){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null);for(let t of this.pages.values()){for(let e of t.sseClients)e.end();t.sseClients.length=0}this.pages.clear(),this.server.close(),this.server=null,this.port=0,
|
|
8
|
+
`;for(let s of r.sseClients)s.write(n)}close(){if(this.server){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null);for(let t of this.pages.values()){for(let e of t.sseClients)e.end();t.sseClients.length=0}this.pages.clear(),this.server.close(),this.server=null,this.port=0,H=null}}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{[...this.pages.values()].some(e=>e.sseClients.length>0)||this.close()},o.IDLE_TIMEOUT_MS)}handleRequest(t,e){let r=t.url??"/";for(let[n,s]of this.pages){if(r===n){e.writeHead(302,{Location:n+"/"}),e.end();return}if(r===n+"/"){e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(s.html);return}if(r===n+"/qr.png"){e.writeHead(200,{"Content-Type":"image/png","Content-Length":s.qrBuffer.length}),e.end(s.qrBuffer);return}if(r===n+"/events"){e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),e.write(`data: ${JSON.stringify({status:s.status})}
|
|
9
9
|
|
|
10
|
-
`),s.sseClients.push(e),t.on("close",()=>{let i=s.sseClients.indexOf(e);i>=0&&s.sseClients.splice(i,1)});return}if(r===n+"/config"){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(s.config??{}));return}}e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Not Found")}},
|
|
11
|
-
\u{1F50D} \u5DF2\u626B\u7801: ${
|
|
12
|
-
\u2705 \u7528\u6237\u5DF2\u786E\u8BA4\u767B\u5F55`)),s?.("success"),!0;case"expired":return i||console.log(
|
|
13
|
-
\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F`)),s?.("expired"),!0;case"canceled":return i||console.log(
|
|
14
|
-
\u{1F6AB} \u7528\u6237\u5DF2\u53D6\u6D88\u767B\u5F55`)),s?.("expired"),!0;default:return!1}}},n??void 0);if(a.status==="confirmed"&&a.token&&a.userInfo)return await this.storage.saveCredentials(a.token,a.userInfo),{userInfo:a.userInfo,token:a.token};throw a.status==="expired"?new
|
|
15
|
-
\u{1F510} \u6B63\u5728\u542F\u52A8\u626B\u7801\u767B\u5F55...`));let{qrData:e,qrUrl:r,setStatus:n,closeServer:s}=await this.generateQR();console.log(
|
|
16
|
-
`)),console.log(
|
|
17
|
-
`)),
|
|
18
|
-
`));let i=Number.parseInt(e.expireTime,10),a=Number.parseInt(e.pollInterval,10);try{let
|
|
10
|
+
`),s.sseClients.push(e),t.on("close",()=>{let i=s.sseClients.indexOf(e);i>=0&&s.sseClients.splice(i,1)});return}if(r===n+"/config"){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(s.config??{}));return}}e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Not Found")}},H=null,io=!1;function dt(){H&&H.close()}function ye(){io||(io=!0,process.on("exit",dt),process.on("SIGINT",dt),process.on("SIGTERM",dt),setInterval(()=>{process.stdin?.destroyed&&dt()},3e3).unref())}function ao(){return H||(H=new kt,ye()),H}var Ce=co.dirname(xe(import.meta.url)),Te="/login",be="/login-xianyu",Rt=null;async function Pe(o){return we.promises.readFile(co.join(Ce,"pages",o),"utf-8")}async function Ae(o){return Rt||(Rt=Ie(import.meta.url)),Rt("qrcode").toBuffer(o,{width:300,margin:2})}function q(o){let t=process.platform==="win32"?`start "" "${o}"`:process.platform==="darwin"?`open "${o}"`:`xdg-open "${o}"`;Se(t)}async function lo(o,t,e,r){let[n,s]=await Promise.all([Pe(t),Ae(e)]),i=ao(),a=await i.start();i.registerPage(o,n,s,r);let c=`http://127.0.0.1:${a}${o}/`;return{url:e,qrUrl:c,setStatus:h=>i.setStatus(o,h),closeServer:()=>i.unregisterPage(o)}}function Lt(o){return lo(Te,"login.html",o)}function Nt(o,t){return lo(be,"xianyu-auth.html",o,{authUrl:t})}import{promises as V}from"node:fs";import Dt from"node:path";import ve from"node:os";var ke=".r2-cli",ut=class{configPath;config;configLoaded=!1;dirEnsured=!1;constructor(){let t=ve.homedir(),e=Dt.join(t,ke);this.configPath=Dt.join(e,"config.json"),this.config={credentials:null}}getConfigPath(){return this.configPath}async loadConfig(){if(this.configLoaded)return this.config;try{let t=await V.readFile(this.configPath,"utf-8");return this.config=JSON.parse(t),this.configLoaded=!0,this.config}catch{return this.config={credentials:null},this.configLoaded=!0,this.config}}async ensureDir(){if(this.dirEnsured)return;let t=Dt.dirname(this.configPath);try{await V.stat(t)}catch(e){if(e.code==="ENOENT")await V.mkdir(t,{recursive:!0});else throw new B("Failed to create directory",t,e.code)}this.dirEnsured=!0}async saveConfig(t){this.config=t,await this.ensureDir();let e=JSON.stringify(t,null,2),r=this.configPath+".tmp";try{await V.writeFile(r,e,"utf-8"),await V.rename(r,this.configPath),this.configLoaded=!0}catch(n){throw await V.unlink(r).catch(s=>{typeof process.env.DEBUG<"u"&&console.error("[config] cleanup tmp failed:",s)}),new B("Failed to save config",this.configPath,n.code)}}},Ot=null;function Ut(){return Ot||(Ot=new ut),Ot}var jt=300*1e3,mt=class{store=Ut();isTokenExpired(t){return t.expire?Date.now()>=t.expire-jt:!1}async saveCredentials(t,e){let r=Date.now(),n=e.expire?Number.parseInt(e.expire,10):0,s={token:t,userInfo:e,timestamp:r,...n>0&&{expire:r+n}},i=await this.store.loadConfig();i.credentials=s,await this.store.saveConfig(i)}async getCredentials(){let t=await this.store.loadConfig();return!t.credentials||this.isTokenExpired(t.credentials)?null:t.credentials}async clearCredentials(){let t=await this.store.loadConfig();t.credentials=null,await this.store.saveConfig(t)}async getToken(){return(await this.getCredentials())?.token??null}async getUserInfo(){return(await this.getCredentials())?.userInfo??null}async isLoggedIn(){return await this.getCredentials()!==null}},Et=null;function nt(){return Et||(Et=new mt),Et}var Re="https://api.puresnake.com",gt=class{config;authStorage=null;cachedToken=null;tokenExpiry=0;constructor(t={}){this.config={baseUrl:t.baseUrl??Re,version:t.version??"v3",debug:t.debug??!1},this.authStorage=t.auth===!1?null:nt()}buildUrl(t){let e=t.startsWith("/")?t.slice(1):t;return`${this.config.baseUrl}/${this.config.version}/${e}`}async getAuthToken(){if(!this.authStorage)return;if(this.cachedToken&&Date.now()<this.tokenExpiry)return this.cachedToken;let t=await this.authStorage.getCredentials();if(!t)throw new C("\u8BF7\u5148\u8FD0\u884C r2-cli auth login \u767B\u5F55");return this.cachedToken=t.token,this.tokenExpiry=t.expire?t.expire-jt:Date.now()+1800*1e3,t.token}async requestFull(t,e){let r=this.buildUrl(t),{method:n,headers:s,body:i,timeout:a=3e4}=e,c=await this.getAuthToken(),h={...s,...c?{token:c}:{}},u=new AbortController,w=setTimeout(()=>u.abort(),a),M={method:n,headers:{"Content-Type":"application/json",...h},signal:u.signal};i!==void 0&&(M.body=JSON.stringify(i)),this.config.debug&&console.error(`[API ${n}]`,r,i);try{let d=await fetch(r,M);if(!d.ok){if(d.status===401)throw this.authStorage&&(this.cachedToken=null,await this.authStorage.clearCredentials().catch(z=>{console.error("[API] \u6E05\u9664\u51ED\u8BC1\u5931\u8D25:",z instanceof Error?z.message:String(z))})),new C("\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8FD0\u884C r2-cli auth login \u91CD\u65B0\u767B\u5F55");let At=await d.text();throw new b(At||`${d.status} ${d.statusText}`,d.status)}let k=await d.json();if(this.config.debug&&console.error("[API Response]",k),!k.success||k.status!==0)throw new b(k.msg||"\u672A\u77E5\u9519\u8BEF",k.status,k);return k}catch(d){throw d instanceof DOMException&&d.name==="AbortError"?new b(`\u8BF7\u6C42\u8D85\u65F6 (${a}ms)`,408):d}finally{clearTimeout(w)}}async request(t,e){return(await this.requestFull(t,e)).data}async get(t,e,r){let n=e&&e.size>0?`${t}?${e.toString()}`:t;return this.request(n,{method:"GET",headers:r})}async post(t,e,r){return this.request(t,{method:"POST",body:e,headers:r})}async put(t,e,r){return this.request(t,{method:"PUT",body:e,headers:r})}async delete(t,e){return this.request(t,{method:"DELETE",headers:e})}async upload(t,e,r){let n=this.buildUrl(t),s=await this.getAuthToken(),i={...r,...s?{token:s}:{}},a=new AbortController,c=setTimeout(()=>a.abort(),6e4),h={method:"POST",headers:i,body:e,signal:a.signal};this.config.debug&&console.error("[API UPLOAD]",n);try{let u=await fetch(n,h);if(!u.ok){if(u.status===401)throw this.authStorage&&(this.cachedToken=null,await this.authStorage.clearCredentials().catch(()=>{})),new C("\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8FD0\u884C r2-cli auth login \u91CD\u65B0\u767B\u5F55");if(u.status===413)throw new b("\u56FE\u7247\u592A\u5927\uFF0C\u4E0A\u4F20\u5931\u8D25\uFF08\u670D\u52A1\u7AEF\u9650\u5236\u7EA6 2MB\uFF09",413);let M=await u.text();throw new b(M||`${u.status} ${u.statusText}`,u.status)}let w=await u.json();if(this.config.debug&&console.error("[API Response]",w),!w.success||w.status!==0)throw new b(w.msg||"\u672A\u77E5\u9519\u8BEF",w.status,w);return w.data}catch(u){throw u instanceof DOMException&&u.name==="AbortError"?new b("\u4E0A\u4F20\u8D85\u65F6 (60000ms)",408):u}finally{clearTimeout(c)}}},pt=new gt,uo=new gt({auth:!1});var mo=uo;async function go(){return mo.post("app/qrcode/generate")}async function po(o){let t=new URLSearchParams;t.append("qrToken",o);let e=`app/qrcode/status?${t.toString()}`,r=await mo.requestFull(e,{method:"GET"});return r.token&&typeof r.data=="object"&&r.data!==null&&(r.data.token=r.token),r.data}async function wo(o,t,e){let{UserInfoCard:r}=await Promise.resolve().then(()=>(ho(),fo)),{renderComponent:n}=await Promise.resolve().then(()=>(st(),ft)),s=t!=null?{userInfo:o,lastLogin:t,daysSinceLogin:e??0}:{userInfo:o};n(r,s)}var ht=class{storage;constructor(t){this.storage=t??nt()}async generateQR(){let t=await go(),e=`https://m.puresnake.com/r2/auth/login?qrToken=${t.qrContent}&from=wechat`,r=await Lt(e);return{qrData:t,...r}}async waitForLogin(t,e,r,n,s,i){let a=await W(()=>po(t),{interval:r,timeout:e,condition:c=>{switch(c.status){case"scanned":return i||(console.log(x.cyan(`
|
|
11
|
+
\u{1F50D} \u5DF2\u626B\u7801: ${c.userInfo?.nickname||"\u672A\u77E5\u7528\u6237"}`)),console.log(x.yellow("\u8BF7\u5728 APP \u4E0A\u786E\u8BA4\u767B\u5F55"))),s?.("scanning"),!1;case"confirmed":return i||console.log(x.green(`
|
|
12
|
+
\u2705 \u7528\u6237\u5DF2\u786E\u8BA4\u767B\u5F55`)),s?.("success"),!0;case"expired":return i||console.log(x.red(`
|
|
13
|
+
\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F`)),s?.("expired"),!0;case"canceled":return i||console.log(x.red(`
|
|
14
|
+
\u{1F6AB} \u7528\u6237\u5DF2\u53D6\u6D88\u767B\u5F55`)),s?.("expired"),!0;default:return!1}}},n??void 0);if(a.status==="confirmed"&&a.token&&a.userInfo)return await this.storage.saveCredentials(a.token,a.userInfo),{userInfo:a.userInfo,token:a.token};throw a.status==="expired"?new C("\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55"):a.status==="canceled"?new C("\u7528\u6237\u5DF2\u53D6\u6D88\u767B\u5F55"):new C("\u767B\u5F55\u5931\u8D25: \u672A\u83B7\u53D6\u5230\u51ED\u8BC1")}async login(t){console.log(x.cyan(`
|
|
15
|
+
\u{1F510} \u6B63\u5728\u542F\u52A8\u626B\u7801\u767B\u5F55...`));let{qrData:e,qrUrl:r,setStatus:n,closeServer:s}=await this.generateQR();console.log(x.green(`\u2705 \u4E8C\u7EF4\u7801\u5DF2\u751F\u6210
|
|
16
|
+
`)),console.log(x.cyan(` \u94FE\u63A5: ${r}
|
|
17
|
+
`)),q(r),console.log(x.yellow(`\u23F3 \u7B49\u5F85\u626B\u7801...
|
|
18
|
+
`));let i=Number.parseInt(e.expireTime,10),a=Number.parseInt(e.pollInterval,10);try{let c=await this.waitForLogin(e.qrToken,i,a,t,n);return console.log(x.green(`
|
|
19
19
|
\u2705 \u767B\u5F55\u6210\u529F\uFF01
|
|
20
|
-
`)),wo(
|
|
20
|
+
`)),wo(c.userInfo),c}catch(c){throw console.log(x.red(`
|
|
21
21
|
\u274C \u767B\u5F55\u5931\u8D25
|
|
22
|
-
`)),
|
|
23
|
-
\u{1F6AA} \u6B63\u5728\u9000\u51FA\u767B\u5F55...`)),await this.storage.clearCredentials(),console.log(
|
|
24
|
-
`))}async status(){if(!await this.storage.isLoggedIn()){console.log(
|
|
25
|
-
`));return}let e=await this.storage.getCredentials(),r=e.userInfo,n=new Date(e.timestamp),s=Math.floor((Date.now()-e.timestamp)/(1e3*60*60*24));console.log(
|
|
26
|
-
`)),await wo(r,n,s)}},
|
|
27
|
-
\u2705 \u6388\u6743\u6210\u529F\uFF01\u5E97\u94FA: ${s.shopName} (${s.shopId})`)),n?.("success"),!0):s.status==="expired"?(console.log(
|
|
28
|
-
\u23F0 \u6388\u6743\u94FE\u63A5\u5DF2\u8FC7\u671F`)),n?.("expired"),!0):!1},r)}async function Gt(o){console.log(
|
|
29
|
-
\u{1F517} \u6B63\u5728\u83B7\u53D6\u95F2\u9C7C\u6388\u6743\u5730\u5740...`));let{authData:t,qrUrl:e,setStatus:r,closeServer:n}=await
|
|
30
|
-
`)),console.log(
|
|
22
|
+
`)),c}finally{s()}}async logout(){console.log(x.cyan(`
|
|
23
|
+
\u{1F6AA} \u6B63\u5728\u9000\u51FA\u767B\u5F55...`)),await this.storage.clearCredentials(),console.log(x.green(`\u2705 \u5DF2\u9000\u51FA\u767B\u5F55
|
|
24
|
+
`))}async status(){if(!await this.storage.isLoggedIn()){console.log(x.yellow(`\u26A0\uFE0F \u5C1A\u672A\u767B\u5F55\u6216\u51ED\u8BC1\u5DF2\u8FC7\u671F
|
|
25
|
+
`));return}let e=await this.storage.getCredentials(),r=e.userInfo,n=new Date(e.timestamp),s=Math.floor((Date.now()-e.timestamp)/(1e3*60*60*24));console.log(x.green(`\u2705 \u5DF2\u767B\u5F55
|
|
26
|
+
`)),await wo(r,n,s)}},qt=null;function L(){return qt||(qt=new ht),qt}import Q from"chalk";var xo=pt;async function Io(){return xo.get("mms/xianyu/auth/url")}async function So(o){let t=new URLSearchParams({state:o});return xo.get("mms/xianyu/auth/status",t)}async function yt(){let o=await Io(),t=await Nt(o.url,o.url);return{authData:o,...t}}async function it(o,t,e,r,n){return W(()=>So(o),{interval:e,timeout:t,condition:s=>s.status==="success"?(console.log(Q.green(`
|
|
27
|
+
\u2705 \u6388\u6743\u6210\u529F\uFF01\u5E97\u94FA: ${s.shopName} (${s.shopId})`)),n?.("success"),!0):s.status==="expired"?(console.log(Q.red(`
|
|
28
|
+
\u23F0 \u6388\u6743\u94FE\u63A5\u5DF2\u8FC7\u671F`)),n?.("expired"),!0):!1},r)}async function Gt(o){console.log(Q.cyan(`
|
|
29
|
+
\u{1F517} \u6B63\u5728\u83B7\u53D6\u95F2\u9C7C\u6388\u6743\u5730\u5740...`));let{authData:t,qrUrl:e,setStatus:r,closeServer:n}=await yt();console.log(Q.green(`\u2705 \u6388\u6743\u4E8C\u7EF4\u7801\u5DF2\u751F\u6210
|
|
30
|
+
`)),console.log(Q.cyan(` \u94FE\u63A5: ${e}`)),console.log(Q.gray(` \u6216\u590D\u5236\u94FE\u63A5\u6253\u5F00: ${t.url}`)),q(e),console.log(Q.yellow(`
|
|
31
31
|
\u23F3 \u7B49\u5F85\u6388\u6743...
|
|
32
|
-
`));let s=t.expireTime?Number.parseInt(t.expireTime,10):3e5,i=t.pollInterval?Number.parseInt(t.pollInterval,10):1e3;try{let a=await
|
|
33
|
-
\u25B2 ${o.message}`)),console.error(
|
|
34
|
-
`));else if(o instanceof
|
|
35
|
-
`));else{let t=o instanceof Error?o.message:String(o);console.error(E.red(`\u25B2 ${t}`))}process.exit(1)}function qt(o){console.log(JSON.stringify({success:!1,error:o})),process.exit(1)}function p(o){return async t=>{try{await o(t)}catch(e){if(t.json){let r=e instanceof Error?e.message:String(e),n=e instanceof P?e.status:void 0;console.log(JSON.stringify({success:!1,error:r,...n!=null&&{status:n}})),process.exit(1)}v(e)}}}function ht(o){return async(...t)=>{try{await o(...t)}catch(e){let r=e instanceof Error?e.message:String(e);qt(r)}}}var Le=new Set(["accessToken","refreshExpireIn"]);function Co(o){return o.map(t=>{let e={};for(let[r,n]of Object.entries(t))Le.has(r)||(e[r]=n);return e})}async function yt(o){let{qrInfo:t,qrUrl:e,setStatus:r,closeServer:n,waitArgs:s}=await o.generate();console.log(JSON.stringify(t,null,2)),B(e);try{let i=await o.waitResult(s,r);console.log(JSON.stringify(o.formatSuccess(i)))}catch(i){let a=i instanceof Error?i.message:String(i);console.log(JSON.stringify({success:!1,error:a})),process.exit(1)}finally{setTimeout(n,1e3)}}function Jt(){let o=new To("login");o.description("\u626B\u7801\u767B\u5F55 Round2AI \u8D26\u6237").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");let t=new To("poll").description("\u8F6E\u8BE2\u767B\u5F55\u72B6\u6001\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").requiredOption("--token <qrToken>","\u4E8C\u7EF4\u7801 token").option("--expire <ms>","\u8FC7\u671F\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09","300000").option("--interval <ms>","\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09","1000").action(ht(async e=>{let n=await R().waitForLogin(e.token,Number.parseInt(e.expire,10),Number.parseInt(e.interval,10));console.log(JSON.stringify({success:!0,...n}))}));return o.addCommand(t),o.action(async e=>{try{e.json?await yt({generate:async()=>{let r=R(),{qrData:n,qrUrl:s,setStatus:i,closeServer:a}=await r.generateQR(),l=Number.parseInt(n.expireTime,10),y=Number.parseInt(n.pollInterval,10);return{qrInfo:{qrToken:n.qrToken,expireTimeMs:l,pollIntervalMs:y,url:`https://m.puresnake.com/r2/auth/login?qrToken=${n.qrContent}&from=wechat`,qrUrl:s},qrUrl:s,setStatus:i,closeServer:a,waitArgs:{qrToken:n.qrToken,expireMs:l,intervalMs:y}}},waitResult:({qrToken:r,expireMs:n,intervalMs:s},i)=>R().waitForLogin(r,n,s,void 0,i,!0),formatSuccess:r=>({success:!0,userInfo:r.userInfo})}):await R().login()}catch(r){if(e.json){let n=r instanceof Error?r.message:String(r);console.log(JSON.stringify({success:!1,error:n})),process.exit(1)}v(r)}}),o}import{Command as Oe}from"commander";function Xt(){let o=new Oe("logout");return o.description("\u9000\u51FA\u767B\u5F55"),o.action(async()=>{try{await R().logout()}catch(t){v(t)}}),o}import{Command as De}from"commander";function _t(){let o=new De("status");return o.description("\u67E5\u770B\u767B\u5F55\u72B6\u6001"),o.action(async()=>{try{await R().status()}catch(t){v(t)}}),o}import{Command as bo}from"commander";function Qt(){let o=new bo("xianyu");o.description("\u95F2\u9C7C\u5E97\u94FA\u6388\u6743").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");let t=new bo("poll").description("\u8F6E\u8BE2\u95F2\u9C7C\u6388\u6743\u72B6\u6001\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").requiredOption("--state <state>","\u6388\u6743\u8F6E\u8BE2 token").option("--expire <ms>","\u8FC7\u671F\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09","300000").option("--interval <ms>","\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09","1000").action(ht(async e=>{let r=await rt(e.state,Number.parseInt(e.expire,10),Number.parseInt(e.interval,10));r.status==="success"?console.log(JSON.stringify({success:!0,shopId:r.shopId,shopName:r.shopName})):qt(`\u6388\u6743\u72B6\u6001: ${r.status}`)}));return o.addCommand(t),o.action(async e=>{try{e.json?await yt({generate:async()=>{let{authData:r,qrUrl:n,setStatus:s,closeServer:i}=await ft(),a=r.expireTime?Number.parseInt(r.expireTime,10):3e5,l=r.pollInterval?Number.parseInt(r.pollInterval,10):1e3;return{qrInfo:{state:r.state,expireTimeMs:a,pollIntervalMs:l,qrUrl:n},qrUrl:n,setStatus:s,closeServer:i,waitArgs:{state:r.state,expireMs:a,intervalMs:l}}},waitResult:async({state:r,expireMs:n,intervalMs:s},i)=>{let a=await rt(r,n,s,void 0,i);if(a.status!=="success")throw new Error(`\u6388\u6743\u72B6\u6001: ${a.status}`);return a},formatSuccess:r=>({success:!0,shopId:r.shopId,shopName:r.shopName})}):await Gt()}catch(r){if(e.json){let n=r instanceof Error?r.message:String(r);console.log(JSON.stringify({success:!1,error:n})),process.exit(1)}v(r)}}),o}import{Command as ir}from"commander";import{Command as Ue}from"commander";import L from"chalk";import{select as Ft,input as Ee,confirm as je}from"@inquirer/prompts";function X(o){let t=new URLSearchParams;for(let[e,r]of Object.entries(o))r!=null&&r!==""&&t.append(e,String(r));return t}var A=mt;async function Mt(o){return A.post("mms/goods/listing/up/xianyu",o)}async function Po(o){return A.get("mms/goods/listing/get",X({...o}))}async function Ao(o){return A.post("mms/goods/listing/down/xianyu",o)}async function ko(o){return A.post("mms/goods/listing/update/xyPrice",o)}async function vo(o){return A.get("mms/goods/listing/list",o?X({...o}):void 0)}async function wt(){return await A.get("mms/user/shop/list")??[]}async function xt(){return await A.get("mms/user/stock/list")??[]}async function It(o){let t=o?X({...o}):void 0;return A.get("mms/seller/goods/select/list",t)}async function No(o){return A.post("mms/goods/listing/hang/up/xianyu",o)}async function Ro(o=16){return await A.get("platform/xy/cat",X({spBizType:o}))??[]}async function Lo(o){return await A.get("platform/xy/props",X({channelCatId:o}))??[]}async function Oo(o,t,e){return await A.get("platform/xy/props/value",X({channelCatId:o,propId:t,key:e}))??[]}var $e=2e3,Be=1e4;function Ge(o){let t=o.status?.toLowerCase()??"";return t===""||t==="init"||t==="pending"||t==="processing"}async function Do(o,t,e,r){r||process.stdout.write(L.cyan("\u23F3 \u6B63\u5728\u67E5\u8BE2\u4E0A\u67B6\u8FDB\u5EA6..."));let n=await F(()=>Po({stockGoodsId:o,shopId:t,platform:e}),{interval:$e,timeout:Be,condition:s=>!Ge(s)});return r||process.stdout.write("\r"+" ".repeat(30)+"\r"),n}function Uo(){let o=new Ue("up");return o.description("\u4E0A\u67B6\u5546\u54C1\u5230\u95F2\u9C7C"),o.option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1ID\uFF08\u4ECE goods list \u83B7\u53D6\uFF09").option("--shop-id <id>","\u5E97\u94FAID\uFF08\u4ECE goods shops \u83B7\u53D6\uFF09").option("--price <amount>","\u4E0A\u67B6\u4EF7\u683C").option("-p, --platform <platform>","\u5E73\u53F0","xianyu").option("--json","\u8F93\u51FA JSON\uFF08Agent \u7528\uFF09").action(p(async t=>{if(t.json&&!(t.stockGoodsId&&t.shopId&&t.price)&&(console.log(JSON.stringify({success:!1,error:"Agent \u6A21\u5F0F\u9700\u8981 --stock-goods-id, --shop-id, --price"})),process.exit(1)),t.stockGoodsId&&t.shopId&&t.price){let d=Number(t.stockGoodsId),k=t.shopId,Pt=Number(t.price),Q=t.platform,ie=await Mt({stockGoodsId:d,shopId:k,price:Pt,platform:Q}),At=await Do(d,k,Q,t.json);if(t.json)console.log(JSON.stringify({success:!0,data:{submit:ie,listing:At}},null,2));else{let ae=At.status?.toLowerCase()!=="failed";console.log(ae?L.green("\u2713 \u4E0A\u67B6\u6210\u529F"):L.red("\u2717 \u4E0A\u67B6\u5931\u8D25")),console.log(JSON.stringify(At,null,2))}return}let e=await wt();if(e.length===0){console.log(L.yellow("\u6CA1\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF0C\u8BF7\u5148\u8FD0\u884C r2-cli auth xianyu \u6388\u6743"));return}let r=await Ft({message:"\u9009\u62E9\u5E97\u94FA",choices:e.map(d=>({name:`${d.shopName} (${d.platform})`,value:d.shopId}))}),n=await xt();if(n.length===0){console.log(L.yellow("\u6CA1\u6709\u53EF\u7528\u7684\u4ED3\u5E93"));return}let s=await Ft({message:"\u9009\u62E9\u4ED3\u5E93",choices:n.map(d=>({name:d.stockName,value:d.stockId}))}),i=await It({stockId:s,size:100});if(!i.items?.length){console.log(L.yellow("\u8BE5\u4ED3\u5E93\u6CA1\u6709\u53EF\u9009\u7684\u5546\u54C1"));return}let a=await Ft({message:"\u9009\u62E9\u5546\u54C1",choices:i.items.map(d=>({name:`${d.goodsName} ${d.size?`| ${d.size}`:""} | \xA5${d.salePrice}`,value:d.stockGoodsId}))}),l=await Ee({message:"\u8F93\u5165\u4E0A\u67B6\u4EF7\u683C",default:i.items.find(d=>d.stockGoodsId===a)?.salePrice?.toString()??"",validate:d=>Number(d)>0?!0:"\u4EF7\u683C\u5FC5\u987B\u4E3A\u6B63\u6570"});if(!await je({message:`\u786E\u8BA4\u4E0A\u67B6\uFF1F\u4EF7\u683C \xA5${l}`,default:!0})){console.log(L.gray("\u5DF2\u53D6\u6D88"));return}let m=Number(a);await Mt({stockGoodsId:m,shopId:r,price:Number(l),platform:"xianyu"}),console.log(L.green("\u2713 \u4E0A\u67B6\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u67E5\u8BE2\u8FDB\u5EA6..."));let b=await Do(m,r,"xianyu"),_=b.status?.toLowerCase()!=="failed";console.log(_?L.green("\u2713 \u4E0A\u67B6\u6210\u529F"):L.red("\u2717 \u4E0A\u67B6\u5931\u8D25")),console.log(JSON.stringify(b,null,2))})),o}import{Command as Qe}from"commander";import Bo from"chalk";function Go(){let o=new Qe("shops");return o.description("\u67E5\u770B\u6240\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF08\u8DE8\u5E73\u53F0\uFF09"),o.option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(p(async t=>{let e=await wt();if(t.json){console.log(JSON.stringify(Co(e),null,2));return}if(!e.length){console.log(Bo.yellow("\u672A\u627E\u5230\u5DF2\u6388\u6743\u7684\u5E97\u94FA")),console.log(Bo.gray(" \u63D0\u793A: \u8BF7\u5148\u5728\u7B2C\u4E8C\u56DE\u5408 APP \u4E2D\u6388\u6743\u5E97\u94FA"));return}let{ShopsTable:r}=await Promise.resolve().then(()=>($o(),jo)),{renderComponent:n}=await Promise.resolve().then(()=>(et(),gt));n(r,{shops:e,platform:"all"})})),o}import{Command as We}from"commander";import He from"chalk";function Xo(){let o=new We("stocks");return o.description("\u67E5\u770B\u6240\u6709\u4ED3\u5E93"),o.option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(p(async t=>{let e=await xt();if(t.json){console.log(JSON.stringify(e,null,2));return}if(!e.length){console.log(He.yellow("\u672A\u627E\u5230\u4ED3\u5E93\u4FE1\u606F"));return}let{StocksTable:r}=await Promise.resolve().then(()=>(Jo(),qo)),{renderComponent:n}=await Promise.resolve().then(()=>(et(),gt));n(r,{stocks:e})})),o}import{Command as Ve}from"commander";import Z from"chalk";function _o(){let o=new Ve("list");return o.description("\u67E5\u770B\u4ED3\u5E93\u4E2D\u7684\u9009\u54C1\u5546\u54C1"),o.option("--stock-id <id>","\u4ED3\u5E93 ID\uFF08\u4ECE goods stocks \u83B7\u53D6\uFF09").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--page <n>","\u9875\u7801","1").option("--size <n>","\u6BCF\u9875\u6570\u91CF\uFF08\u6700\u5927 50\uFF09","20").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(p(async t=>{let r=await It({stockId:t.stockId||void 0,stockGoodsId:t.stockGoodsId||void 0,page:Number(t.page)||1,size:Math.min(Number(t.size)||20,50)})??{items:[],total:0};if(t.json){r.items?.length?console.log(JSON.stringify(r,null,2)):console.log(JSON.stringify({...r,hint:"\u9009\u54C1\u5546\u54C1\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u5728\u540E\u53F0\u751F\u6210\u9009\u54C1\u8868\u6570\u636E\u540E\u518D\u8BD5"},null,2));return}if(!r.items?.length){console.log(Z.yellow("\u6682\u65E0\u9009\u54C1\u5546\u54C1\uFF0C\u8BF7\u5148\u7ED1\u5B9A\u4ED3\u5E93\u6216\u5728\u540E\u53F0\u751F\u6210\u9009\u54C1\u8868\u6570\u636E"));return}console.log(Z.cyan(`
|
|
32
|
+
`));let s=t.expireTime?Number.parseInt(t.expireTime,10):3e5,i=t.pollInterval?Number.parseInt(t.pollInterval,10):1e3;try{let a=await it(t.state,s,i,o,r);if(a.status==="success")return a;throw new C("\u95F2\u9C7C\u6388\u6743\u5931\u8D25: "+(a.status==="expired"?"\u94FE\u63A5\u5DF2\u8FC7\u671F":"\u672A\u77E5\u72B6\u6001"))}finally{n()}}import N from"chalk";function X(o){if(o instanceof C)console.error(N.red(`
|
|
33
|
+
\u25B2 ${o.message}`)),console.error(N.gray(`\u2192 \u8BF7\u5148\u8FD0\u884C: r2-cli auth login
|
|
34
|
+
`));else if(o instanceof b)console.error(N.red(`\u25B2 \u64CD\u4F5C\u5931\u8D25: ${o.message}`)),o.status&&console.error(N.gray(` \u72B6\u6001\u7801: ${o.status}`));else if(o instanceof B)console.error(N.red(`\u25B2 \u914D\u7F6E\u6587\u4EF6\u5F02\u5E38: ${o.message}`)),o.path&&console.error(N.gray(` \u8DEF\u5F84: ${o.path}`)),console.error(N.gray(`\u2192 \u8BF7\u5C1D\u8BD5\u91CD\u65B0\u767B\u5F55: r2-cli auth login
|
|
35
|
+
`));else{let t=o instanceof Error?o.message:String(o);console.error(N.red(`\u25B2 ${t}`))}process.exit(1)}function Jt(o){console.log(JSON.stringify({success:!1,error:o})),process.exit(1)}function m(o){return async t=>{try{await o(t)}catch(e){if(t.json){let r=e instanceof Error?e.message:String(e),n=e instanceof b?e.status:void 0;console.log(JSON.stringify({success:!1,error:r,...n!=null&&{status:n}})),process.exit(1)}X(e)}}}function P(o,t){o.json&&(console.log(JSON.stringify({success:!1,error:t})),process.exit(1)),console.log(N.yellow(t))}function j(o,t,e){o.json?console.log(JSON.stringify({success:!0,data:t},null,2)):(e&&console.log(N.green(e)),console.log(JSON.stringify(t,null,2)))}function wt(o){return async(...t)=>{try{await o(...t)}catch(e){let r=e instanceof Error?e.message:String(e);Jt(r)}}}var je=new Set(["accessToken","refreshExpireIn"]);function Co(o){return o.map(t=>{let e={};for(let[r,n]of Object.entries(t))je.has(r)||(e[r]=n);return e})}async function xt(o){let{qrInfo:t,qrUrl:e,setStatus:r,closeServer:n,waitArgs:s}=await o.generate();console.log(JSON.stringify(t,null,2)),q(e);try{let i=await o.waitResult(s,r);console.log(JSON.stringify(o.formatSuccess(i)))}catch(i){let a=i instanceof Error?i.message:String(i);console.log(JSON.stringify({success:!1,error:a})),process.exit(1)}finally{setTimeout(n,1e3)}}function Qt(){let o=new To("login");o.description("\u626B\u7801\u767B\u5F55 Round2AI \u8D26\u6237").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");let t=new To("poll").description("\u8F6E\u8BE2\u767B\u5F55\u72B6\u6001\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").requiredOption("--token <qrToken>","\u4E8C\u7EF4\u7801 token").option("--expire <ms>","\u8FC7\u671F\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09","300000").option("--interval <ms>","\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09","1000").action(wt(async e=>{let n=await L().waitForLogin(e.token,Number.parseInt(e.expire,10),Number.parseInt(e.interval,10));console.log(JSON.stringify({success:!0,...n}))}));return o.addCommand(t),o.action(m(async e=>{e.json?await xt({generate:async()=>{let r=L(),{qrData:n,qrUrl:s,setStatus:i,closeServer:a}=await r.generateQR(),c=Number.parseInt(n.expireTime,10),h=Number.parseInt(n.pollInterval,10);return{qrInfo:{qrToken:n.qrToken,expireTimeMs:c,pollIntervalMs:h,qrUrl:s},qrUrl:s,setStatus:i,closeServer:a,waitArgs:{qrToken:n.qrToken,expireMs:c,intervalMs:h}}},waitResult:({qrToken:r,expireMs:n,intervalMs:s},i)=>L().waitForLogin(r,n,s,void 0,i,!0),formatSuccess:r=>({success:!0,userInfo:r.userInfo})}):await L().login()})),o}import{Command as $e}from"commander";function Xt(){let o=new $e("logout");return o.description("\u9000\u51FA\u767B\u5F55"),o.action(async()=>{try{await L().logout()}catch(t){X(t)}}),o}import{Command as Be}from"commander";function _t(){let o=new Be("status");return o.description("\u67E5\u770B\u767B\u5F55\u72B6\u6001"),o.action(async()=>{try{await L().status()}catch(t){X(t)}}),o}import{Command as bo}from"commander";function Mt(){let o=new bo("xianyu");o.description("\u95F2\u9C7C\u5E97\u94FA\u6388\u6743").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");let t=new bo("poll").description("\u8F6E\u8BE2\u95F2\u9C7C\u6388\u6743\u72B6\u6001\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").requiredOption("--state <state>","\u6388\u6743\u8F6E\u8BE2 token").option("--expire <ms>","\u8FC7\u671F\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09","300000").option("--interval <ms>","\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09","1000").action(wt(async e=>{let r=await it(e.state,Number.parseInt(e.expire,10),Number.parseInt(e.interval,10));r.status==="success"?console.log(JSON.stringify({success:!0,shopId:r.shopId,shopName:r.shopName})):Jt(`\u6388\u6743\u72B6\u6001: ${r.status}`)}));return o.addCommand(t),o.action(m(async e=>{e.json?await xt({generate:async()=>{let{authData:r,qrUrl:n,setStatus:s,closeServer:i}=await yt(),a=r.expireTime?Number.parseInt(r.expireTime,10):3e5,c=r.pollInterval?Number.parseInt(r.pollInterval,10):1e3;return{qrInfo:{state:r.state,expireTimeMs:a,pollIntervalMs:c,qrUrl:n},qrUrl:n,setStatus:s,closeServer:i,waitArgs:{state:r.state,expireMs:a,intervalMs:c}}},waitResult:async({state:r,expireMs:n,intervalMs:s},i)=>{let a=await it(r,n,s,void 0,i);if(a.status!=="success")throw new Error(`\u6388\u6743\u72B6\u6001: ${a.status}`);return a},formatSuccess:r=>({success:!0,shopId:r.shopId,shopName:r.shopName})}):await Gt()})),o}import{Command as xr}from"commander";import{Command as Xe}from"commander";import D from"chalk";import{select as Ft,input as _e,confirm as Me}from"@inquirer/prompts";import{basename as Qe}from"node:path";function _(o){let t=new URLSearchParams;for(let[e,r]of Object.entries(o))r!=null&&r!==""&&t.append(e,String(r));return t}import{statSync as qe,readFileSync as Po}from"node:fs";import Ge from"sharp";var Je=2*1024*1024;async function Ao(o,t=Je){let{size:e}=qe(o);if(e<=t)return Po(o);let r=Ge(o);await r.metadata();let n=[100,90,80,70,60,50,40,30],s=null;for(let i of n){let a=await r.jpeg({quality:i,mozjpeg:!0}).toBuffer();if(a.length<=t)return a;s=a}return s??Po(o)}var T=pt;async function zt(o){return T.post("mms/goods/listing/up/xianyu",o)}async function vo(o){return T.get("mms/goods/listing/get",_({...o}))}async function ko(o){return T.post("mms/goods/listing/down/xianyu",o)}async function Ro(o){return T.post("mms/goods/listing/update/xyPrice",o)}async function Lo(o){return T.post("mms/goods/listing/update/goodsInfo",o)}async function No(o){return T.get("mms/goods/listing/list",o?_({...o}):void 0)}async function It(){return await T.get("mms/user/shop/list")??[]}async function St(){return await T.get("mms/user/stock/list")??[]}async function Ct(o){let t=o?_({...o}):void 0;return T.get("mms/seller/goods/select/list",t)}async function Do(o,t){let e=async(i,a=1)=>{for(let c=0;c<=a;c++)try{let h=await Ao(i),u=Qe(i),w=new FormData;return w.append("file",new Blob([new Uint8Array(h)]),u),await T.upload(`platform/xy/media/upload?shopId=${encodeURIComponent(o)}`,w)}catch(h){if(c<a){await new Promise(u=>setTimeout(u,1e3));continue}throw h}throw new Error("unreachable")},r=await Promise.allSettled(t.map(e)),n=[],s=[];for(let i=0;i<r.length;i++){let a=r[i];if(a.status==="fulfilled")n.push(a.value);else{let c=a.reason;s.push({file:t[i],error:c instanceof Error?c.message:`${c}`})}}return{images:n,failed:s}}async function Oo(o){return T.post("mms/goods/listing/hang/up/xianyu",o)}async function Uo(o=16){return await T.get("platform/xy/cat",_({spBizType:o}))??[]}async function Eo(o){return await T.get("platform/xy/props",_({channelCatId:o}))??[]}async function jo(o,t,e){return await T.get("platform/xy/props/value",_({channelCatId:o,propId:t,key:e}))??[]}var ze=2e3,Fe=1e4;function We(o){let t=o.status?.toLowerCase()??"";return t===""||t==="init"||t==="pending"||t==="processing"}async function $o(o,t,e,r){r||process.stdout.write(D.cyan("\u23F3 \u6B63\u5728\u67E5\u8BE2\u4E0A\u67B6\u8FDB\u5EA6..."));let n=await W(()=>vo({stockGoodsId:o,shopId:t,platform:e}),{interval:ze,timeout:Fe,condition:s=>!We(s)});return r||process.stdout.write("\r"+" ".repeat(30)+"\r"),n}function Bo(){let o=new Xe("up");return o.description("\u4E0A\u67B6\u5546\u54C1\u5230\u95F2\u9C7C"),o.option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1ID\uFF08\u4ECE goods list \u83B7\u53D6\uFF09").option("--shop-id <id>","\u5E97\u94FAID\uFF08\u4ECE goods shops \u83B7\u53D6\uFF09").option("--price <amount>","\u4E0A\u67B6\u4EF7\u683C").option("-p, --platform <platform>","\u5E73\u53F0","xianyu").option("--json","\u8F93\u51FA JSON\uFF08Agent \u7528\uFF09").action(m(async t=>{if(t.json&&!(t.stockGoodsId&&t.shopId&&t.price)){P(t,"Agent \u6A21\u5F0F\u9700\u8981 --stock-goods-id, --shop-id, --price");return}if(t.stockGoodsId&&t.shopId&&t.price){let d=Number(t.stockGoodsId),k=t.shopId,At=Number(t.price),z=t.platform,ue=await zt({stockGoodsId:d,shopId:k,price:At,platform:z}),vt=await $o(d,k,z,t.json);if(t.json)console.log(JSON.stringify({success:!0,data:{submit:ue,listing:vt}},null,2));else{let me=vt.status?.toLowerCase()!=="failed";console.log(me?D.green("\u2713 \u4E0A\u67B6\u6210\u529F"):D.red("\u2717 \u4E0A\u67B6\u5931\u8D25")),console.log(JSON.stringify(vt,null,2))}return}let e=await It();if(e.length===0){console.log(D.yellow("\u6CA1\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF0C\u8BF7\u5148\u8FD0\u884C r2-cli auth xianyu \u6388\u6743"));return}let r=await Ft({message:"\u9009\u62E9\u5E97\u94FA",choices:e.map(d=>({name:`${d.shopName} (${d.platform})`,value:d.shopId}))}),n=await St();if(n.length===0){console.log(D.yellow("\u6CA1\u6709\u53EF\u7528\u7684\u4ED3\u5E93"));return}let s=await Ft({message:"\u9009\u62E9\u4ED3\u5E93",choices:n.map(d=>({name:d.stockName,value:d.stockId}))}),i=await Ct({stockId:s,size:100});if(!i.items?.length){console.log(D.yellow("\u8BE5\u4ED3\u5E93\u6CA1\u6709\u53EF\u9009\u7684\u5546\u54C1"));return}let a=await Ft({message:"\u9009\u62E9\u5546\u54C1",choices:i.items.map(d=>({name:`${d.goodsName} ${d.size?`| ${d.size}`:""} | \xA5${d.salePrice}`,value:d.stockGoodsId}))}),c=await _e({message:"\u8F93\u5165\u4E0A\u67B6\u4EF7\u683C",default:i.items.find(d=>d.stockGoodsId===a)?.salePrice?.toString()??"",validate:d=>Number(d)>0?!0:"\u4EF7\u683C\u5FC5\u987B\u4E3A\u6B63\u6570"});if(!await Me({message:`\u786E\u8BA4\u4E0A\u67B6\uFF1F\u4EF7\u683C \xA5${c}`,default:!0})){console.log(D.gray("\u5DF2\u53D6\u6D88"));return}let u=Number(a);await zt({stockGoodsId:u,shopId:r,price:Number(c),platform:"xianyu"}),console.log(D.green("\u2713 \u4E0A\u67B6\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u67E5\u8BE2\u8FDB\u5EA6..."));let w=await $o(u,r,"xianyu"),M=w.status?.toLowerCase()!=="failed";console.log(M?D.green("\u2713 \u4E0A\u67B6\u6210\u529F"):D.red("\u2717 \u4E0A\u67B6\u5931\u8D25")),console.log(JSON.stringify(w,null,2))})),o}import{Command as Ze}from"commander";import Qo from"chalk";function Xo(){let o=new Ze("shops");return o.description("\u67E5\u770B\u6240\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF08\u8DE8\u5E73\u53F0\uFF09"),o.option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{let e=await It();if(t.json){console.log(JSON.stringify(Co(e),null,2));return}if(!e.length){console.log(Qo.yellow("\u672A\u627E\u5230\u5DF2\u6388\u6743\u7684\u5E97\u94FA")),console.log(Qo.gray(" \u63D0\u793A: \u8BF7\u5148\u5728\u7B2C\u4E8C\u56DE\u5408 APP \u4E2D\u6388\u6743\u5E97\u94FA"));return}let{ShopsTable:r}=await Promise.resolve().then(()=>(Jo(),Go)),{renderComponent:n}=await Promise.resolve().then(()=>(st(),ft));n(r,{shops:e,platform:"all"})})),o}import{Command as rr}from"commander";import nr from"chalk";function zo(){let o=new rr("stocks");return o.description("\u67E5\u770B\u6240\u6709\u4ED3\u5E93"),o.option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{let e=await St();if(t.json){console.log(JSON.stringify(e,null,2));return}if(!e.length){console.log(nr.yellow("\u672A\u627E\u5230\u4ED3\u5E93\u4FE1\u606F"));return}let{StocksTable:r}=await Promise.resolve().then(()=>(Mo(),_o)),{renderComponent:n}=await Promise.resolve().then(()=>(st(),ft));n(r,{stocks:e})})),o}import{Command as sr}from"commander";import ot from"chalk";function Fo(){let o=new sr("list");return o.description("\u67E5\u770B\u4ED3\u5E93\u4E2D\u7684\u9009\u54C1\u5546\u54C1"),o.option("--stock-id <id>","\u4ED3\u5E93 ID\uFF08\u4ECE goods stocks \u83B7\u53D6\uFF09").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--page <n>","\u9875\u7801","1").option("--size <n>","\u6BCF\u9875\u6570\u91CF\uFF08\u6700\u5927 50\uFF09","20").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{let r=await Ct({stockId:t.stockId||void 0,stockGoodsId:t.stockGoodsId||void 0,page:Number(t.page)||1,size:Math.min(Number(t.size)||20,50)})??{items:[],total:0};if(t.json){r.items?.length?console.log(JSON.stringify(r,null,2)):console.log(JSON.stringify({...r,hint:"\u9009\u54C1\u5546\u54C1\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u5728\u540E\u53F0\u751F\u6210\u9009\u54C1\u8868\u6570\u636E\u540E\u518D\u8BD5"},null,2));return}if(!r.items?.length){console.log(ot.yellow("\u6682\u65E0\u9009\u54C1\u5546\u54C1\uFF0C\u8BF7\u5148\u7ED1\u5B9A\u4ED3\u5E93\u6216\u5728\u540E\u53F0\u751F\u6210\u9009\u54C1\u8868\u6570\u636E"));return}console.log(ot.cyan(`
|
|
36
36
|
\u9009\u54C1\u5546\u54C1\uFF08\u5171 ${r.total} \u4EF6\uFF0C\u7B2C ${r.page} \u9875\uFF09
|
|
37
|
-
`));for(let n of r.items)console.log(` ${Z.bold(n.goodsName)} ${n.size?Z.gray(`| ${n.size}`):""}`),console.log(` \u54C1\u724C: ${n.brand} \u5EFA\u8BAE\u552E\u4EF7: \xA5${n.salePrice} stockGoodsId: ${Z.green(n.stockGoodsId)}`),console.log(Z.gray(` \u5206\u7C7B: ${n.cate1Name} > ${n.cate2Name} > ${n.cate3Name}`)),console.log()})),o}import{Command as or}from"commander";import er from"chalk";et();import{Box as g,Text as h}from"ink";import{jsx as c,jsxs as j}from"react/jsx-runtime";var Ke={init:{label:"\u5F85\u4E0A\u67B6",color:"yellow"},up:{label:"\u5DF2\u4E0A\u67B6",color:"green"},down:{label:"\u5DF2\u4E0B\u67B6",color:"gray"},fail:{label:"\u5931\u8D25",color:"red"},sold:{label:"\u5DF2\u552E\u51FA",color:"blue"}},to=4,oo=8,St=12,eo=10,ro=6,no=8;function Qo(o,t){return o.length>t?o.slice(0,t-1)+"\u2026":o}function Mo(o){if(!o)return"-";let t=new Date(o),e=r=>String(r).padStart(2,"0");return`${e(t.getMonth()+1)}/${e(t.getDate())} ${e(t.getHours())}:${e(t.getMinutes())}`}function Ye({fillWidth:o}){return j(g,{flexDirection:"row",children:[c(g,{width:to,children:c(h,{bold:!0,color:"white",children:"ID"})}),c(g,{width:oo,children:c(h,{bold:!0,color:"white",children:"\u72B6\u6001"})}),c(g,{width:St,children:c(h,{bold:!0,color:"white",children:"\u54C1\u724C"})}),c(g,{width:o,children:c(h,{bold:!0,color:"white",children:"\u5546\u54C1\u540D\u79F0"})}),c(g,{width:eo,children:c(h,{bold:!0,color:"white",children:"\u4EF7\u683C"})}),c(g,{width:ro,children:c(h,{bold:!0,color:"white",children:"\u89C4\u683C"})}),c(g,{width:no,children:c(h,{bold:!0,color:"white",children:"\u5E93\u5B58ID"})})]})}function Ze({item:o}){return c(g,{flexDirection:"column",children:c(h,{color:"gray",children:` shopId: ${o.shopId} thirdItemNo: ${o.thirdItemNo||"-"} outItemNo: ${o.outItemNo||"-"} \u8D27\u53F7: ${o.goodsNo||"-"} ${o.type||"-"} ${o.platform} \u521B\u5EFA: ${Mo(o.gmtCreate)} \u4FEE\u6539: ${Mo(o.gmtModified)}`})})}function tr({item:o,fillWidth:t}){let e=Ke[o.status]??{label:o.status,color:"white"};return j(g,{flexDirection:"column",children:[j(g,{flexDirection:"row",children:[c(g,{width:to,children:c(h,{color:"gray",children:o.id})}),c(g,{width:oo,children:c(h,{color:e.color,children:e.label})}),c(g,{width:St,children:c(h,{color:"cyan",children:Qo(o.brandName||"-",St-1)})}),c(g,{width:t,children:c(h,{children:Qo(o.goodsName,t-1)})}),c(g,{width:eo,children:j(h,{color:"yellow",children:["\xA5",o.price]})}),c(g,{width:ro,children:c(h,{color:"gray",children:o.spec||"-"})}),c(g,{width:no,children:c(h,{color:"gray",children:o.stockGoodsId})})]}),c(Ze,{item:o})]})}function Fo({items:o,total:t}){let e=process.stdout.columns||80,r=4,n=to+oo+St+eo+ro+no,s=Math.max(e-r-n,20),i=n+s;return j(g,{flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"gray",paddingX:1,children:[j(g,{flexDirection:"row",children:[c(h,{bold:!0,color:"cyan",children:"\u4E0A\u67B6\u5217\u8868"}),j(h,{color:"gray",children:[" \xB7 \u5171 ",t," \u6761"]})]}),j(g,{flexDirection:"column",marginTop:1,children:[c(Ye,{fillWidth:s}),c(h,{color:"gray",children:"\u2500".repeat(i)}),o.map(a=>c(tr,{item:a,fillWidth:s},a.id))]})]})}function zo(){let o=new or("listing");return o.description("\u67E5\u8BE2\u4E0A\u67B6\u5546\u54C1\u5217\u8868"),o.option("--id <id>","\u4E0A\u67B6\u8BB0\u5F55 ID").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--shop-id <id>","\u5E97\u94FA ID").option("--stock-id <id>","\u4ED3\u5E93 ID").option("-s, --status <status>","\u72B6\u6001\u8FC7\u6EE4\uFF08init/up/down/fail/sold\uFF09").option("-p, --platform <platform>","\u5E73\u53F0","xianyu").option("--page <n>","\u9875\u7801","1").option("--size <n>","\u6BCF\u9875\u6570\u91CF\uFF08\u6700\u5927 50\uFF09","20").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(p(async t=>{let r=await vo({id:t.id,stockGoodsId:t.stockGoodsId?Number(t.stockGoodsId):void 0,shopId:t.shopId,stockId:t.stockId,status:t.status,platform:t.platform,page:Number(t.page)||1,size:Math.min(Number(t.size)||20,50)})??{items:[],total:0};if(t.json){r.items?.length?console.log(JSON.stringify(r,null,2)):console.log(JSON.stringify({...r,hint:"\u6682\u65E0\u4E0A\u67B6\u8BB0\u5F55"},null,2));return}if(!r.items?.length){console.log(er.yellow("\u6682\u65E0\u4E0A\u67B6\u8BB0\u5F55"));return}$t(Fo,{items:r.items,total:r.total})})),o}import{Command as rr}from"commander";import so from"chalk";function Wo(){let o=new rr("down");return o.description("\u4E0B\u67B6\u95F2\u9C7C\u5546\u54C1"),o.option("--id <id>","\u4E0A\u67B6\u8BB0\u5F55 ID").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--shop-id <id>","\u5E97\u94FA ID").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(p(async t=>{if(!t.id&&!(t.stockGoodsId&&t.shopId)){t.json&&(console.log(JSON.stringify({success:!1,error:"\u8BF7\u6307\u5B9A\u4E0B\u67B6\u6761\u4EF6\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>"})),process.exit(1)),console.log(so.yellow("\u8BF7\u6307\u5B9A\u4E0B\u67B6\u6761\u4EF6\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>"));return}let e={};t.id&&(e.id=t.id),t.stockGoodsId&&(e.stockGoodsId=Number(t.stockGoodsId)),t.shopId&&(e.shopId=t.shopId),t.json||console.log(so.cyan("\u{1F4E6} \u6B63\u5728\u4E0B\u67B6\u5546\u54C1..."));let r=await Ao(e);t.json?console.log(JSON.stringify({success:!0,data:r},null,2)):(console.log(so.green("\u2705 \u4E0B\u67B6\u6210\u529F")),console.log(JSON.stringify(r,null,2)))})),o}import{Command as nr}from"commander";import Ct from"chalk";function Ho(){let o=new nr("price");return o.description("\u4FEE\u6539\u95F2\u9C7C\u4E0A\u67B6\u5546\u54C1\u4EF7\u683C"),o.option("--id <id>","\u4E0A\u67B6\u8BB0\u5F55 ID").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--shop-id <id>","\u5E97\u94FA ID").option("--price <amount>","\u65B0\u4EF7\u683C\uFF08\u5FC5\u586B\uFF09").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(p(async t=>{if(!t.price){t.json&&(console.log(JSON.stringify({success:!1,error:"--price <amount> \u4E3A\u5FC5\u586B\u53C2\u6570"})),process.exit(1)),console.log(Ct.yellow("--price <amount> \u4E3A\u5FC5\u586B\u53C2\u6570"));return}if(!t.id&&!(t.stockGoodsId&&t.shopId)){t.json&&(console.log(JSON.stringify({success:!1,error:"\u8BF7\u6307\u5B9A\u5546\u54C1\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>"})),process.exit(1)),console.log(Ct.yellow("\u8BF7\u6307\u5B9A\u5546\u54C1\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>"));return}let e={price:Number(t.price)};t.id&&(e.id=t.id),t.stockGoodsId&&(e.stockGoodsId=Number(t.stockGoodsId)),t.shopId&&(e.shopId=t.shopId),t.json||console.log(Ct.cyan(`\u{1F4B0} \u6B63\u5728\u4FEE\u6539\u4EF7\u683C\u4E3A ${t.price}...`));let r=await ko(e);t.json?console.log(JSON.stringify({success:!0,data:r},null,2)):(console.log(Ct.green("\u2705 \u4EF7\u683C\u4FEE\u6539\u6210\u529F")),console.log(JSON.stringify(r,null,2)))})),o}import{Command as Fs}from"commander";import Ws from"chalk";import{Command as nt}from"commander";import T from"chalk";var sr={100:"\u5168\u65B0",[-1]:"\u51C6\u65B0",99:"99\u65B0",95:"95\u65B0",90:"9\u65B0"};function Vo(){let o=new nt("hang-up");return o.description("\u95F2\u9C7C\u6302\u552E\u4E0A\u67B6\uFF08\u5B8C\u6574\u5546\u54C1\u4FE1\u606F\u6A21\u5F0F\uFF09"),o.addCommand(new nt("categories").description("\u83B7\u53D6\u95F2\u9C7C\u7C7B\u76EE\u5217\u8868\uFF08\u5927\u5206\u7C7B \u2192 \u5C0F\u5206\u7C7B\uFF09").option("--sp-biz-type <n>","\u4E1A\u52A1\u5206\u7C7B\uFF0C16=\u5962\u54C1","16").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(p(async t=>{let e=await Ro(Number(t.spBizType));if(t.json){console.log(JSON.stringify(e,null,2));return}let r=new Map;for(let n of e){let s=String(n.catId);r.has(s)||r.set(s,{catName:n.catName,children:[]}),r.get(s).children.push({channel:n.channel,channelCatId:n.channelCatId})}for(let[n,s]of r){console.log(T.bold(`${s.catName} (catId: ${T.green(n)})`));for(let i of s.children)console.log(` ${i.channel} (channelCatId: ${T.green(i.channelCatId)})`)}}))),o.addCommand(new nt("props").description("\u83B7\u53D6\u6307\u5B9A\u7C7B\u76EE\u4E0B\u7684\u5C5E\u6027\u5217\u8868\uFF08\u542B\u53EF\u9009\u503C\uFF09").requiredOption("--channel-cat-id <id>","\u5C0F\u5206\u7C7B ID\uFF08\u4ECE categories \u83B7\u53D6\uFF09").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(p(async t=>{let e=await Lo(t.channelCatId);if(t.json){console.log(JSON.stringify(e,null,2));return}for(let r of e)if(console.log(T.bold(`
|
|
38
|
-
${r.propName} (propId: ${r.propId})`)),r.propsValues?.length)for(let n of r.propsValues)console.log(` ${n.valueName} (valueId: ${n.valueId})`);else console.log(
|
|
39
|
-
\
|
|
40
|
-
|
|
41
|
-
\
|
|
42
|
-
\
|
|
43
|
-
\
|
|
44
|
-
\
|
|
45
|
-
|
|
37
|
+
`));for(let n of r.items)console.log(` ${ot.bold(n.goodsName)} ${n.size?ot.gray(`| ${n.size}`):""}`),console.log(` \u54C1\u724C: ${n.brand} \u5EFA\u8BAE\u552E\u4EF7: \xA5${n.salePrice} stockGoodsId: ${ot.green(n.stockGoodsId)}`),console.log(ot.gray(` \u5206\u7C7B: ${n.cate1Name} > ${n.cate2Name} > ${n.cate3Name}`)),console.log()})),o}import{Command as dr}from"commander";import ur from"chalk";st();import{Box as p,Text as y}from"ink";import{jsx as l,jsxs as $}from"react/jsx-runtime";var ir={init:{label:"\u5F85\u4E0A\u67B6",color:"yellow"},up:{label:"\u5DF2\u4E0A\u67B6",color:"green"},down:{label:"\u5DF2\u4E0B\u67B6",color:"gray"},fail:{label:"\u5931\u8D25",color:"red"},sold:{label:"\u5DF2\u552E\u51FA",color:"blue"}},oo=4,eo=8,Tt=12,ro=10,no=6,so=8;function Wo(o,t){return o.length>t?o.slice(0,t-1)+"\u2026":o}function Ho(o){if(!o)return"-";let t=new Date(o),e=r=>String(r).padStart(2,"0");return`${e(t.getMonth()+1)}/${e(t.getDate())} ${e(t.getHours())}:${e(t.getMinutes())}`}function ar({fillWidth:o}){return $(p,{flexDirection:"row",children:[l(p,{width:oo,children:l(y,{bold:!0,color:"white",children:"ID"})}),l(p,{width:eo,children:l(y,{bold:!0,color:"white",children:"\u72B6\u6001"})}),l(p,{width:Tt,children:l(y,{bold:!0,color:"white",children:"\u54C1\u724C"})}),l(p,{width:o,children:l(y,{bold:!0,color:"white",children:"\u5546\u54C1\u540D\u79F0"})}),l(p,{width:ro,children:l(y,{bold:!0,color:"white",children:"\u4EF7\u683C"})}),l(p,{width:no,children:l(y,{bold:!0,color:"white",children:"\u89C4\u683C"})}),l(p,{width:so,children:l(y,{bold:!0,color:"white",children:"\u5E93\u5B58ID"})})]})}function cr({item:o}){return l(p,{flexDirection:"column",children:l(y,{color:"gray",children:` shopId: ${o.shopId} thirdItemNo: ${o.thirdItemNo||"-"} outItemNo: ${o.outItemNo||"-"} \u8D27\u53F7: ${o.goodsNo||"-"} ${o.type||"-"} ${o.platform} \u521B\u5EFA: ${Ho(o.gmtCreate)} \u4FEE\u6539: ${Ho(o.gmtModified)}`})})}function lr({item:o,fillWidth:t}){let e=ir[o.status]??{label:o.status,color:"white"};return $(p,{flexDirection:"column",children:[$(p,{flexDirection:"row",children:[l(p,{width:oo,children:l(y,{color:"gray",children:o.id})}),l(p,{width:eo,children:l(y,{color:e.color,children:e.label})}),l(p,{width:Tt,children:l(y,{color:"cyan",children:Wo(o.brandName||"-",Tt-1)})}),l(p,{width:t,children:l(y,{children:Wo(o.goodsName,t-1)})}),l(p,{width:ro,children:$(y,{color:"yellow",children:["\xA5",o.price]})}),l(p,{width:no,children:l(y,{color:"gray",children:o.spec||"-"})}),l(p,{width:so,children:l(y,{color:"gray",children:o.stockGoodsId})})]}),l(cr,{item:o})]})}function Vo({items:o,total:t}){let e=process.stdout.columns||80,r=4,n=oo+eo+Tt+ro+no+so,s=Math.max(e-r-n,20),i=n+s;return $(p,{flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"gray",paddingX:1,children:[$(p,{flexDirection:"row",children:[l(y,{bold:!0,color:"cyan",children:"\u4E0A\u67B6\u5217\u8868"}),$(y,{color:"gray",children:[" \xB7 \u5171 ",t," \u6761"]})]}),$(p,{flexDirection:"column",marginTop:1,children:[l(ar,{fillWidth:s}),l(y,{color:"gray",children:"\u2500".repeat(i)}),o.map(a=>l(lr,{item:a,fillWidth:s},a.id))]})]})}function Ko(){let o=new dr("listing");return o.description("\u67E5\u8BE2\u4E0A\u67B6\u5546\u54C1\u5217\u8868"),o.option("--id <id>","\u4E0A\u67B6\u8BB0\u5F55 ID").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--shop-id <id>","\u5E97\u94FA ID").option("--stock-id <id>","\u4ED3\u5E93 ID").option("-s, --status <status>","\u72B6\u6001\u8FC7\u6EE4\uFF08init/up/down/fail/sold\uFF09").option("-p, --platform <platform>","\u5E73\u53F0","xianyu").option("--page <n>","\u9875\u7801","1").option("--size <n>","\u6BCF\u9875\u6570\u91CF\uFF08\u6700\u5927 50\uFF09","20").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{let r=await No({id:t.id,stockGoodsId:t.stockGoodsId?Number(t.stockGoodsId):void 0,shopId:t.shopId,stockId:t.stockId,status:t.status,platform:t.platform,page:Number(t.page)||1,size:Math.min(Number(t.size)||20,50)})??{items:[],total:0};if(t.json){r.items?.length?console.log(JSON.stringify(r,null,2)):console.log(JSON.stringify({...r,hint:"\u6682\u65E0\u4E0A\u67B6\u8BB0\u5F55"},null,2));return}if(!r.items?.length){console.log(ur.yellow("\u6682\u65E0\u4E0A\u67B6\u8BB0\u5F55"));return}Bt(Vo,{items:r.items,total:Number(r.total)})})),o}import{Command as mr}from"commander";import gr from"chalk";function Yo(){let o=new mr("down");return o.description("\u4E0B\u67B6\u95F2\u9C7C\u5546\u54C1"),o.option("--id <id>","\u4E0A\u67B6\u8BB0\u5F55 ID").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--shop-id <id>","\u5E97\u94FA ID").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{if(!t.id&&!(t.stockGoodsId&&t.shopId)){P(t,"\u8BF7\u6307\u5B9A\u4E0B\u67B6\u6761\u4EF6\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>");return}let e={};t.id&&(e.id=t.id),t.stockGoodsId&&(e.stockGoodsId=Number(t.stockGoodsId)),t.shopId&&(e.shopId=t.shopId),t.json||console.log(gr.cyan("\u{1F4E6} \u6B63\u5728\u4E0B\u67B6\u5546\u54C1..."));let r=await ko(e);j(t,r,"\u2705 \u4E0B\u67B6\u6210\u529F")})),o}import{Command as pr}from"commander";import fr from"chalk";function Zo(){let o=new pr("price");return o.description("\u4FEE\u6539\u95F2\u9C7C\u4E0A\u67B6\u5546\u54C1\u4EF7\u683C"),o.option("--id <id>","\u4E0A\u67B6\u8BB0\u5F55 ID").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID").option("--shop-id <id>","\u5E97\u94FA ID").option("--price <amount>","\u65B0\u4EF7\u683C\uFF08\u5FC5\u586B\uFF09").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{if(!t.price){P(t,"--price <amount> \u4E3A\u5FC5\u586B\u53C2\u6570");return}if(!t.id&&!(t.stockGoodsId&&t.shopId)){P(t,"\u8BF7\u6307\u5B9A\u5546\u54C1\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>");return}let e={price:Number(t.price)};t.id&&(e.id=t.id),t.stockGoodsId&&(e.stockGoodsId=Number(t.stockGoodsId)),t.shopId&&(e.shopId=t.shopId),t.json||console.log(fr.cyan(`\u{1F4B0} \u6B63\u5728\u4FEE\u6539\u4EF7\u683C\u4E3A ${t.price}...`));let r=await Ro(e);j(t,r,"\u2705 \u4EF7\u683C\u4FEE\u6539\u6210\u529F")})),o}import{Command as hr}from"commander";import yr from"chalk";function te(){let o=new hr("edit");return o.description("\u4FEE\u6539\u5DF2\u4E0A\u67B6\u5546\u54C1\u4FE1\u606F\uFF08\u6807\u9898\u3001\u63CF\u8FF0\u3001\u54C1\u724C\u3001\u7C7B\u76EE\u3001\u56FE\u7247\u3001\u5C5E\u6027\u7B49\uFF09"),o.option("--id <id>","\u5546\u54C1\u4E0A\u67B6 ID\uFF08goodsListingId\uFF0C\u63A8\u8350\uFF09").option("--stock-goods-id <id>","\u5E93\u5B58\u5546\u54C1 ID\uFF08\u4E0E --account \u914D\u5408\uFF09").option("--account <shopId>","\u95F2\u9C7C\u7528\u6237\u540D/\u5E97\u94FA ID\uFF08\u4E0E --stock-goods-id \u914D\u5408\uFF09").option("--title <title>","\u5546\u54C1\u6807\u9898").option("--desc <desc>","\u5546\u54C1\u63CF\u8FF0").requiredOption("--category-id <id>","\u5546\u54C1\u7C7B\u76EE ID\uFF08\u5927\u5206\u7C7B\uFF0C\u540E\u7AEF\u5FC5\u586B\uFF09").requiredOption("--channel-cat-id <id>","\u6E20\u9053\u7C7B\u76EE ID\uFF08\u5C0F\u5206\u7C7B\uFF0C\u540E\u7AEF\u5FC5\u586B\uFF09").option("--image-ids <ids>","\u56FE\u7247 ID \u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09").option("--item-attrs <json>","\u5546\u54C1\u5C5E\u6027\u5217\u8868\uFF08JSON \u5B57\u7B26\u4E32\uFF09").option("--brand-name <name>","\u54C1\u724C\u540D\u79F0").option("--stuff-status <status>","\u6210\u8272\u7B49\u7EA7\uFF1A100=\u5168\u65B0 -1=\u51C6\u65B0 99=99\u65B0 95=95\u65B0 90=9\u65B0").option("--goods-no <no>","\u8D27\u53F7").option("--original-price <price>","\u539F\u4EF7\uFF08\u5355\u4F4D\uFF1A\u5143\uFF09").option("--size <size>","\u5C3A\u7801").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(m(async t=>{if(!t.id&&!(t.stockGoodsId&&t.account)){P(t,"\u8BF7\u6307\u5B9A\u5546\u54C1\uFF1A--id <goodsListingId> \u6216 --stock-goods-id <id> --account <shopId>");return}let e={categoryId:Number(t.categoryId),channelCatId:t.channelCatId};if(t.id&&(e.goodsListingId=Number(t.id)),t.stockGoodsId&&(e.stockGoodsId=Number(t.stockGoodsId)),t.account&&(e.account=t.account),t.title&&(e.title=t.title),t.desc&&(e.desc=t.desc),t.imageIds&&(e.imageIdList=t.imageIds.split(",").map(s=>s.trim())),t.brandName&&(e.brandName=t.brandName),t.stuffStatus&&(e.stuffStatus=Number(t.stuffStatus)),t.goodsNo&&(e.goodsNo=t.goodsNo),t.originalPrice&&(e.originalPrice=Number(t.originalPrice)),t.size&&(e.size=t.size),t.itemAttrs)try{e.itemAttrList=JSON.parse(t.itemAttrs)}catch{P(t,"--item-attrs JSON \u89E3\u6790\u5931\u8D25");return}if(!Object.keys(e).some(s=>!["goodsListingId","stockGoodsId","account"].includes(s))){P(t,"\u672A\u6307\u5B9A\u9700\u8981\u4FEE\u6539\u7684\u5B57\u6BB5");return}t.json||console.log(yr.cyan("\u6B63\u5728\u4FEE\u6539\u5546\u54C1\u4FE1\u606F..."));let n=await Lo(e);j(t,n,"\u2705 \u5546\u54C1\u4FE1\u606F\u4FEE\u6539\u6210\u529F")})),o}import{Command as et}from"commander";import S from"chalk";var wr={100:"\u5168\u65B0",[-1]:"\u51C6\u65B0",99:"99\u65B0",95:"95\u65B0",90:"9\u65B0"};function oe(){let o=new et("hang-up");return o.description("\u95F2\u9C7C\u6302\u552E\u4E0A\u67B6\uFF08\u5B8C\u6574\u5546\u54C1\u4FE1\u606F\u6A21\u5F0F\uFF09"),o.addCommand(new et("categories").description("\u83B7\u53D6\u95F2\u9C7C\u7C7B\u76EE\u5217\u8868\uFF08\u5927\u5206\u7C7B \u2192 \u5C0F\u5206\u7C7B\uFF09").option("--sp-biz-type <n>","\u4E1A\u52A1\u5206\u7C7B\uFF0C16=\u5962\u54C1","16").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(m(async t=>{let e=await Uo(Number(t.spBizType));if(t.json){console.log(JSON.stringify(e,null,2));return}let r=new Map;for(let n of e){let s=String(n.catId);r.has(s)||r.set(s,{catName:n.catName,children:[]}),r.get(s).children.push({channel:n.channel,channelCatId:n.channelCatId})}for(let[n,s]of r){console.log(S.bold(`${s.catName} (catId: ${S.green(n)})`));for(let i of s.children)console.log(` ${i.channel} (channelCatId: ${S.green(i.channelCatId)})`)}}))),o.addCommand(new et("props").description("\u83B7\u53D6\u6307\u5B9A\u7C7B\u76EE\u4E0B\u7684\u5C5E\u6027\u5217\u8868\uFF08\u542B\u53EF\u9009\u503C\uFF09").requiredOption("--channel-cat-id <id>","\u5C0F\u5206\u7C7B ID\uFF08\u4ECE categories \u83B7\u53D6\uFF09").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(m(async t=>{let e=await Eo(t.channelCatId);if(t.json){console.log(JSON.stringify(e,null,2));return}for(let r of e)if(console.log(S.bold(`
|
|
38
|
+
${r.propName} (propId: ${r.propId})`)),r.propsValues?.length)for(let n of r.propsValues)console.log(` ${n.valueName} (valueId: ${n.valueId})`);else console.log(S.gray(" \uFF08\u4F7F\u7528 brands \u5B50\u547D\u4EE4\u641C\u7D22\uFF09"))}))),o.addCommand(new et("brands").description("\u641C\u7D22\u95F2\u9C7C\u54C1\u724C\uFF08\u6309\u5173\u952E\u5B57\u8FC7\u6EE4\uFF09").requiredOption("--channel-cat-id <id>","\u5C0F\u5206\u7C7B ID").requiredOption("--prop-id <id>","\u5C5E\u6027 ID\uFF08\u54C1\u724C\u5C5E\u6027\u7684 propId\uFF09").requiredOption("--key <keyword>","\u641C\u7D22\u5173\u952E\u5B57").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(m(async t=>{let e=await jo(t.channelCatId,t.propId,t.key);if(t.json){console.log(JSON.stringify(e,null,2));return}if(!e.length){console.log(S.yellow("\u672A\u627E\u5230\u5339\u914D\u7684\u54C1\u724C"));return}for(let r of e)console.log(` ${r.valueName} (valueId: ${r.valueId})`)}))),o.addCommand(new et("upload-images").description("\u6279\u91CF\u4E0A\u4F20\u56FE\u7247\u5230\u95F2\u9C7C\uFF08\u6302\u552E\u524D\u5FC5\u987B\u5148\u4E0A\u4F20\u56FE\u7247\uFF09").requiredOption("--shop-id <id>","\u5E97\u94FA ID").requiredOption("--files <paths>","\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84\uFF0C\u9017\u53F7\u5206\u9694").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(m(async t=>{let e=t.files.split(",").map(s=>s.trim()).filter(Boolean);if(e.length===0){P(t,"\u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u5F20\u56FE\u7247");return}t.json||console.log(S.cyan(`\u6B63\u5728\u4E0A\u4F20 ${e.length} \u5F20\u56FE\u7247...`));let{images:r,failed:n}=await Do(t.shopId,e);if(t.json){let s={success:!0,images:r};n.length&&(s.warning=`${n.length} \u5F20\u56FE\u7247\u4E0A\u4F20\u5931\u8D25`,s.failed=n),console.log(JSON.stringify(s,null,2))}else{if(r.length){console.log(S.green(`\u4E0A\u4F20\u6210\u529F\uFF0C\u5171 ${r.length} \u5F20`));for(let s of r)console.log(` \u56FE\u7247ID: ${s.value}`)}if(n.length){console.log(S.yellow(`
|
|
39
|
+
${n.length} \u5F20\u4E0A\u4F20\u5931\u8D25:`));for(let s of n)console.log(` ${s.file}: ${s.error}`)}}}))),o.addCommand(new et("submit").description("\u63D0\u4EA4\u6302\u552E\u4E0A\u67B6").requiredOption("--shop-id <id>","\u5E97\u94FA ID\uFF08\u5373\u95F2\u9C7C\u7528\u6237\u540D account\uFF09").requiredOption("--title <title>","\u5546\u54C1\u6807\u9898").requiredOption("--price <amount>","\u552E\u4EF7").requiredOption("--category-id <id>","\u5927\u5206\u7C7B ID\uFF08\u4ECE categories \u83B7\u53D6\uFF09").requiredOption("--channel-cat-id <id>","\u5C0F\u5206\u7C7B ID\uFF08\u4ECE categories \u83B7\u53D6\uFF09").requiredOption("--image-ids <ids>","\u56FE\u7247 ID \u5217\u8868\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u5148\u901A\u8FC7 upload-images \u83B7\u53D6\uFF09").requiredOption("--stuff-status <n>","\u6210\u8272\uFF1A100 \u5168\u65B0 / -1 \u51C6\u65B0 / 99 99\u65B0 / 95 95\u65B0 / 90 9\u65B0").option("--item-attrs <json>",'\u5546\u54C1\u5C5E\u6027\u5217\u8868 JSON\uFF0C\u683C\u5F0F: [{"valueName":"x","valueId":"y","propId":"z"}]').option("--brand-name <name>","\u54C1\u724C\u540D\u79F0").requiredOption("--desc <desc>","\u5546\u54C1\u63CF\u8FF0").option("--size <size>","\u5C3A\u7801").option("--goods-no <no>","\u8D27\u53F7").option("--original-price <amount>","\u539F\u4EF7").option("--trade-type <n>","\u4EA4\u6613\u65B9\u5F0F\uFF1A0 \u4EC5\u5728\u7EBF / 1 \u4EC5\u7EBF\u4E0B / 2 \u7EBF\u4E0A\u6216\u7EBF\u4E0B","0").option("--transport-fee <amount>","\u8FD0\u8D39\uFF08\u9ED8\u8BA4 0 \u5305\u90AE\uFF09","0").option("--yhb","\u662F\u5426\u5F00\u542F\u9A8C\u8D27\u5B9D").requiredOption("--out-item-no <no>","\u5546\u5BB6\u7F16\u7801\uFF08\u540C\u5E97\u94FA\u552F\u4E00\uFF0C\u7528\u6237\u81EA\u5B9A\u4E49\uFF09").option("--division-id <id>","\u884C\u653F\u533A\u5212 ID\uFF08\u5E02\u7EA7 ID\uFF0C\u9ED8\u8BA4\u676D\u5DDE 330100\uFF09","330100").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09").action(m(async t=>{let e=t.imageIds.split(",").map(i=>i.trim()),r=t.itemAttrs?JSON.parse(t.itemAttrs):void 0,n={account:t.shopId,title:t.title,reservePrice:Number(t.price),categoryId:Number(t.categoryId),channelCatId:t.channelCatId,imageIdList:e,stuffStatus:Number(t.stuffStatus),itemBizType:2,spBizType:"16",tradeType:Number(t.tradeType)||0,transportFee:Number(t.transportFee)||0,yhb:t.yhb??!1,...t.brandName&&{brandName:t.brandName},desc:t.desc,...t.size&&{size:t.size},...t.goodsNo&&{goodsNo:t.goodsNo},...t.originalPrice&&{originalPrice:Number(t.originalPrice)},...r?.length&&{itemAttrList:r},outItemNo:t.outItemNo,divisionId:Number(t.divisionId)||330100,apiAfterSalesDo:{supportFd10msPolicy:!1,supportFd24hsPolicy:!1,supportNfrPolicy:!1,supportSdrPolicy:!1,supportVnrPolicy:!1,supportGpaPolicy:!1,supportFd48hsPolicy:!1}};t.json||(console.log(S.cyan("\u6B63\u5728\u63D0\u4EA4\u6302\u552E...")),console.log(S.gray(` \u6807\u9898: ${n.title}`)),console.log(S.gray(` \u552E\u4EF7: \xA5${n.reservePrice}`)),console.log(S.gray(` \u6210\u8272: ${wr[n.stuffStatus]??n.stuffStatus}`)),console.log(S.gray(` \u56FE\u7247: ${e.length} \u5F20`)),r?.length&&console.log(S.gray(` \u5C5E\u6027: ${r.length} \u9879`)));let s=await Oo(n);j(t,s,"\u6302\u552E\u63D0\u4EA4\u6210\u529F")}))),o}function ee(){let o=new xr("goods");return o.description("\u5546\u54C1\u7BA1\u7406"),o.addCommand(Xo()),o.addCommand(zo()),o.addCommand(Fo()),o.addCommand(Ko()),o.addCommand(Yo()),o.addCommand(Zo()),o.addCommand(te()),o.addCommand(Bo()),o.addCommand(oe()),o}import{Command as Ir}from"commander";import O from"chalk";import{promises as Sr}from"node:fs";import Cr from"node:path";import Tr from"node:os";import{spawn as br}from"node:child_process";var bt="@round2ai/r2-cli";function re(){let o=new Ir("uninstall");return o.description("\u5378\u8F7D R2-CLI \u5E76\u6E05\u9664\u6240\u6709\u914D\u7F6E"),o.action(async()=>{try{console.log(O.yellow(`
|
|
40
|
+
\u26A0\uFE0F \u5373\u5C06\u6267\u884C\u4EE5\u4E0B\u64CD\u4F5C\uFF1A`)),console.log(O.gray(" 1. \u5220\u9664\u914D\u7F6E\u76EE\u5F55 ~/.r2-cli/")),console.log(O.gray(` 2. \u5168\u5C40\u5378\u8F7D ${bt}
|
|
41
|
+
`));let{confirm:t}=await import("@inquirer/prompts");if(!await t({message:"\u786E\u8BA4\u5378\u8F7D\uFF1F",default:!1})){console.log(O.gray("\u5DF2\u53D6\u6D88\u5378\u8F7D"));return}let r=Cr.join(Tr.homedir(),".r2-cli");try{await Sr.rm(r,{recursive:!0,force:!0}),console.log(O.green("\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u6E05\u9664"))}catch{console.log(O.yellow("\u26A0\uFE0F \u914D\u7F6E\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u5220\u9664\uFF08\u53EF\u5FFD\u7565\uFF09"))}console.log(O.cyan(`\u6B63\u5728\u5378\u8F7D ${bt}...`)),br("npm",["uninstall","-g",bt],{stdio:"inherit",shell:!0}).on("exit",s=>{s===0?console.log(O.green(`
|
|
42
|
+
\u2705 ${bt} \u5DF2\u5378\u8F7D`)):(console.log(O.yellow(`
|
|
43
|
+
\u26A0\uFE0F npm \u5378\u8F7D\u5931\u8D25 (exit code: ${s})`)),console.log(O.gray(" \u5982\u901A\u8FC7 yarn/pnpm \u5B89\u88C5\uFF0C\u8BF7\u624B\u52A8\u5378\u8F7D"))),process.exit(s??1)})}catch(t){X(t)}}),o}import{Command as vr}from"commander";import at from"chalk";import{spawn as kr,execSync as Rr}from"node:child_process";import{readFileSync as Pr}from"node:fs";import{join as Ar}from"node:path";function Pt(){for(let o of["../package.json","../../package.json"])try{return JSON.parse(Pr(Ar(import.meta.dirname,o),"utf-8")).version}catch{}return"0.0.0"}var ne="@round2ai/r2-cli";function Lr(o,t){return new Promise(e=>{let r=kr(o,t,{stdio:"inherit"});r.on("close",n=>e(n??1)),r.on("error",()=>e(1))})}function se(){return new vr("update").description("\u4E00\u952E\u66F4\u65B0 CLI \u548C\u6280\u80FD").action(async()=>{let o=Pt();console.log(at.cyan(`\u5F53\u524D\u7248\u672C: ${o}`)),console.log(at.cyan("\u6B63\u5728\u66F4\u65B0 CLI...")),await Lr("npm",["install","-g",`${ne}@latest`])!==0&&(console.error(at.red(`
|
|
44
|
+
\u2717 update failed \xB7 Try: npm install -g ${ne}@latest`)),process.exit(1));let e=o;try{e=Rr("r2-cli --version",{encoding:"utf-8"}).trim()||o}catch{}console.log(at.green(`
|
|
45
|
+
\u2713 \u66F4\u65B0\u5B8C\u6210: ${o} \u2192 ${e}`)),console.log(at.green("\u2713 \u6280\u80FD\u5DF2\u540C\u6B65\u66F4\u65B0"))})}function ie(o){let t=o.command("auth").description("\u6388\u6743\u7BA1\u7406");t.addCommand(Qt()),t.addCommand(Xt()),t.addCommand(_t()),t.addCommand(Mt()),o.addCommand(ee()),o.addCommand(re()),o.addCommand(se())}import ae from"chalk";var ce="@round2ai/r2-cli",Nr=[`https://registry.npmmirror.com/${encodeURIComponent(ce)}/latest`,`https://registry.npmjs.org/${encodeURIComponent(ce)}/latest`],Dr=5e3;async function Or(o){let t=new AbortController,e=setTimeout(()=>t.abort(),Dr);try{let r=await fetch(o,{signal:t.signal});return r.ok?(await r.json()).version??null:null}catch{return null}finally{clearTimeout(e)}}async function Ur(){let o=await Promise.allSettled(Nr.map(Or));for(let t of o)if(t.status==="fulfilled"&&t.value)return t.value;return null}function Er(o,t){let e=o.split(".").map(Number),r=t.split(".").map(Number);for(let n=0;n<3;n++)if((e[n]??0)!==(r[n]??0))return(e[n]??0)>(r[n]??0);return!1}async function le(o){let t=await Ur();t&&Er(t,o)&&jr(o,t)}function jr(o,t){console.error(ae.yellow(`
|
|
46
|
+
Update available: ${o} \u2192 ${t}`)+ae.gray(`
|
|
46
47
|
Run: r2-cli update
|
|
47
|
-
`))}async function
|
|
48
|
-
`))}function
|
|
49
|
-
\u64CD\u4F5C\u5DF2\u53D6\u6D88`)),process.exit(130)}process.on("SIGINT",
|
|
48
|
+
`))}async function Br(){let{default:o}=await import("figlet");console.log(rt.cyan.bold(o.textSync("R2-CLI",{font:"Standard",horizontalLayout:"full"}))),console.log(rt.gray(` \u5411 AI \u5F00\u653E\u4E8C\u624B\u6F6E\u5962\u4EA4\u6613\u5168\u94FE\u8DEF\u80FD\u529B
|
|
49
|
+
`))}function qr(){let o=new $r;o.name("r2-cli").description("R2-CLI\uFF0C\u5411 AI \u5F00\u653E\u4E8C\u624B\u6F6E\u5962\u4EA4\u6613\u5168\u94FE\u8DEF\u80FD\u529B");let t=Pt();t==="0.0.0"&&console.error(rt.yellow("Warning: unable to read version from package.json")),o.version(t,"-v, --version");let e=le(t);return o.configureOutput({writeErr:r=>{console.error(rt.red(r.replace("error:","").trim()))}}),o.action(async()=>{await Br(),o.help()}),ie(o),{program:o,updateCheckPromise:e}}function de(){console.log(rt.gray(`
|
|
50
|
+
\u64CD\u4F5C\u5DF2\u53D6\u6D88`)),process.exit(130)}process.on("SIGINT",de);process.on("SIGTERM",de);var{program:Gr,updateCheckPromise:Jr}=qr();Gr.parse(process.argv);Jr.catch(o=>{console.error(rt.gray(`[update-check] ${o instanceof Error?o.message:String(o)}`))});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@round2ai/r2-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"description": "R2-CLI,向 AI 开放二手潮奢交易全链路能力",
|
|
5
5
|
"main": "dist/r2-cli.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"ink": "^7.0.0",
|
|
50
50
|
"ora": "^9.3.0",
|
|
51
51
|
"qrcode": "^1.5.4",
|
|
52
|
-
"react": "^19.2.5"
|
|
52
|
+
"react": "^19.2.5",
|
|
53
|
+
"sharp": "^0.34.5"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@types/node": "^25.5.2",
|
package/skills/r2-auth/SKILL.md
CHANGED
|
@@ -33,6 +33,8 @@ r2-cli auth login --json
|
|
|
33
33
|
|
|
34
34
|
命令会依次输出两段 JSON:
|
|
35
35
|
|
|
36
|
+
> ⚠️ **命令会自动轮询,不需要(也不应该)手动调用 `auth login poll`。只需等待命令完成即可。**
|
|
37
|
+
|
|
36
38
|
**第 1 段:二维码信息(立即输出)**
|
|
37
39
|
|
|
38
40
|
```json
|
|
@@ -40,7 +42,6 @@ r2-cli auth login --json
|
|
|
40
42
|
"qrToken": "xxx",
|
|
41
43
|
"expireTimeMs": 300000,
|
|
42
44
|
"pollIntervalMs": 800,
|
|
43
|
-
"url": "https://m.puresnake.com/r2/auth/login?qrToken=xxx&from=wechat",
|
|
44
45
|
"qrUrl": "http://127.0.0.1:52173/login/"
|
|
45
46
|
}
|
|
46
47
|
```
|
|
@@ -49,8 +50,9 @@ r2-cli auth login --json
|
|
|
49
50
|
|------|------|
|
|
50
51
|
| `qrToken` | 二维码 token(轮询用,不需要手动使用) |
|
|
51
52
|
| `expireTimeMs` | 二维码过期时间(毫秒),默认 5 分钟 |
|
|
52
|
-
| `
|
|
53
|
-
|
|
53
|
+
| `qrUrl` | 本地扫码页面链接(**请在浏览器中打开此链接**,页面会显示二维码供手机扫描) |
|
|
54
|
+
|
|
55
|
+
> ⚠️ **浏览器可能无法自动打开**:请手动复制 `qrUrl` 在浏览器中打开。用户使用**第二回合 APP / 微信 / 支付宝**扫描页面上的二维码。
|
|
54
56
|
|
|
55
57
|
**第 2 段:登录结果(用户扫码确认后输出)**
|
|
56
58
|
|
|
@@ -60,21 +62,23 @@ r2-cli auth login --json
|
|
|
60
62
|
|
|
61
63
|
### Agent 操作步骤
|
|
62
64
|
|
|
63
|
-
>
|
|
65
|
+
> ⚠️ **不要手动轮询**:`auth login --json` 已内置自动轮询,不要用 `auth login poll` 单独轮询。
|
|
66
|
+
> ⚠️ **不要在命令末尾加 `&`**:如果工具已有后台执行选项,不要额外加 `&`,否则输出丢失。
|
|
64
67
|
|
|
65
|
-
1.
|
|
66
|
-
2.
|
|
67
|
-
3. **必须先**将 `qrUrl`
|
|
68
|
+
1. 启动 `r2-cli auth login --json`(异步/后台执行,设置 5 分钟超时)
|
|
69
|
+
2. 读取命令输出,获取第 1 段 JSON(QR 信息)
|
|
70
|
+
3. **必须先**将 `qrUrl` 以醒目格式展示给用户:
|
|
68
71
|
|
|
69
72
|
```
|
|
70
|
-
|
|
73
|
+
请在浏览器中打开此链接扫码登录:http://127.0.0.1:PORT/login/
|
|
71
74
|
```
|
|
72
75
|
|
|
73
|
-
4.
|
|
74
|
-
5.
|
|
75
|
-
6.
|
|
76
|
+
4. **不要关闭/中断命令** — 命令正在自动轮询,等待用户扫码
|
|
77
|
+
5. 告知用户:用**第二回合 APP / 微信 / 支付宝**扫描页面上的二维码。浏览器会尝试自动打开扫码页面,**如未自动打开请手动复制上方链接在浏览器中打开**
|
|
78
|
+
6. 继续读取命令输出,等待第 2 段 JSON(登录结果,最长 5 分钟)
|
|
79
|
+
7. 检查第 2 段 JSON 的 `success` 字段判断登录是否成功
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
**为什么必须先展示链接**:浏览器自动打开在 Windows/远程服务器/SSH 环境下经常失败。`qrUrl` 是用户扫码的唯一保障,必须优先展示并提示手动打开。
|
|
78
82
|
|
|
79
83
|
---
|
|
80
84
|
|
|
@@ -109,7 +113,7 @@ r2-cli auth xianyu --json
|
|
|
109
113
|
{ "success": true, "shopId": "...", "shopName": "..." }
|
|
110
114
|
```
|
|
111
115
|
|
|
112
|
-
Agent
|
|
116
|
+
Agent 操作步骤与登录相同:启动命令 → 获取第 1 段 JSON → **先展示 `qrUrl`** → **不要中断命令,等待第 2 段 JSON**。同样不要手动轮询。
|
|
113
117
|
|
|
114
118
|
---
|
|
115
119
|
|
package/skills/r2-goods/SKILL.md
CHANGED
|
@@ -34,7 +34,7 @@ metadata:
|
|
|
34
34
|
|
|
35
35
|
**判断方法**:
|
|
36
36
|
1. 用户**明确指定**了上架方式 → 直接走对应流程
|
|
37
|
-
2. 用户提供了图片文件 → 直接走 `goods hang-up`,Agent 用 Read
|
|
37
|
+
2. 用户提供了图片文件 → 直接走 `goods hang-up`,Agent 用 Read 工具查看图片自动识别商品信息(如果 Read 工具返回 `[Unsupported Image]`,视为不能识别,走询问路径)
|
|
38
38
|
3. 用户只说"上架"未指定方式 → **必须询问用户**:"选品上架还是挂售上架?"
|
|
39
39
|
|
|
40
40
|
## 命令概览
|
|
@@ -48,15 +48,14 @@ metadata:
|
|
|
48
48
|
| `r2-cli goods list [--stock-id <id>] [--json]` | 查看选品商品 | [r2-goods-query](references/r2-goods-query.md) |
|
|
49
49
|
| `r2-cli goods listing [--status <up/down/sold>] [--json]` | 查询上架列表 | [r2-goods-query](references/r2-goods-query.md) |
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### 上架/下架/改价/修改
|
|
52
52
|
|
|
53
53
|
| 命令 | 说明 | 详细文档 |
|
|
54
54
|
|------|------|----------|
|
|
55
55
|
| `r2-cli goods up --stock-goods-id <> --shop-id <> --price <> --json` | 普通上架(选品商品) | [r2-goods-listing](references/r2-goods-listing.md) |
|
|
56
56
|
| `r2-cli goods down --id <id> [--json]` | 下架商品 | [r2-goods-listing](references/r2-goods-listing.md) |
|
|
57
57
|
| `r2-cli goods price --id <id> --price <amount> [--json]` | 修改价格 | [r2-goods-listing](references/r2-goods-listing.md) |
|
|
58
|
-
|
|
59
|
-
> **暂未开放**:`goods edit`(修改商品信息)接口尚未发布正式版,暂时不可用。
|
|
58
|
+
| `r2-cli goods edit --id <id> [--title ...] --json` | 修改商品信息 | [r2-goods-listing](references/r2-goods-listing.md) |
|
|
60
59
|
|
|
61
60
|
### 选品上架 4 步流程
|
|
62
61
|
|
|
@@ -67,6 +66,42 @@ metadata:
|
|
|
67
66
|
|
|
68
67
|
必填参数:`--stock-goods-id`、`--shop-id`(取 `shopId` 不是 `id`)、`--price`
|
|
69
68
|
|
|
69
|
+
### 修改商品信息(edit)
|
|
70
|
+
|
|
71
|
+
修改已上架商品的标题、描述、品牌、类目、图片、属性等。
|
|
72
|
+
|
|
73
|
+
> **注意**:`goods edit` 不支持修改价格。改价需单独使用 `r2-cli goods price --id <id> --price <amount>`。
|
|
74
|
+
|
|
75
|
+
**路由决策**:
|
|
76
|
+
|
|
77
|
+
| 用户意图 | 流程 |
|
|
78
|
+
|----------|------|
|
|
79
|
+
| 提供了图片文件 | 全自动:读图识别 → 上传图片 → 匹配类目/属性/品牌 → 展示变更 → 用户确认 → 提交 |
|
|
80
|
+
| 指定了具体字段(如"改标题为X") | 直接修改指定字段,不动图片 |
|
|
81
|
+
| 说"修改/更新商品信息"但没给细节 | 提示:可以提供图片自动识别商品信息,也可以指定要修改的具体字段 |
|
|
82
|
+
|
|
83
|
+
**定位商品**:优先使用 `--id <goodsListingId>`(从上架列表获取 `id` 字段),也可用 `--stock-goods-id <id> --account <shopId>`。
|
|
84
|
+
|
|
85
|
+
**关键约束**:
|
|
86
|
+
- `--category-id` 和 `--channel-cat-id` 是**必填的**(后端复用挂售 DTO),即使不改类目也要传当前类目
|
|
87
|
+
- **`--item-attrs` 必须包含 props 中所有属性,不只是修改的那一个**:后端替换整个属性列表,漏传的属性会被清除。调 `goods hang-up props --channel-cat-id <id> --json` 获取全部属性后,改目标值,其他保持原样一并传入
|
|
88
|
+
- Agent 应自动查询类目并匹配,不需要用户手动提供
|
|
89
|
+
- AI 读图识别后填充的字段需展示给用户确认,不能静默覆盖已有信息
|
|
90
|
+
- `--image-ids` 接受已上传的图片 ID,用户给图片文件时需先调 `hang-up upload-images` 上传
|
|
91
|
+
|
|
92
|
+
**带图片的全自动流程**(Agent 自动完成,用户只需提供图片并确认):
|
|
93
|
+
|
|
94
|
+
1. **展示列表**:`goods listing --json` → 用户选择要修改的商品
|
|
95
|
+
2. **上传图片**:`hang-up upload-images --shop-id <shopId> --files <paths> --json`
|
|
96
|
+
3. **AI 读图识别**:Agent 用 Read 工具查看图片,识别品牌/类目/成色/描述等
|
|
97
|
+
4. **自动匹配类目**:`hang-up categories --json` → 根据识别结果匹配 catId + channelCatId
|
|
98
|
+
5. **自动查询属性**:`hang-up props --channel-cat-id <id> --json` → 根据识别结果匹配成色/尺码/季节等
|
|
99
|
+
6. **自动搜索品牌**:`hang-up brands --channel-cat-id <> --prop-id <> --key <品牌名> --json` → 获取品牌 valueId
|
|
100
|
+
7. **汇总展示**:当前值 vs 变更值,让用户确认
|
|
101
|
+
8. **提交**:`goods edit --id <goodsListingId> --category-id <> --channel-cat-id <> --image-ids <> --item-attrs <> --brand-name <> --json`
|
|
102
|
+
|
|
103
|
+
**核心原则**:用户只需提供图片 + 确认。类目匹配、属性填充、品牌搜索全部由 Agent 自动完成。
|
|
104
|
+
|
|
70
105
|
### 挂售(hang-up)
|
|
71
106
|
|
|
72
107
|
| 命令 | 说明 | 详细文档 |
|
|
@@ -74,26 +109,37 @@ metadata:
|
|
|
74
109
|
| `r2-cli goods hang-up categories [--json]` | 获取闲鱼类目 | [r2-goods-hangup](references/r2-goods-hangup.md) |
|
|
75
110
|
| `r2-cli goods hang-up props --channel-cat-id <id> [--json]` | 获取属性列表 | [r2-goods-hangup](references/r2-goods-hangup.md) |
|
|
76
111
|
| `r2-cli goods hang-up brands --channel-cat-id <> --prop-id <> --key <> [--json]` | 品牌搜索 | [r2-goods-hangup](references/r2-goods-hangup.md) |
|
|
112
|
+
| `r2-cli goods hang-up upload-images --shop-id <> --files <> --json` | 上传图片 | [r2-goods-hangup](references/r2-goods-hangup.md) |
|
|
77
113
|
| `r2-cli goods hang-up submit --shop-id <> --title <> ... --json` | 提交挂售上架 | [r2-goods-hangup](references/r2-goods-hangup.md) |
|
|
78
114
|
|
|
79
|
-
> **暂未开放**:`hang-up upload-images`(上传图片)接口尚未发布正式版,暂时不可用。
|
|
80
|
-
|
|
81
115
|
### 挂售上架流程
|
|
82
116
|
|
|
83
|
-
1.
|
|
84
|
-
2.
|
|
85
|
-
3.
|
|
86
|
-
4.
|
|
87
|
-
5.
|
|
117
|
+
1. **上传图片**:`hang-up upload-images --shop-id <> --files <paths> --json`
|
|
118
|
+
2. **识别商品**:Agent 用 Read 工具查看图片,自动识别品牌/成色/类目/描述。不支持读图的 Agent 走询问路径
|
|
119
|
+
3. **匹配类目**:`hang-up categories --json` → 自动匹配
|
|
120
|
+
4. **匹配属性**:`hang-up props --channel-cat-id <id> --json` → 自动填充。品牌需调 `hang-up brands` 搜索
|
|
121
|
+
5. **汇总展示**:自动填充的字段标 ✅,缺失字段标 ❓ 让用户补充。**运费默认包邮(`--transport-fee` 默认 0),需告知用户可修改**
|
|
122
|
+
6. **提交**:`hang-up submit` — 必填:`shop-id`、`title`、`price`、`category-id`、`channel-cat-id`、`image-ids`、`stuff-status`、`desc`、`out-item-no`
|
|
88
123
|
|
|
89
124
|
**核心原则**:**图片里能看到的,就别问用户**。只问价格和商家编码(优先用户自定义,不填则推荐自动生成),其他全部从图片自动提取。
|
|
90
125
|
|
|
91
126
|
**关键注意事项**:
|
|
92
|
-
- **品牌必须双传**:`--brand-name` + itemAttrs 中的一项(含 propId/valueId/valueName
|
|
127
|
+
- **品牌必须双传**:`--brand-name` + itemAttrs 中的一项(含 propId/valueId/valueName/propName/channelCatId),缺一不可。**只要涉及品牌修改,必须同时传 `--item-attrs`,`--item-attrs` 中必须包含 propName 和 channelCatId**
|
|
93
128
|
- **描述自动生成**:品牌+款式+颜色+材质+货号自动组合,不要标记为"需要补充"
|
|
94
129
|
- **季节自动推断**:夹克→春秋季,羽绒服→秋冬季,T恤→夏季等,不需要问用户
|
|
95
130
|
- **尺码/货号从标签读取**:图片中有标签时自动提取,读不到才问用户
|
|
96
131
|
- **标题自动组合**:品牌+款式+颜色+尺码+成色
|
|
132
|
+
- **stuff-status 与 itemAttrs 成色映射**:
|
|
133
|
+
|
|
134
|
+
| stuff-status | itemAttrs 成色 valueName |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `100`(全新) | 全新 |
|
|
137
|
+
| `-1`(准新) | 几乎全新 |
|
|
138
|
+
| `99`(99新) | 几乎全新 |
|
|
139
|
+
| `95`(95新) | 轻微穿着痕迹 |
|
|
140
|
+
| `90`(9新) | 明显穿着痕迹 |
|
|
141
|
+
|
|
142
|
+
> 挂售提交时 `--item-attrs` 中的成色值需要从 props 中取对应 valueId,上面的映射告诉你取哪个 valueName。`--stuff-status` 参数单独传数字值。
|
|
97
143
|
|
|
98
144
|
> Agent 执行具体操作时,用 Read 工具读取对应的 reference 文件获取完整参数和流程说明。
|
|
99
145
|
|
|
@@ -111,5 +157,6 @@ metadata:
|
|
|
111
157
|
| `商品不存在` | edit 用了无效的 `--id` 或商品已被删除 | 确认 listing 列表中的 id 值 |
|
|
112
158
|
| `getCategoryId() is null` | edit 缺少 `--category-id` | 必须传 `--category-id` 和 `--channel-cat-id` |
|
|
113
159
|
| `商家编码重复` | out-item-no 同店铺已存在 | 更换唯一编码 |
|
|
160
|
+
| `该商品已上架` | 挂售已下架商品重新提交时 out-item-no 被占用 | 更换新的 out-item-no |
|
|
114
161
|
| `ITEM_CONDITION_NOT_SUPPORT_SIGN` | 售后服务未开通或品类不支持 | 默认关闭售后 |
|
|
115
162
|
| `轮询超时` | 上架结果查询超时 | 稍后用 `goods listing` 查看 |
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
- 商家编码(`out-item-no`)**优先让用户自定义**,用户不填则推荐自动生成编码(如 `GS20260512-0005`)
|
|
14
14
|
- **必须问用户的条件**:价格(永远无法从图片判断)。其他一切字段都应尝试从图片获取。商家编码优先用户自定义,不填则推荐自动生成
|
|
15
15
|
- **描述必须自动生成**:基于 AI 识别的品牌+款式+颜色+材质+货号自动组合,不要标记为"需要补充"
|
|
16
|
-
- **品牌必须双传**:`--brand-name`(文本字段)+ itemAttrs 中的一项(含 propId/valueId/valueName),缺一不可
|
|
16
|
+
- **品牌必须双传**:`--brand-name`(文本字段)+ itemAttrs 中的一项(含 propId/valueId/valueName/propName/channelCatId),缺一不可
|
|
17
17
|
- **季节自动推断**:根据商品类型推断适用季节(夹克/风衣→春秋季,羽绒服→秋冬季,T恤/短裤→夏季),不需要问用户
|
|
18
18
|
- **尺码/货号从标签读取**:如果图片中有标签/吊牌/水洗标,尝试读取尺码和货号,读不到时才问用户
|
|
19
19
|
- **标题自动组合**:品牌+款式+颜色+尺码+成色,自动组合为标题
|
|
@@ -50,7 +50,22 @@ r2-cli goods hang-up upload-images --shop-id <shopId> --files /path/img1.jpg,/pa
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
> 图片路径是用户本地文件路径。`--image-ids` 保持字符串,不要转数字(19 位 ID
|
|
53
|
+
> 图片路径是用户本地文件路径。`--image-ids` 保持字符串,不要转数字(19 位 ID 会精度丢失)。**CLI 自动压缩超过 2MB 的图片**(使用 sharp 渐进式降低 JPEG quality 直到 < 2MB,PNG 自动转 JPEG),原文件不会被修改。多张图片**并行上传**,单张失败自动重试 1 次。
|
|
54
|
+
|
|
55
|
+
返回(部分成功时带 `warning` 和 `failed` 字段):
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"success": true,
|
|
60
|
+
"images": [
|
|
61
|
+
{ "value": "1086608743767730915" }
|
|
62
|
+
],
|
|
63
|
+
"warning": "1 张图片上传失败",
|
|
64
|
+
"failed": [
|
|
65
|
+
{ "file": "d:/path/bad.jpg", "error": "413 Request Entity Too Large" }
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
54
69
|
|
|
55
70
|
**同时尝试识别图片**:如果 Agent 支持多模态(如 Claude Code、Gemini),用 Read 工具查看用户图片文件,识别以下信息。不支持则跳过,全部改为向用户询问。
|
|
56
71
|
|
|
@@ -123,22 +138,29 @@ Agent 遍历所有属性,尽量自动匹配:
|
|
|
123
138
|
|
|
124
139
|
**品牌精确匹配规则**:brands 搜索结果中必须选**完全匹配**的官方名称(如搜 Nike → 只选 `Nike/耐克`,忽略 BACHNIKE、NIKE 7 等)
|
|
125
140
|
|
|
141
|
+
**品牌搜索注意事项**:
|
|
142
|
+
- **支持大小写模糊搜索**:如搜索 `nike` 也能匹配到 `Nike/耐克`,搜索 `louis` 也能匹配到 `Louis Vuitton/路易威登`
|
|
143
|
+
- **搜索结果中选择精确匹配**:如搜 nike 返回多个结果,选官方名称 `Nike/耐克`,忽略 BACHNIKE、NIKE 7 等
|
|
144
|
+
|
|
126
145
|
```bash
|
|
127
146
|
r2-cli goods hang-up brands --channel-cat-id <id> --prop-id <品牌propId> --key "Nike" --json
|
|
128
147
|
```
|
|
129
148
|
|
|
130
|
-
最终构建 `--item-attrs
|
|
149
|
+
最终构建 `--item-attrs`(**5 个字段:valueName、valueId、propId、propName、channelCatId**):
|
|
131
150
|
|
|
132
|
-
**⚠️ 品牌必须同时出现在 itemAttrs 和 --brand-name 中**。只传 `--brand-name` 不会把品牌写入商品属性,品牌必须作为 itemAttrs 的一项传入(含
|
|
151
|
+
**⚠️ 品牌必须同时出现在 itemAttrs 和 --brand-name 中**。只传 `--brand-name` 不会把品牌写入商品属性,品牌必须作为 itemAttrs 的一项传入(含 propId、valueId、valueName、propName、channelCatId)。
|
|
133
152
|
|
|
134
153
|
```json
|
|
135
154
|
[
|
|
136
|
-
{ "
|
|
137
|
-
{ "
|
|
138
|
-
{ "
|
|
155
|
+
{ "valueName": "Nike/耐克", "valueId": "68af4e8f...", "propId": "83b8f62c...", "propName": "品牌", "channelCatId": "f4718bbb..." },
|
|
156
|
+
{ "valueName": "几乎全新", "valueId": "25317efe...", "propId": "3b9f06b2...", "propName": "成色", "channelCatId": "f4718bbb..." },
|
|
157
|
+
{ "valueName": "L", "valueId": "65f57139...", "propId": "6562df9f...", "propName": "尺码", "channelCatId": "f4718bbb..." },
|
|
158
|
+
{ "valueName": "春秋季", "valueId": "3162b94f...", "propId": "be925d4d...", "propName": "适用季节", "channelCatId": "f4718bbb..." }
|
|
139
159
|
]
|
|
140
160
|
```
|
|
141
161
|
|
|
162
|
+
> **注意**:每个属性项包含 `valueName`、`valueId`、`propId`、`propName`、`channelCatId` 五个字段,全部从 `props` 返回的 `propsValues` 中获取。
|
|
163
|
+
|
|
142
164
|
---
|
|
143
165
|
|
|
144
166
|
## 第 3 步:汇总展示 → 补充缺失 → 提交
|
|
@@ -155,6 +177,7 @@ Agent 将所有自动填充和识别结果汇总展示给用户,**一次确认
|
|
|
155
177
|
✅ 款式:运动鞋(图片识别)
|
|
156
178
|
✅ 鞋码:42(图片识别)
|
|
157
179
|
❓ 季节:?(无法识别,请选择:春季/夏季/秋季/冬季/四季)
|
|
180
|
+
📦 运费:默认包邮(如需收运费请告知金额)
|
|
158
181
|
💰 价格:?(必填)
|
|
159
182
|
📋 商家编码:?(优先自定义,不填自动生成)
|
|
160
183
|
```
|
|
@@ -179,7 +202,7 @@ r2-cli goods hang-up submit \
|
|
|
179
202
|
--out-item-no "商家编码" \
|
|
180
203
|
--brand-name "Nike/耐克" \
|
|
181
204
|
--size "42" \
|
|
182
|
-
--item-attrs '[{"
|
|
205
|
+
--item-attrs '[{"valueName":"Nike/耐克","valueId":"品牌valueId","propId":"83b8f62c...","propName":"品牌","channelCatId":"f4718bbb..."},{"valueName":"全新","valueId":"d114e6ab...","propId":"3b9f06b2...","propName":"成色","channelCatId":"f4718bbb..."},{"valueName":"42","valueId":"尺码valueId","propId":"6562df9f...","propName":"尺码","channelCatId":"f4718bbb..."}]' \
|
|
183
206
|
--json
|
|
184
207
|
```
|
|
185
208
|
|
|
@@ -222,6 +245,7 @@ r2-cli goods hang-up submit \
|
|
|
222
245
|
- **`--stuff-status` 准新是数字 `-1`**:不是字符串 `"-1"`,直接传 `--stuff-status -1`
|
|
223
246
|
- **`--item-attrs` 传 JSON 字符串**:值必须是 `JSON.stringify()` 后的字符串,不能直接传对象。命令行示例:`--item-attrs '[{"propId":"x","valueId":"y"}]'`
|
|
224
247
|
- **`--files` 和 `--image-ids` 都是逗号分隔**:不要多次传 `--files`,用逗号拼成单个值:`--files a.jpg,b.jpg`
|
|
248
|
+
- **`--category-id` 取 `catId` 不是 `id`**:categories 返回的数据中 `catId`(如 50106003)是真正的类目 ID,`id`(如 865)是自增 ID,不要用错
|
|
225
249
|
|
|
226
250
|
## 必填参数
|
|
227
251
|
|
|
@@ -282,9 +306,11 @@ r2-cli goods hang-up submit \
|
|
|
282
306
|
| 错误信息 | 原因 | 解决方法 |
|
|
283
307
|
|----------|------|----------|
|
|
284
308
|
| `请提供至少一张图片` | upload-images 无图片 | 提供本地图片路径 |
|
|
309
|
+
| 413 / `图片太大` | 图片超过服务端大小限制 | CLI 自动压缩 > 2MB 的图片,如仍失败请手动压缩 |
|
|
285
310
|
| `请填写有效的商品叶子类目` | category-id 或 channel-cat-id 错误 | 重新查询 categories |
|
|
286
311
|
| `找不到传入的某些图片` | 图片 ID 无效或过期 | 重新上传图片 |
|
|
287
312
|
| `商家编码重复` | out-item-no 同店铺已存在 | 更换唯一编码 |
|
|
313
|
+
| `该商品已上架` | 挂售已下架商品重新提交使用了相同的 out-item-no | 更换新的 out-item-no,或检查 listing 确认该商品是否已在闲鱼端恢复上架 |
|
|
288
314
|
| `ITEM_CONDITION_NOT_SUPPORT_SIGN` | 售后服务未开通或品类不支持 | 默认关闭售后,或在闲鱼 APP 开通对应服务 |
|
|
289
315
|
|
|
290
316
|
## References
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
状态值:`init`(处理中)、`up`(已上架)、`down`(已下架)、`fail`(失败,查看 `errorMsg`)、`sold`(已售出)
|
|
26
|
+
状态值:`init`(处理中)、`up`(已上架)、`down`(已下架)、`fail`(失败,查看 `errorMsg`)、`sold`(已售出)、`sold`(已售出)
|
|
27
27
|
|
|
28
28
|
## 上架列表返回字段
|
|
29
29
|
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
| `goodsName` | 商品名称 |
|
|
36
36
|
| `brandName` | 品牌 |
|
|
37
37
|
| `price` | 上架价格 |
|
|
38
|
-
| `status` | 状态:`init`/`up`/`down`/`fail`/`sold
|
|
38
|
+
| `status` | 状态:`init`/`up`/`down`/`fail`/`sold`(已售出) |
|
|
39
39
|
| `thirdItemNo` | 平台商品 ID |
|
|
40
40
|
| `outItemNo` | 商家编码 |
|
|
41
41
|
| `spec` | 规格(尺码) |
|
|
@@ -81,6 +81,8 @@ r2-cli goods price --stock-goods-id <id> --shop-id <id> --price <新价格> --js
|
|
|
81
81
|
|
|
82
82
|
修改已上架商品的标题、描述、品牌、类目、图片、属性等。
|
|
83
83
|
|
|
84
|
+
> **注意**:`goods edit` 不支持修改价格。改价需单独使用 `r2-cli goods price --id <id> --price <amount>`。
|
|
85
|
+
|
|
84
86
|
### 定位商品(二选一)
|
|
85
87
|
|
|
86
88
|
| 方式 | 参数 | 推荐度 |
|
|
@@ -93,6 +95,7 @@ r2-cli goods price --stock-goods-id <id> --shop-id <id> --price <新价格> --js
|
|
|
93
95
|
- **`--image-ids` 保持字符串**:图片 ID 是 19 位数字,`Number()` 会精度丢失
|
|
94
96
|
- **`--item-attrs` 传 JSON 字符串**:必须是 `JSON.stringify()` 后的结果,不能直接传对象
|
|
95
97
|
- **即使不改类目也要传 `--category-id` 和 `--channel-cat-id`**:后端必填,缺少会报 `getCategoryId() is null`
|
|
98
|
+
- **`--item-attrs` 必须包含 props 中所有属性,不只是修改的那一个**:后端替换整个属性列表,漏传的属性会被清除。从 `goods hang-up props --channel-cat-id <id> --json` 获取全部属性后,修改目标属性的值,其他属性保持原样一并传入
|
|
96
99
|
|
|
97
100
|
### 必填参数
|
|
98
101
|
|
|
@@ -147,6 +150,8 @@ r2-cli goods edit \
|
|
|
147
150
|
|
|
148
151
|
### 只改文字字段(无图片)
|
|
149
152
|
|
|
153
|
+
> 只改标题/描述等文字字段时,不需要传 `--item-attrs`。**但一旦传了 `--item-attrs`,必须包含 props 中所有属性**,不能只传修改的那一项。
|
|
154
|
+
|
|
150
155
|
```bash
|
|
151
156
|
# 改标题
|
|
152
157
|
r2-cli goods edit --id 5 \
|
|
@@ -158,3 +163,5 @@ r2-cli goods edit --id 5 \
|
|
|
158
163
|
--category-id 50106003 --channel-cat-id "f4718bbb04d7ed1facde29f76907b07f" \
|
|
159
164
|
--brand-name "Nike" --desc "全新描述" --json
|
|
160
165
|
```
|
|
166
|
+
|
|
167
|
+
> **注意**:改品牌时建议同时传 `--item-attrs`(含所有属性,品牌项用最新 valueId),因为只传 `--brand-name` 可能不会更新属性列表中的品牌值。
|
|
@@ -71,9 +71,11 @@ npm install -g @round2ai/r2-cli@latest
|
|
|
71
71
|
| 上架 | `r2-cli goods up --stock-goods-id <> --shop-id <> --price <> --json` | 普通上架(选品商品) |
|
|
72
72
|
| | `r2-cli goods down --id <id> [--json]` | 下架商品 |
|
|
73
73
|
| | `r2-cli goods price --id <id> --price <amount> [--json]` | 修改价格 |
|
|
74
|
+
| 修改 | `r2-cli goods edit --id <> --category-id <> --channel-cat-id <> ... --json` | 修改商品信息(定位推荐 `--id`) |
|
|
74
75
|
| 挂售 | `r2-cli goods hang-up categories [--json]` | 获取闲鱼类目 |
|
|
75
76
|
| | `r2-cli goods hang-up props --channel-cat-id <id> [--json]` | 获取属性列表 |
|
|
76
77
|
| | `r2-cli goods hang-up brands --channel-cat-id <> --prop-id <> --key <> [--json]` | 品牌搜索 |
|
|
78
|
+
| | `r2-cli goods hang-up upload-images --shop-id <> --files <> --json` | 上传图片 |
|
|
77
79
|
| | `r2-cli goods hang-up submit --shop-id <> --title <> ... --json` | 提交挂售上架 |
|
|
78
80
|
|
|
79
81
|
## 其他命令
|