@round2ai/r2-cli 1.0.9-beta.0 → 1.0.10
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 +23 -44
- package/dist/README.md +23 -44
- package/dist/package.json +2 -1
- package/dist/pages/login.html +2 -7
- package/dist/pages/xianyu-auth.html +3 -9
- package/dist/r2-cli.js +1757 -49
- package/package.json +2 -1
- package/skills/r2-auth/SKILL.md +98 -30
- package/skills/r2-cli/SKILL.md +21 -21
- package/skills/r2-goods/SKILL.md +125 -25
package/dist/r2-cli.js
CHANGED
|
@@ -1,51 +1,1759 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`));else{let t=o instanceof Error?o.message:String(o);console.error(A.red(`\u25B2 ${t}`))}process.exit(1)}function g(o){console.log(A.yellow(`\u25B2 "${o}" \u529F\u80FD\u5F00\u53D1\u4E2D\uFF0C\u6682\u4E0D\u53EF\u7528`))}function Rt(o){console.log(JSON.stringify({success:!1,error:o})),process.exit(1)}function z(o){return async(...t)=>{try{await o(...t)}catch(e){let r=e instanceof Error?e.message:String(e);Rt(r)}}}var se=new Set(["accessToken","refreshExpireIn"]);function uo(o){return o.map(t=>{let e={};for(let[r,n]of Object.entries(t))se.has(r)||(e[r]=n);return e})}function Et(){let o=new Nt("login");o.description("\u626B\u7801\u767B\u5F55 Round2AI \u8D26\u6237");let t=new Nt("qr").description("\u751F\u6210\u767B\u5F55\u4E8C\u7EF4\u7801\uFF08\u8FD4\u56DE JSON\uFF0C\u4F9B AI Agent \u4F7F\u7528\uFF09").action(z(async()=>{let r=v(),{qrData:n,...s}=await r.generateQR(),i=Number.parseInt(n.expireTime,10),c=Number.parseInt(n.pollInterval,10);console.log(JSON.stringify({qrToken:n.qrToken,expireTimeMs:i,pollIntervalMs:c,...s},null,2)),r.pollPageStatus(n.qrToken,i,c,s.setStatus).then(()=>{setTimeout(s.closeServer,3e3)}).catch(()=>{s.closeServer()})})),e=new Nt("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(z(async r=>{let s=await v().waitForLogin(r.token,Number.parseInt(r.expire,10),Number.parseInt(r.interval,10));console.log(JSON.stringify({success:!0,...s}))}));return o.addCommand(t),o.addCommand(e),o.action(async()=>{try{await v().login()}catch(r){m(r)}}),o}import{Command as ie}from"commander";function Ut(){let o=new ie("logout");return o.description("\u9000\u51FA\u767B\u5F55"),o.action(async()=>{try{await v().logout()}catch(t){m(t)}}),o}import{Command as ae}from"commander";function Dt(){let o=new ae("status");return o.description("\u67E5\u770B\u767B\u5F55\u72B6\u6001"),o.action(async()=>{try{await v().status()}catch(t){m(t)}}),o}import{Command as Ot}from"commander";function $t(){let o=new Ot("xianyu");o.description("\u95F2\u9C7C\u5E97\u94FA\u6388\u6743");let t=new Ot("qr").description("\u83B7\u53D6\u95F2\u9C7C\u6388\u6743\u4E8C\u7EF4\u7801\uFF08\u8FD4\u56DE JSON\uFF0C\u4F9B AI Agent \u4F7F\u7528\uFF09").action(z(async()=>{let{authData:r,...n}=await ct(),s=r.expireTime?Number.parseInt(r.expireTime,10):3e5,i=r.pollInterval?Number.parseInt(r.pollInterval,10):1e3;console.log(JSON.stringify({state:r.state,expireTimeMs:s,pollIntervalMs:i,...n},null,2)),mo(r.state,s,i,n.setStatus).then(()=>{setTimeout(n.closeServer,3e3)}).catch(()=>{n.closeServer()})})),e=new Ot("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(z(async r=>{let n=await lt(r.state,Number.parseInt(r.expire,10),Number.parseInt(r.interval,10));n.status==="success"?console.log(JSON.stringify({success:!0,shopId:n.shopId,shopName:n.shopName})):Rt(`\u6388\u6743\u72B6\u6001: ${n.status}`)}));return o.addCommand(t),o.addCommand(e),o.action(async()=>{try{await Lt()}catch(r){m(r)}}),o}import{Command as ce}from"commander";function po(){let o=new ce("analyze");return o.description("\u5206\u6790\u5546\u54C1\u4EF7\u683C\u5EFA\u8BAE"),o.option("--sku <sku>","\u5546\u54C1SKU"),o.option("--condition <condition>","\u5546\u54C1\u6210\u8272"),o.action(()=>g("pricing analyze")),o}import{Command as le}from"commander";function go(){let o=new le("generate");return o.description("\u751F\u6210\u7ECF\u8425\u62A5\u544A"),o.option("--type <type>","\u62A5\u544A\u7C7B\u578B: daily, weekly","daily"),o.action(()=>g("report generate")),o}import{Command as me}from"commander";function fo(){let o=new me("risk");return o.description("\u5E93\u5B58\u98CE\u9669\u8BC6\u522B"),o.option("--warehouse <warehouse>","\u4ED3\u5E93\u4EE3\u7801"),o.action(()=>g("inventory risk")),o}import{Command as de}from"commander";function ho(){let o=new de("chat");return o.description("\u4E0E AI \u52A9\u624B\u804A\u5929\uFF0C\u83B7\u53D6\u7ECF\u8425\u5EFA\u8BAE"),o.action(()=>g("ai chat")),o}import{Command as ue}from"commander";function yo(){let o=new ue("skills");return o.description("AI Agent \u6280\u80FD\u7BA1\u7406"),o.action(()=>g("ai skills")),o}import{Command as De}from"commander";import{Command as pe}from"commander";import k from"chalk";import{select as Jt,input as ge,confirm as fe}from"@inquirer/prompts";var R=new L;function Gt(o){let t=new URLSearchParams;for(let[e,r]of Object.entries(o))r!=null&&r!==""&&t.append(e,String(r));return t}async function Bt(o){return R.post("mms/goods/listing/up/xianyu",o)}async function wo(o){return R.get("mms/goods/listing/get",Gt({...o}))}async function jt(o){return R.post("mms/goods/listing/down/xianyu",o)}async function qt(o){return R.post("mms/goods/listing/update/xyPrice",o)}async function Qt(o){return R.get("mms/goods/listing/list",o?Gt({...o}):void 0)}async function mt(){return await R.get("mms/user/shop/list")??[]}async function dt(){return await R.get("mms/user/stock/list")??[]}async function Y(o){return R.get("mms/seller/goods/select/list",o?Gt({...o}):void 0)}var he=2e3,ye=1e4;function we(o){let t=o.status?.toLowerCase()??"";return t===""||t==="init"||t==="pending"||t==="processing"}async function xo(o,t,e,r){r||process.stdout.write(k.cyan("\u23F3 \u6B63\u5728\u67E5\u8BE2\u4E0A\u67B6\u8FDB\u5EA6..."));let n=await T(()=>wo({stockGoodsId:o,shopId:t,platform:e}),{interval:he,timeout:ye,condition:s=>!we(s)});return r||process.stdout.write("\r"+" ".repeat(30)+"\r"),n}function So(){let o=new pe("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(async t=>{try{if(t.stockGoodsId&&t.shopId&&t.price){let a=Number(t.stockGoodsId),C=t.shopId,gt=Number(t.price),q=t.platform,Qo=await Bt({stockGoodsId:a,shopId:C,price:gt,platform:q}),ft=await xo(a,C,q,t.json);if(t.json)console.log(JSON.stringify({success:!0,data:{submit:Qo,listing:ft}},null,2));else{let Jo=ft.status?.toLowerCase()!=="failed";console.log(Jo?k.green("\u2713 \u4E0A\u67B6\u6210\u529F"):k.red("\u2717 \u4E0A\u67B6\u5931\u8D25")),console.log(JSON.stringify(ft,null,2))}return}let e=await mt();if(e.length===0){console.log(k.yellow("\u6CA1\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF0C\u8BF7\u5148\u8FD0\u884C r2-cli auth xianyu \u6388\u6743"));return}let r=await Jt({message:"\u9009\u62E9\u5E97\u94FA",choices:e.map(a=>({name:`${a.shopName} (${a.platform})`,value:a.shopId}))}),n=await dt();if(n.length===0){console.log(k.yellow("\u6CA1\u6709\u53EF\u7528\u7684\u4ED3\u5E93"));return}let s=await Jt({message:"\u9009\u62E9\u4ED3\u5E93",choices:n.map(a=>({name:a.stockName,value:a.stockId}))}),i=await Y({stockId:s,size:100});if(!i.items?.length){console.log(k.yellow("\u8BE5\u4ED3\u5E93\u6CA1\u6709\u53EF\u9009\u7684\u5546\u54C1"));return}let c=await Jt({message:"\u9009\u62E9\u5546\u54C1",choices:i.items.map(a=>({name:`${a.goodsName} ${a.size?`| ${a.size}`:""} | \xA5${a.salePrice}`,value:a.stockGoodsId}))}),l=await ge({message:"\u8F93\u5165\u4E0A\u67B6\u4EF7\u683C",default:i.items.find(a=>a.stockGoodsId===c)?.salePrice?.toString()??"",validate:a=>Number(a)>0?!0:"\u4EF7\u683C\u5FC5\u987B\u4E3A\u6B63\u6570"});if(!await fe({message:`\u786E\u8BA4\u4E0A\u67B6\uFF1F\u4EF7\u683C \xA5${l}`,default:!0})){console.log(k.gray("\u5DF2\u53D6\u6D88"));return}let f=Number(c);await Bt({stockGoodsId:f,shopId:r,price:Number(l),platform:"xianyu"}),console.log(k.green("\u2713 \u4E0A\u67B6\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u67E5\u8BE2\u8FDB\u5EA6..."));let N=await xo(f,r,"xianyu"),E=N.status?.toLowerCase()!=="failed";console.log(E?k.green("\u2713 \u4E0A\u67B6\u6210\u529F"):k.red("\u2717 \u4E0A\u67B6\u5931\u8D25")),console.log(JSON.stringify(N,null,2))}catch(e){m(e)}}),o}import{Command as ke}from"commander";import Po from"chalk";function vo(){let o=new ke("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(async t=>{try{let e=await mt();if(t.json){console.log(JSON.stringify(uo(e),null,2));return}if(!e.length){console.log(Po.yellow("\u672A\u627E\u5230\u5DF2\u6388\u6743\u7684\u5E97\u94FA")),console.log(Po.gray(" \u63D0\u793A: \u8BF7\u5148\u5728\u7B2C\u4E8C\u56DE\u5408 APP \u4E2D\u6388\u6743\u5E97\u94FA"));return}let{ShopsTable:r}=await Promise.resolve().then(()=>(ko(),Io)),{renderComponent:n}=await Promise.resolve().then(()=>(it(),st));n(r,{shops:e,platform:"all"})}catch(e){m(e)}}),o}import{Command as be}from"commander";import Te from"chalk";function To(){let o=new be("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(async t=>{try{let e=await dt();if(t.json){console.log(JSON.stringify(e,null,2));return}if(!e.length){console.log(Te.yellow("\u672A\u627E\u5230\u4ED3\u5E93\u4FE1\u606F"));return}let{StocksTable:r}=await Promise.resolve().then(()=>(bo(),Ao)),{renderComponent:n}=await Promise.resolve().then(()=>(it(),st));n(r,{stocks:e})}catch(e){m(e)}}),o}import{Command as Le}from"commander";import j from"chalk";function Lo(){let o=new Le("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("--page <n>","\u9875\u7801","1").option("--size <n>","\u6BCF\u9875\u6570\u91CF","20").option("--json","\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09"),o.action(async t=>{if(t.json){try{let e=await Y({stockId:t.stockId??"",page:Number(t.page)||1,size:Number(t.size)||20});console.log(JSON.stringify(e??{items:[],total:0},null,2))}catch(e){let r=e instanceof Error?e.message:String(e);console.log(JSON.stringify({success:!1,error:r})),process.exit(1)}return}try{if(!t.stockId){console.log(j.yellow("\u8BF7\u6307\u5B9A\u4ED3\u5E93 ID: r2-cli goods list --stock-id <id>"));return}let e=await Y({stockId:t.stockId,page:Number(t.page)||1,size:Number(t.size)||20});if(!e.items?.length){console.log(j.yellow("\u8BE5\u4ED3\u5E93\u6CA1\u6709\u9009\u54C1\u5546\u54C1"));return}console.log(j.cyan(`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/components/UserInfoCard.tsx
|
|
14
|
+
var UserInfoCard_exports = {};
|
|
15
|
+
__export(UserInfoCard_exports, {
|
|
16
|
+
UserInfoCard: () => UserInfoCard
|
|
17
|
+
});
|
|
18
|
+
import { Box, Text } from "ink";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
function UserInfoCard({ userInfo, lastLogin, daysSinceLogin }) {
|
|
21
|
+
const maskedMobile = userInfo.mobile ? userInfo.mobile.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2") : "-";
|
|
22
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
|
|
23
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u7528\u6237\u4FE1\u606F" }),
|
|
24
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", marginTop: 1, children: [
|
|
25
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u6635\u79F0" }) }),
|
|
26
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: userInfo.nickname })
|
|
27
|
+
] }),
|
|
28
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
29
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u624B\u673A\u53F7" }) }),
|
|
30
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: maskedMobile })
|
|
31
|
+
] }),
|
|
32
|
+
lastLogin && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
33
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
34
|
+
"\u6700\u540E\u767B\u5F55: ",
|
|
35
|
+
lastLogin.toLocaleString()
|
|
36
|
+
] }),
|
|
37
|
+
daysSinceLogin !== void 0 && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
38
|
+
" \u8DDD\u4ECA: ",
|
|
39
|
+
daysSinceLogin,
|
|
40
|
+
" \u5929"
|
|
41
|
+
] })
|
|
42
|
+
] })
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
var init_UserInfoCard = __esm({
|
|
46
|
+
"src/components/UserInfoCard.tsx"() {
|
|
47
|
+
"use strict";
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// src/utils/render.tsx
|
|
52
|
+
var render_exports = {};
|
|
53
|
+
__export(render_exports, {
|
|
54
|
+
renderComponent: () => renderComponent,
|
|
55
|
+
renderOnce: () => renderOnce
|
|
56
|
+
});
|
|
57
|
+
import React from "react";
|
|
58
|
+
import chalk from "chalk";
|
|
59
|
+
import { render } from "ink";
|
|
60
|
+
import { Writable } from "node:stream";
|
|
61
|
+
function renderOnce(component) {
|
|
62
|
+
const prevLevel = chalk.level;
|
|
63
|
+
if (!process.env.NO_COLOR) {
|
|
64
|
+
chalk.level = 3;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const chunks = [];
|
|
68
|
+
const buffer = new Writable({
|
|
69
|
+
write(chunk, _, done) {
|
|
70
|
+
chunks.push(Buffer.from(chunk));
|
|
71
|
+
done();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
buffer.isTTY = true;
|
|
75
|
+
buffer.columns = process.stdout.columns || 80;
|
|
76
|
+
buffer.rows = process.stdout.rows || 24;
|
|
77
|
+
const instance4 = render(component, {
|
|
78
|
+
stdout: buffer,
|
|
79
|
+
patchConsole: false
|
|
80
|
+
});
|
|
81
|
+
instance4.unmount();
|
|
82
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
83
|
+
const lastRender = raw.split(/\x1B\[2J\x1B\[3J\x1B\[H/).at(-1) || raw;
|
|
84
|
+
const cleaned = lastRender.replace(/\x1B\[\?[\d;]+[hl]/g, "").trimEnd() + "\n";
|
|
85
|
+
process.stdout.write(cleaned);
|
|
86
|
+
} finally {
|
|
87
|
+
chalk.level = prevLevel;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function renderComponent(Component, props) {
|
|
91
|
+
renderOnce(React.createElement(Component, props));
|
|
92
|
+
}
|
|
93
|
+
var init_render = __esm({
|
|
94
|
+
"src/utils/render.tsx"() {
|
|
95
|
+
"use strict";
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// src/components/ShopsTable.tsx
|
|
100
|
+
var ShopsTable_exports = {};
|
|
101
|
+
__export(ShopsTable_exports, {
|
|
102
|
+
ShopsTable: () => ShopsTable
|
|
103
|
+
});
|
|
104
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
105
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
106
|
+
function normalizeShops(shops) {
|
|
107
|
+
return shops.map((s) => {
|
|
108
|
+
if ("shopName" in s) {
|
|
109
|
+
return {
|
|
110
|
+
id: s.shopId,
|
|
111
|
+
name: s.shopName,
|
|
112
|
+
platform: s.platform,
|
|
113
|
+
expiresIn: s.expiresIn
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
id: s.id,
|
|
118
|
+
name: s.name,
|
|
119
|
+
platform: s.thirdUserId,
|
|
120
|
+
expiresIn: s.expiresIn
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function Header({ hasPlatform, fillWidth }) {
|
|
125
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", paddingBottom: 0, children: [
|
|
126
|
+
hasPlatform && /* @__PURE__ */ jsx2(Box2, { width: COL_PLATFORM, children: /* @__PURE__ */ jsx2(Text2, { bold: true, color: "white", children: "\u5E73\u53F0" }) }),
|
|
127
|
+
/* @__PURE__ */ jsx2(Box2, { width: fillWidth, children: /* @__PURE__ */ jsx2(Text2, { bold: true, color: "white", children: "\u5E97\u94FA\u540D" }) }),
|
|
128
|
+
/* @__PURE__ */ jsx2(Box2, { width: COL_ID, children: /* @__PURE__ */ jsx2(Text2, { bold: true, color: "white", children: "ID" }) }),
|
|
129
|
+
/* @__PURE__ */ jsx2(Box2, { width: COL_STATUS, children: /* @__PURE__ */ jsx2(Text2, { bold: true, color: "white", children: "\u72B6\u6001" }) })
|
|
130
|
+
] });
|
|
131
|
+
}
|
|
132
|
+
function Row({ shop, hasPlatform, fillWidth }) {
|
|
133
|
+
const platformLabel = PLATFORM_LABELS[shop.platform] ?? shop.platform;
|
|
134
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
|
|
135
|
+
hasPlatform && /* @__PURE__ */ jsx2(Box2, { width: COL_PLATFORM, children: /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: platformLabel }) }),
|
|
136
|
+
/* @__PURE__ */ jsx2(Box2, { width: fillWidth, children: /* @__PURE__ */ jsx2(Text2, { bold: true, children: shop.name }) }),
|
|
137
|
+
/* @__PURE__ */ jsx2(Box2, { width: COL_ID, children: /* @__PURE__ */ jsx2(Text2, { color: "gray", children: shop.id }) }),
|
|
138
|
+
/* @__PURE__ */ jsx2(Box2, { width: COL_STATUS, children: /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u25CF \u6388\u6743\u4E2D" }) })
|
|
139
|
+
] });
|
|
140
|
+
}
|
|
141
|
+
function ShopsTable({ shops, platform }) {
|
|
142
|
+
const items = normalizeShops(shops);
|
|
143
|
+
const hasPlatform = platform === "all";
|
|
144
|
+
const title = platform === "all" ? "\u6240\u6709\u6388\u6743\u5E97\u94FA" : `${PLATFORM_LABELS[platform] ?? platform}\u6388\u6743\u5E97\u94FA`;
|
|
145
|
+
const termWidth = process.stdout.columns || 80;
|
|
146
|
+
const borderPadding = 4;
|
|
147
|
+
const fixedCols = COL_ID + COL_STATUS + (hasPlatform ? COL_PLATFORM : 0);
|
|
148
|
+
const fillWidth = Math.max(termWidth - borderPadding - fixedCols, 20);
|
|
149
|
+
const totalWidth = fixedCols + fillWidth;
|
|
150
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
|
|
151
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
|
|
152
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: title }),
|
|
153
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
|
|
154
|
+
" \xB7 ",
|
|
155
|
+
items.length,
|
|
156
|
+
" \u5BB6"
|
|
157
|
+
] })
|
|
158
|
+
] }),
|
|
159
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
160
|
+
/* @__PURE__ */ jsx2(Header, { hasPlatform, fillWidth }),
|
|
161
|
+
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "\u2500".repeat(totalWidth) }),
|
|
162
|
+
items.map((shop) => /* @__PURE__ */ jsx2(Row, { shop, hasPlatform, fillWidth }, shop.id))
|
|
163
|
+
] })
|
|
164
|
+
] });
|
|
165
|
+
}
|
|
166
|
+
var PLATFORM_LABELS, COL_PLATFORM, COL_ID, COL_STATUS;
|
|
167
|
+
var init_ShopsTable = __esm({
|
|
168
|
+
"src/components/ShopsTable.tsx"() {
|
|
169
|
+
"use strict";
|
|
170
|
+
PLATFORM_LABELS = {
|
|
171
|
+
xianyu: "\u95F2\u9C7C",
|
|
172
|
+
douyin: "\u6296\u97F3"
|
|
173
|
+
};
|
|
174
|
+
COL_PLATFORM = 8;
|
|
175
|
+
COL_ID = 16;
|
|
176
|
+
COL_STATUS = 10;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// src/components/StocksTable.tsx
|
|
181
|
+
var StocksTable_exports = {};
|
|
182
|
+
__export(StocksTable_exports, {
|
|
183
|
+
StocksTable: () => StocksTable
|
|
184
|
+
});
|
|
185
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
186
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
187
|
+
function Header2({ fillWidth }) {
|
|
188
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", paddingBottom: 0, children: [
|
|
189
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_ID2, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "white", children: "ID" }) }),
|
|
190
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_USER_ID, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "white", children: "\u7528\u6237ID" }) }),
|
|
191
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_STOCK_ID, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "white", children: "\u4ED3\u5E93ID" }) }),
|
|
192
|
+
/* @__PURE__ */ jsx3(Box3, { width: fillWidth, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "white", children: "\u4ED3\u5E93\u540D\u79F0" }) }),
|
|
193
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_TIME, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "white", children: "\u521B\u5EFA\u65F6\u95F4" }) })
|
|
194
|
+
] });
|
|
195
|
+
}
|
|
196
|
+
function Row2({ stock, fillWidth }) {
|
|
197
|
+
const created = new Date(stock.gmtCreate).toLocaleString("zh-CN");
|
|
198
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", children: [
|
|
199
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_ID2, children: /* @__PURE__ */ jsx3(Text3, { color: "gray", children: stock.id }) }),
|
|
200
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_USER_ID, children: /* @__PURE__ */ jsx3(Text3, { color: "gray", children: stock.userId }) }),
|
|
201
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_STOCK_ID, children: /* @__PURE__ */ jsx3(Text3, { color: "gray", children: stock.stockId }) }),
|
|
202
|
+
/* @__PURE__ */ jsx3(Box3, { width: fillWidth, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: stock.stockName }) }),
|
|
203
|
+
/* @__PURE__ */ jsx3(Box3, { width: COL_TIME, children: /* @__PURE__ */ jsx3(Text3, { color: "gray", children: created }) })
|
|
204
|
+
] });
|
|
205
|
+
}
|
|
206
|
+
function StocksTable({ stocks }) {
|
|
207
|
+
const termWidth = process.stdout.columns || 80;
|
|
208
|
+
const borderPadding = 4;
|
|
209
|
+
const fixedCols = COL_ID2 + COL_USER_ID + COL_STOCK_ID + COL_TIME;
|
|
210
|
+
const fillWidth = Math.max(termWidth - borderPadding - fixedCols, 20);
|
|
211
|
+
const totalWidth = fixedCols + fillWidth;
|
|
212
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
|
|
213
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", children: [
|
|
214
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "\u4ED3\u5E93\u5217\u8868" }),
|
|
215
|
+
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
216
|
+
" \xB7 ",
|
|
217
|
+
stocks.length,
|
|
218
|
+
" \u4E2A"
|
|
219
|
+
] })
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
222
|
+
/* @__PURE__ */ jsx3(Header2, { fillWidth }),
|
|
223
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "\u2500".repeat(totalWidth) }),
|
|
224
|
+
stocks.map((stock) => /* @__PURE__ */ jsx3(Row2, { stock, fillWidth }, stock.id))
|
|
225
|
+
] })
|
|
226
|
+
] });
|
|
227
|
+
}
|
|
228
|
+
var COL_ID2, COL_USER_ID, COL_STOCK_ID, COL_TIME;
|
|
229
|
+
var init_StocksTable = __esm({
|
|
230
|
+
"src/components/StocksTable.tsx"() {
|
|
231
|
+
"use strict";
|
|
232
|
+
COL_ID2 = 6;
|
|
233
|
+
COL_USER_ID = 10;
|
|
234
|
+
COL_STOCK_ID = 10;
|
|
235
|
+
COL_TIME = 22;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// src/entrypoints/r2-cli.tsx
|
|
240
|
+
import { Command as Command15 } from "commander";
|
|
241
|
+
import { readFileSync } from "node:fs";
|
|
242
|
+
import path4 from "node:path";
|
|
243
|
+
import chalk14 from "chalk";
|
|
244
|
+
|
|
245
|
+
// src/commands/setup.ts
|
|
246
|
+
import "commander";
|
|
247
|
+
|
|
248
|
+
// src/commands/auth/login.ts
|
|
249
|
+
import { Command } from "commander";
|
|
250
|
+
|
|
251
|
+
// src/services/auth/login.ts
|
|
252
|
+
import chalk2 from "chalk";
|
|
253
|
+
|
|
254
|
+
// src/errors/index.ts
|
|
255
|
+
var R2Error = class _R2Error extends Error {
|
|
256
|
+
constructor(message, code, details) {
|
|
257
|
+
super(message);
|
|
258
|
+
this.code = code;
|
|
259
|
+
this.details = details;
|
|
260
|
+
this.name = "R2Error";
|
|
261
|
+
if (Error.captureStackTrace) {
|
|
262
|
+
Error.captureStackTrace(this, _R2Error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
code;
|
|
266
|
+
details;
|
|
267
|
+
};
|
|
268
|
+
var ApiError = class extends R2Error {
|
|
269
|
+
constructor(message, status, response) {
|
|
270
|
+
super(message, "API_ERROR", response);
|
|
271
|
+
this.status = status;
|
|
272
|
+
this.response = response;
|
|
273
|
+
this.name = "ApiError";
|
|
274
|
+
}
|
|
275
|
+
status;
|
|
276
|
+
response;
|
|
277
|
+
};
|
|
278
|
+
var StorageError = class extends R2Error {
|
|
279
|
+
constructor(message, path5, code) {
|
|
280
|
+
super(message, "STORAGE_ERROR", { path: path5, code });
|
|
281
|
+
this.path = path5;
|
|
282
|
+
this.code = code;
|
|
283
|
+
this.name = "StorageError";
|
|
284
|
+
}
|
|
285
|
+
path;
|
|
286
|
+
code;
|
|
287
|
+
};
|
|
288
|
+
var AuthError = class extends R2Error {
|
|
289
|
+
constructor(message) {
|
|
290
|
+
super(message, "AUTH_ERROR");
|
|
291
|
+
this.name = "AuthError";
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
var PollingError = class extends R2Error {
|
|
295
|
+
constructor(message, attempts, timeout) {
|
|
296
|
+
super(message, "POLLING_ERROR", { attempts, timeout });
|
|
297
|
+
this.attempts = attempts;
|
|
298
|
+
this.timeout = timeout;
|
|
299
|
+
this.name = "PollingError";
|
|
300
|
+
}
|
|
301
|
+
attempts;
|
|
302
|
+
timeout;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/utils/polling.ts
|
|
306
|
+
async function callWithTimeout(fn, ms, parentSignal) {
|
|
307
|
+
const controller = new AbortController();
|
|
308
|
+
const onParentAbort = () => controller.abort();
|
|
309
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
310
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
311
|
+
try {
|
|
312
|
+
return await fn();
|
|
313
|
+
} catch (error) {
|
|
314
|
+
if (controller.signal.aborted && !parentSignal?.aborted) {
|
|
315
|
+
throw new PollingError("\u5355\u6B21\u8F6E\u8BE2\u8BF7\u6C42\u8D85\u65F6");
|
|
316
|
+
}
|
|
317
|
+
throw error;
|
|
318
|
+
} finally {
|
|
319
|
+
clearTimeout(timer);
|
|
320
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function poll(fn, options, signal) {
|
|
324
|
+
const { interval, timeout, condition } = options;
|
|
325
|
+
const startTime = Date.now();
|
|
326
|
+
let attempts = 0;
|
|
327
|
+
while (Date.now() - startTime < timeout) {
|
|
328
|
+
if (signal?.aborted) {
|
|
329
|
+
throw new PollingError("\u8F6E\u8BE2\u88AB\u4E2D\u6B62");
|
|
330
|
+
}
|
|
331
|
+
attempts++;
|
|
332
|
+
const remaining = timeout - (Date.now() - startTime);
|
|
333
|
+
const data = await callWithTimeout(fn, remaining, signal);
|
|
334
|
+
if (condition(data, attempts)) {
|
|
335
|
+
return data;
|
|
336
|
+
}
|
|
337
|
+
await sleep(interval, signal);
|
|
338
|
+
}
|
|
339
|
+
throw new PollingError(`\u8F6E\u8BE2\u8D85\u65F6 (\u5DF2\u7B49\u5F85 ${Date.now() - startTime}ms, \u5171 ${attempts} \u6B21)`);
|
|
340
|
+
}
|
|
341
|
+
function sleep(ms, signal) {
|
|
342
|
+
return new Promise((resolve, reject) => {
|
|
343
|
+
if (signal?.aborted) {
|
|
344
|
+
reject(new PollingError("\u8F6E\u8BE2\u88AB\u4E2D\u6B62"));
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const onAbort = () => {
|
|
348
|
+
clearTimeout(timer);
|
|
349
|
+
reject(new PollingError("\u8F6E\u8BE2\u88AB\u4E2D\u6B62"));
|
|
350
|
+
};
|
|
351
|
+
const timer = setTimeout(() => {
|
|
352
|
+
signal?.removeEventListener("abort", onAbort);
|
|
353
|
+
resolve();
|
|
354
|
+
}, ms);
|
|
355
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/qr-server/render.ts
|
|
360
|
+
import fs from "node:fs";
|
|
361
|
+
import { fileURLToPath } from "node:url";
|
|
362
|
+
import { createRequire } from "node:module";
|
|
363
|
+
import path from "node:path";
|
|
364
|
+
import { exec } from "node:child_process";
|
|
365
|
+
|
|
366
|
+
// src/qr-server/server.ts
|
|
367
|
+
import http from "node:http";
|
|
368
|
+
var QrServer = class _QrServer {
|
|
369
|
+
server = null;
|
|
370
|
+
pages = /* @__PURE__ */ new Map();
|
|
371
|
+
port = 0;
|
|
372
|
+
idleTimer = null;
|
|
373
|
+
static IDLE_TIMEOUT_MS = 1e4;
|
|
374
|
+
async start() {
|
|
375
|
+
if (this.server) return this.port;
|
|
376
|
+
return new Promise((resolve, reject) => {
|
|
377
|
+
this.server = http.createServer((req, res) => this.handleRequest(req, res));
|
|
378
|
+
this.server.listen(0, "127.0.0.1", () => {
|
|
379
|
+
const addr = this.server.address();
|
|
380
|
+
if (typeof addr === "object" && addr) {
|
|
381
|
+
this.port = addr.port;
|
|
382
|
+
resolve(this.port);
|
|
383
|
+
} else {
|
|
384
|
+
reject(new Error("Failed to get server address"));
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
this.server.on("error", reject);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
registerPage(route, html, qrBuffer, config) {
|
|
391
|
+
const existing = this.pages.get(route);
|
|
392
|
+
if (existing) {
|
|
393
|
+
existing.qrBuffer = qrBuffer;
|
|
394
|
+
existing.status = "waiting";
|
|
395
|
+
existing.config = config;
|
|
396
|
+
const payload = `data: ${JSON.stringify({ status: "waiting" })}
|
|
397
|
+
|
|
398
|
+
`;
|
|
399
|
+
for (const client4 of existing.sseClients) client4.write(payload);
|
|
400
|
+
} else {
|
|
401
|
+
this.pages.set(route, { html, qrBuffer, status: "waiting", sseClients: [], config });
|
|
402
|
+
}
|
|
403
|
+
this.resetIdleTimer();
|
|
404
|
+
}
|
|
405
|
+
unregisterPage(route) {
|
|
406
|
+
const page = this.pages.get(route);
|
|
407
|
+
if (!page) return;
|
|
408
|
+
for (const client4 of page.sseClients) client4.end();
|
|
409
|
+
page.sseClients.length = 0;
|
|
410
|
+
this.pages.delete(route);
|
|
411
|
+
if (this.pages.size === 0) this.close();
|
|
412
|
+
}
|
|
413
|
+
setStatus(route, status) {
|
|
414
|
+
const page = this.pages.get(route);
|
|
415
|
+
if (!page) return;
|
|
416
|
+
page.status = status;
|
|
417
|
+
const payload = `data: ${JSON.stringify({ status })}
|
|
418
|
+
|
|
419
|
+
`;
|
|
420
|
+
for (const client4 of page.sseClients) client4.write(payload);
|
|
421
|
+
}
|
|
422
|
+
close() {
|
|
423
|
+
if (!this.server) return;
|
|
424
|
+
if (this.idleTimer) {
|
|
425
|
+
clearTimeout(this.idleTimer);
|
|
426
|
+
this.idleTimer = null;
|
|
427
|
+
}
|
|
428
|
+
for (const page of this.pages.values()) {
|
|
429
|
+
for (const client4 of page.sseClients) client4.end();
|
|
430
|
+
page.sseClients.length = 0;
|
|
431
|
+
}
|
|
432
|
+
this.pages.clear();
|
|
433
|
+
this.server.close();
|
|
434
|
+
this.server = null;
|
|
435
|
+
this.port = 0;
|
|
436
|
+
instance = null;
|
|
437
|
+
}
|
|
438
|
+
resetIdleTimer() {
|
|
439
|
+
if (this.idleTimer) clearTimeout(this.idleTimer);
|
|
440
|
+
this.idleTimer = setTimeout(() => {
|
|
441
|
+
const hasClients = [...this.pages.values()].some((p) => p.sseClients.length > 0);
|
|
442
|
+
if (!hasClients) this.close();
|
|
443
|
+
}, _QrServer.IDLE_TIMEOUT_MS);
|
|
444
|
+
}
|
|
445
|
+
handleRequest(req, res) {
|
|
446
|
+
const url = req.url ?? "/";
|
|
447
|
+
for (const [route, page] of this.pages) {
|
|
448
|
+
if (url === route) {
|
|
449
|
+
res.writeHead(302, { Location: route + "/" });
|
|
450
|
+
res.end();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (url === route + "/") {
|
|
454
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
455
|
+
res.end(page.html);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (url === route + "/qr.png") {
|
|
459
|
+
res.writeHead(200, { "Content-Type": "image/png", "Content-Length": page.qrBuffer.length });
|
|
460
|
+
res.end(page.qrBuffer);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (url === route + "/events") {
|
|
464
|
+
res.writeHead(200, {
|
|
465
|
+
"Content-Type": "text/event-stream",
|
|
466
|
+
"Cache-Control": "no-cache",
|
|
467
|
+
Connection: "keep-alive"
|
|
468
|
+
});
|
|
469
|
+
res.write(`data: ${JSON.stringify({ status: page.status })}
|
|
470
|
+
|
|
471
|
+
`);
|
|
472
|
+
page.sseClients.push(res);
|
|
473
|
+
req.on("close", () => {
|
|
474
|
+
const idx = page.sseClients.indexOf(res);
|
|
475
|
+
if (idx >= 0) page.sseClients.splice(idx, 1);
|
|
476
|
+
});
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (url === route + "/config") {
|
|
480
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
481
|
+
res.end(JSON.stringify(page.config ?? {}));
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
486
|
+
res.end("Not Found");
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
var instance = null;
|
|
490
|
+
var listenersRegistered = false;
|
|
491
|
+
function cleanup() {
|
|
492
|
+
if (instance) instance.close();
|
|
493
|
+
}
|
|
494
|
+
function ensureProcessListeners() {
|
|
495
|
+
if (listenersRegistered) return;
|
|
496
|
+
listenersRegistered = true;
|
|
497
|
+
process.on("exit", cleanup);
|
|
498
|
+
process.on("SIGINT", cleanup);
|
|
499
|
+
process.on("SIGTERM", cleanup);
|
|
500
|
+
setInterval(() => {
|
|
501
|
+
if (process.stdin?.destroyed) cleanup();
|
|
502
|
+
}, 3e3).unref();
|
|
503
|
+
}
|
|
504
|
+
function getQrServer() {
|
|
505
|
+
if (!instance) {
|
|
506
|
+
instance = new QrServer();
|
|
507
|
+
ensureProcessListeners();
|
|
508
|
+
}
|
|
509
|
+
return instance;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/qr-server/render.ts
|
|
513
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
514
|
+
var LOGIN_ROUTE = "/login";
|
|
515
|
+
var XIANYU_ROUTE = "/login-xianyu";
|
|
516
|
+
var _require = null;
|
|
517
|
+
async function loadHtml(filename) {
|
|
518
|
+
return fs.promises.readFile(path.join(__dirname, "pages", filename), "utf-8");
|
|
519
|
+
}
|
|
520
|
+
async function generateQRBuffer(content) {
|
|
521
|
+
if (!_require) _require = createRequire(import.meta.url);
|
|
522
|
+
const QRCodeLib = _require("qrcode");
|
|
523
|
+
return QRCodeLib.toBuffer(content, { width: 300, margin: 2 });
|
|
524
|
+
}
|
|
525
|
+
function openUrl(url) {
|
|
526
|
+
const cmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
527
|
+
exec(cmd);
|
|
528
|
+
}
|
|
529
|
+
async function renderQRPage(route, htmlFile, content, config) {
|
|
530
|
+
const [html, qrBuffer] = await Promise.all([
|
|
531
|
+
loadHtml(htmlFile),
|
|
532
|
+
generateQRBuffer(content)
|
|
533
|
+
]);
|
|
534
|
+
const server = getQrServer();
|
|
535
|
+
const port = await server.start();
|
|
536
|
+
server.registerPage(route, html, qrBuffer, config);
|
|
537
|
+
const qrUrl = `http://127.0.0.1:${port}${route}/`;
|
|
538
|
+
return {
|
|
539
|
+
url: content,
|
|
540
|
+
qrUrl,
|
|
541
|
+
setStatus: (status) => server.setStatus(route, status),
|
|
542
|
+
closeServer: () => server.unregisterPage(route)
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function renderLoginQR(content) {
|
|
546
|
+
return renderQRPage(LOGIN_ROUTE, "login.html", content);
|
|
547
|
+
}
|
|
548
|
+
function renderXianyuAuthQR(content, authUrl) {
|
|
549
|
+
return renderQRPage(XIANYU_ROUTE, "xianyu-auth.html", content, { authUrl });
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/services/storage/config-store.ts
|
|
553
|
+
import { promises as fs2 } from "node:fs";
|
|
554
|
+
import path2 from "node:path";
|
|
555
|
+
import os from "node:os";
|
|
556
|
+
var CONFIG_FILE_NAME = ".r2-cli";
|
|
557
|
+
var ConfigStore = class {
|
|
558
|
+
configPath;
|
|
559
|
+
config;
|
|
560
|
+
configLoaded = false;
|
|
561
|
+
dirEnsured = false;
|
|
562
|
+
constructor() {
|
|
563
|
+
const homeDir = os.homedir();
|
|
564
|
+
const configDir = path2.join(homeDir, CONFIG_FILE_NAME);
|
|
565
|
+
this.configPath = path2.join(configDir, "config.json");
|
|
566
|
+
this.config = { credentials: null };
|
|
567
|
+
}
|
|
568
|
+
getConfigPath() {
|
|
569
|
+
return this.configPath;
|
|
570
|
+
}
|
|
571
|
+
async loadConfig() {
|
|
572
|
+
if (this.configLoaded) return this.config;
|
|
573
|
+
try {
|
|
574
|
+
const content = await fs2.readFile(this.configPath, "utf-8");
|
|
575
|
+
this.config = JSON.parse(content);
|
|
576
|
+
this.configLoaded = true;
|
|
577
|
+
return this.config;
|
|
578
|
+
} catch {
|
|
579
|
+
this.config = { credentials: null };
|
|
580
|
+
this.configLoaded = true;
|
|
581
|
+
return this.config;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
async ensureDir() {
|
|
585
|
+
if (this.dirEnsured) return;
|
|
586
|
+
const dirPath = path2.dirname(this.configPath);
|
|
587
|
+
try {
|
|
588
|
+
await fs2.stat(dirPath);
|
|
589
|
+
} catch (error) {
|
|
590
|
+
if (error.code === "ENOENT") {
|
|
591
|
+
await fs2.mkdir(dirPath, { recursive: true });
|
|
592
|
+
} else {
|
|
593
|
+
throw new StorageError("Failed to create directory", dirPath, error.code);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
this.dirEnsured = true;
|
|
597
|
+
}
|
|
598
|
+
async saveConfig(config) {
|
|
599
|
+
this.config = config;
|
|
600
|
+
await this.ensureDir();
|
|
601
|
+
const content = JSON.stringify(config, null, 2);
|
|
602
|
+
const tmpPath = this.configPath + ".tmp";
|
|
603
|
+
try {
|
|
604
|
+
await fs2.writeFile(tmpPath, content, "utf-8");
|
|
605
|
+
await fs2.rename(tmpPath, this.configPath);
|
|
606
|
+
this.configLoaded = true;
|
|
607
|
+
} catch (error) {
|
|
608
|
+
await fs2.unlink(tmpPath).catch((e) => {
|
|
609
|
+
if (typeof process.env.DEBUG !== "undefined") console.error("[config] cleanup tmp failed:", e);
|
|
610
|
+
});
|
|
611
|
+
throw new StorageError("Failed to save config", this.configPath, error.code);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
var instance2 = null;
|
|
616
|
+
function getConfigStore() {
|
|
617
|
+
if (!instance2) instance2 = new ConfigStore();
|
|
618
|
+
return instance2;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// src/services/storage/auth-storage.ts
|
|
622
|
+
var TOKEN_EXPIRY_MARGIN_MS = 5 * 60 * 1e3;
|
|
623
|
+
var AuthStorage = class {
|
|
624
|
+
store = getConfigStore();
|
|
625
|
+
isTokenExpired(cred) {
|
|
626
|
+
if (!cred.expire) return false;
|
|
627
|
+
return Date.now() >= cred.expire - TOKEN_EXPIRY_MARGIN_MS;
|
|
628
|
+
}
|
|
629
|
+
async saveCredentials(token, userInfo) {
|
|
630
|
+
const now = Date.now();
|
|
631
|
+
const durationMs = userInfo.expire ? Number.parseInt(userInfo.expire, 10) : 0;
|
|
632
|
+
const credentials = {
|
|
633
|
+
token,
|
|
634
|
+
userInfo,
|
|
635
|
+
timestamp: now,
|
|
636
|
+
...durationMs > 0 && { expire: now + durationMs }
|
|
637
|
+
};
|
|
638
|
+
let config = await this.store.loadConfig();
|
|
639
|
+
config.credentials = credentials;
|
|
640
|
+
await this.store.saveConfig(config);
|
|
641
|
+
}
|
|
642
|
+
async getCredentials() {
|
|
643
|
+
const config = await this.store.loadConfig();
|
|
644
|
+
if (!config.credentials) return null;
|
|
645
|
+
if (this.isTokenExpired(config.credentials)) return null;
|
|
646
|
+
return config.credentials;
|
|
647
|
+
}
|
|
648
|
+
async clearCredentials() {
|
|
649
|
+
const config = await this.store.loadConfig();
|
|
650
|
+
config.credentials = null;
|
|
651
|
+
await this.store.saveConfig(config);
|
|
652
|
+
}
|
|
653
|
+
async getToken() {
|
|
654
|
+
const credentials = await this.getCredentials();
|
|
655
|
+
return credentials?.token ?? null;
|
|
656
|
+
}
|
|
657
|
+
async getUserInfo() {
|
|
658
|
+
const credentials = await this.getCredentials();
|
|
659
|
+
return credentials?.userInfo ?? null;
|
|
660
|
+
}
|
|
661
|
+
async isLoggedIn() {
|
|
662
|
+
const credentials = await this.getCredentials();
|
|
663
|
+
return credentials !== null;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var instance3 = null;
|
|
667
|
+
function getAuthStorage() {
|
|
668
|
+
if (!instance3) instance3 = new AuthStorage();
|
|
669
|
+
return instance3;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/services/api/client.ts
|
|
673
|
+
var SERVER_BASEURL = "https://api.qiuxietang.com";
|
|
674
|
+
var ApiClientService = class {
|
|
675
|
+
config;
|
|
676
|
+
authStorage = null;
|
|
677
|
+
cachedToken = null;
|
|
678
|
+
tokenExpiry = 0;
|
|
679
|
+
constructor(config = {}) {
|
|
680
|
+
this.config = {
|
|
681
|
+
baseUrl: config.baseUrl ?? SERVER_BASEURL,
|
|
682
|
+
version: config.version ?? "v3",
|
|
683
|
+
debug: config.debug ?? false
|
|
684
|
+
};
|
|
685
|
+
this.authStorage = config.auth === false ? null : getAuthStorage();
|
|
686
|
+
}
|
|
687
|
+
buildUrl(path5) {
|
|
688
|
+
const cleanPath = path5.startsWith("/") ? path5.slice(1) : path5;
|
|
689
|
+
return `${this.config.baseUrl}/${this.config.version}/${cleanPath}`;
|
|
690
|
+
}
|
|
691
|
+
async getAuthToken() {
|
|
692
|
+
if (!this.authStorage) return void 0;
|
|
693
|
+
if (this.cachedToken && Date.now() < this.tokenExpiry) return this.cachedToken;
|
|
694
|
+
const credentials = await this.authStorage.getCredentials();
|
|
695
|
+
if (!credentials) {
|
|
696
|
+
throw new AuthError("\u8BF7\u5148\u8FD0\u884C r2-cli auth login \u767B\u5F55");
|
|
697
|
+
}
|
|
698
|
+
this.cachedToken = credentials.token;
|
|
699
|
+
this.tokenExpiry = credentials.expire ? credentials.expire - TOKEN_EXPIRY_MARGIN_MS : Date.now() + 30 * 60 * 1e3;
|
|
700
|
+
return credentials.token;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* 发起请求,返回完整响应信封(含 token 等顶层字段)
|
|
704
|
+
*/
|
|
705
|
+
async requestFull(path5, reqConfig) {
|
|
706
|
+
const url = this.buildUrl(path5);
|
|
707
|
+
const { method, headers: rawHeaders, body, timeout = 3e4 } = reqConfig;
|
|
708
|
+
const token = await this.getAuthToken();
|
|
709
|
+
const headers = { ...rawHeaders, ...token ? { token } : {} };
|
|
710
|
+
const controller = new AbortController();
|
|
711
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
712
|
+
const init = {
|
|
713
|
+
method,
|
|
714
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
715
|
+
signal: controller.signal
|
|
716
|
+
};
|
|
717
|
+
if (body !== void 0) init.body = JSON.stringify(body);
|
|
718
|
+
if (this.config.debug) {
|
|
719
|
+
console.error(`[API ${method}]`, url, body);
|
|
720
|
+
}
|
|
721
|
+
try {
|
|
722
|
+
const response = await fetch(url, init);
|
|
723
|
+
if (!response.ok) {
|
|
724
|
+
if (response.status === 401) {
|
|
725
|
+
if (this.authStorage) {
|
|
726
|
+
this.cachedToken = null;
|
|
727
|
+
await this.authStorage.clearCredentials().catch((e) => {
|
|
728
|
+
console.error("[API] \u6E05\u9664\u51ED\u8BC1\u5931\u8D25:", e instanceof Error ? e.message : String(e));
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
throw new AuthError("\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8FD0\u884C r2-cli auth login \u91CD\u65B0\u767B\u5F55");
|
|
732
|
+
}
|
|
733
|
+
const errorText = await response.text();
|
|
734
|
+
throw new ApiError(errorText || `${response.status} ${response.statusText}`, response.status);
|
|
735
|
+
}
|
|
736
|
+
const result = await response.json();
|
|
737
|
+
if (this.config.debug) {
|
|
738
|
+
console.error("[API Response]", result);
|
|
739
|
+
}
|
|
740
|
+
if (!result.success || result.status !== 0) {
|
|
741
|
+
throw new ApiError(result.msg || "\u672A\u77E5\u9519\u8BEF", result.status, result);
|
|
742
|
+
}
|
|
743
|
+
return result;
|
|
744
|
+
} catch (error) {
|
|
745
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
746
|
+
throw new ApiError(`\u8BF7\u6C42\u8D85\u65F6 (${timeout}ms)`, 408);
|
|
747
|
+
}
|
|
748
|
+
throw error;
|
|
749
|
+
} finally {
|
|
750
|
+
clearTimeout(timer);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
async request(path5, config) {
|
|
754
|
+
const result = await this.requestFull(path5, config);
|
|
755
|
+
return result.data;
|
|
756
|
+
}
|
|
757
|
+
async get(path5, params, headers) {
|
|
758
|
+
const fullPath = params && params.size > 0 ? `${path5}?${params.toString()}` : path5;
|
|
759
|
+
return this.request(fullPath, { method: "GET", headers });
|
|
760
|
+
}
|
|
761
|
+
async post(path5, body, headers) {
|
|
762
|
+
return this.request(path5, { method: "POST", body, headers });
|
|
763
|
+
}
|
|
764
|
+
async put(path5, body, headers) {
|
|
765
|
+
return this.request(path5, { method: "PUT", body, headers });
|
|
766
|
+
}
|
|
767
|
+
async delete(path5, headers) {
|
|
768
|
+
return this.request(path5, { method: "DELETE", headers });
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
// src/services/api/modules/qrcode-auth.ts
|
|
773
|
+
var client = new ApiClientService({ auth: false });
|
|
774
|
+
async function generateQRCode() {
|
|
775
|
+
return client.post("app/qrcode/generate");
|
|
776
|
+
}
|
|
777
|
+
async function getQRCodeStatus(qrToken) {
|
|
778
|
+
const params = new URLSearchParams();
|
|
779
|
+
params.append("qrToken", qrToken);
|
|
780
|
+
const fullPath = `app/qrcode/status?${params.toString()}`;
|
|
781
|
+
const full = await client.requestFull(fullPath, { method: "GET" });
|
|
782
|
+
if (full.token && typeof full.data === "object" && full.data !== null) {
|
|
783
|
+
full.data.token = full.token;
|
|
784
|
+
}
|
|
785
|
+
return full.data;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// src/services/auth/login.ts
|
|
789
|
+
async function displayUserInfo(userInfo, lastLogin, daysSinceLogin) {
|
|
790
|
+
const { UserInfoCard: UserInfoCard2 } = await Promise.resolve().then(() => (init_UserInfoCard(), UserInfoCard_exports));
|
|
791
|
+
const { renderComponent: renderComponent2 } = await Promise.resolve().then(() => (init_render(), render_exports));
|
|
792
|
+
const props = lastLogin != null ? { userInfo, lastLogin, daysSinceLogin: daysSinceLogin ?? 0 } : { userInfo };
|
|
793
|
+
renderComponent2(UserInfoCard2, props);
|
|
794
|
+
}
|
|
795
|
+
var LoginService = class {
|
|
796
|
+
storage;
|
|
797
|
+
constructor(storage) {
|
|
798
|
+
this.storage = storage ?? getAuthStorage();
|
|
799
|
+
}
|
|
800
|
+
async generateQR() {
|
|
801
|
+
const qrData = await generateQRCode();
|
|
802
|
+
const qrContent = `https://m.puresnake.com/r2/auth/login?qrToken=${qrData.qrContent}&from=wechat`;
|
|
803
|
+
const rendered = await renderLoginQR(qrContent);
|
|
804
|
+
return { qrData, ...rendered };
|
|
805
|
+
}
|
|
806
|
+
async waitForLogin(qrToken, expireTimeMs, pollIntervalMs, signal, setStatus, silent) {
|
|
807
|
+
const result = await poll(
|
|
808
|
+
() => getQRCodeStatus(qrToken),
|
|
809
|
+
{
|
|
810
|
+
interval: pollIntervalMs,
|
|
811
|
+
timeout: expireTimeMs,
|
|
812
|
+
condition: (data) => {
|
|
813
|
+
switch (data.status) {
|
|
814
|
+
case "scanned":
|
|
815
|
+
if (!silent) {
|
|
816
|
+
console.log(chalk2.cyan(`
|
|
817
|
+
\u{1F50D} \u5DF2\u626B\u7801: ${data.userInfo?.nickname || "\u672A\u77E5\u7528\u6237"}`));
|
|
818
|
+
console.log(chalk2.yellow("\u8BF7\u5728 APP \u4E0A\u786E\u8BA4\u767B\u5F55"));
|
|
819
|
+
}
|
|
820
|
+
setStatus?.("scanning");
|
|
821
|
+
return false;
|
|
822
|
+
case "confirmed":
|
|
823
|
+
if (!silent) console.log(chalk2.green("\n\u2705 \u7528\u6237\u5DF2\u786E\u8BA4\u767B\u5F55"));
|
|
824
|
+
setStatus?.("success");
|
|
825
|
+
return true;
|
|
826
|
+
case "expired":
|
|
827
|
+
if (!silent) console.log(chalk2.red("\n\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F"));
|
|
828
|
+
setStatus?.("expired");
|
|
829
|
+
return true;
|
|
830
|
+
case "canceled":
|
|
831
|
+
if (!silent) console.log(chalk2.red("\n\u{1F6AB} \u7528\u6237\u5DF2\u53D6\u6D88\u767B\u5F55"));
|
|
832
|
+
setStatus?.("expired");
|
|
833
|
+
return true;
|
|
834
|
+
default:
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
},
|
|
839
|
+
signal ?? void 0
|
|
840
|
+
);
|
|
841
|
+
if (result.status === "confirmed" && result.token && result.userInfo) {
|
|
842
|
+
await this.storage.saveCredentials(result.token, result.userInfo);
|
|
843
|
+
return { userInfo: result.userInfo, token: result.token };
|
|
844
|
+
}
|
|
845
|
+
if (result.status === "expired") throw new AuthError("\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55");
|
|
846
|
+
if (result.status === "canceled") throw new AuthError("\u7528\u6237\u5DF2\u53D6\u6D88\u767B\u5F55");
|
|
847
|
+
throw new AuthError("\u767B\u5F55\u5931\u8D25: \u672A\u83B7\u53D6\u5230\u51ED\u8BC1");
|
|
848
|
+
}
|
|
849
|
+
async login(signal) {
|
|
850
|
+
console.log(chalk2.cyan("\n\u{1F510} \u6B63\u5728\u542F\u52A8\u626B\u7801\u767B\u5F55..."));
|
|
851
|
+
const { qrData, qrUrl, setStatus, closeServer } = await this.generateQR();
|
|
852
|
+
console.log(chalk2.green("\u2705 \u4E8C\u7EF4\u7801\u5DF2\u751F\u6210\n"));
|
|
853
|
+
console.log(chalk2.cyan(` \u94FE\u63A5: ${qrUrl}
|
|
854
|
+
`));
|
|
855
|
+
openUrl(qrUrl);
|
|
856
|
+
console.log(chalk2.yellow("\u23F3 \u7B49\u5F85\u626B\u7801...\n"));
|
|
857
|
+
const expireTimeMs = Number.parseInt(qrData.expireTime, 10);
|
|
858
|
+
const pollIntervalMs = Number.parseInt(qrData.pollInterval, 10);
|
|
859
|
+
try {
|
|
860
|
+
const result = await this.waitForLogin(qrData.qrToken, expireTimeMs, pollIntervalMs, signal, setStatus);
|
|
861
|
+
console.log(chalk2.green("\n\u2705 \u767B\u5F55\u6210\u529F\uFF01\n"));
|
|
862
|
+
displayUserInfo(result.userInfo);
|
|
863
|
+
return result;
|
|
864
|
+
} catch (error) {
|
|
865
|
+
console.log(chalk2.red("\n\u274C \u767B\u5F55\u5931\u8D25\n"));
|
|
866
|
+
throw error;
|
|
867
|
+
} finally {
|
|
868
|
+
closeServer();
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
async logout() {
|
|
872
|
+
console.log(chalk2.cyan("\n\u{1F6AA} \u6B63\u5728\u9000\u51FA\u767B\u5F55..."));
|
|
873
|
+
await this.storage.clearCredentials();
|
|
874
|
+
console.log(chalk2.green("\u2705 \u5DF2\u9000\u51FA\u767B\u5F55\n"));
|
|
875
|
+
}
|
|
876
|
+
async status() {
|
|
877
|
+
const isLoggedIn = await this.storage.isLoggedIn();
|
|
878
|
+
if (!isLoggedIn) {
|
|
879
|
+
console.log(chalk2.yellow("\u26A0\uFE0F \u5C1A\u672A\u767B\u5F55\u6216\u51ED\u8BC1\u5DF2\u8FC7\u671F\n"));
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
const credentials = await this.storage.getCredentials();
|
|
883
|
+
const userInfo = credentials.userInfo;
|
|
884
|
+
const lastLogin = new Date(credentials.timestamp);
|
|
885
|
+
const daysSinceLogin = Math.floor((Date.now() - credentials.timestamp) / (1e3 * 60 * 60 * 24));
|
|
886
|
+
console.log(chalk2.green("\u2705 \u5DF2\u767B\u5F55\n"));
|
|
887
|
+
await displayUserInfo(userInfo, lastLogin, daysSinceLogin);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
var loginInstance = null;
|
|
891
|
+
function getLoginService() {
|
|
892
|
+
if (!loginInstance) loginInstance = new LoginService();
|
|
893
|
+
return loginInstance;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// src/services/auth/xianyu-auth.ts
|
|
897
|
+
import chalk3 from "chalk";
|
|
898
|
+
|
|
899
|
+
// src/services/api/modules/xianyu-auth.ts
|
|
900
|
+
var client2 = new ApiClientService();
|
|
901
|
+
async function getAuthUrl() {
|
|
902
|
+
return client2.get("mms/xianyu/auth/url");
|
|
903
|
+
}
|
|
904
|
+
async function getAuthStatus(state) {
|
|
905
|
+
const params = new URLSearchParams({ state });
|
|
906
|
+
return client2.get("mms/xianyu/auth/status", params);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// src/services/auth/xianyu-auth.ts
|
|
910
|
+
async function generateAuthQR() {
|
|
911
|
+
const authData = await getAuthUrl();
|
|
912
|
+
const rendered = await renderXianyuAuthQR(authData.url, authData.url);
|
|
913
|
+
return { authData, ...rendered };
|
|
914
|
+
}
|
|
915
|
+
async function waitForAuth(state, expireMs, intervalMs, signal, setStatus) {
|
|
916
|
+
return poll(
|
|
917
|
+
() => getAuthStatus(state),
|
|
918
|
+
{
|
|
919
|
+
interval: intervalMs,
|
|
920
|
+
timeout: expireMs,
|
|
921
|
+
condition: (data) => {
|
|
922
|
+
if (data.status === "success") {
|
|
923
|
+
console.log(chalk3.green(`
|
|
924
|
+
\u2705 \u6388\u6743\u6210\u529F\uFF01\u5E97\u94FA: ${data.shopName} (${data.shopId})`));
|
|
925
|
+
setStatus?.("success");
|
|
926
|
+
return true;
|
|
927
|
+
}
|
|
928
|
+
if (data.status === "expired") {
|
|
929
|
+
console.log(chalk3.red("\n\u23F0 \u6388\u6743\u94FE\u63A5\u5DF2\u8FC7\u671F"));
|
|
930
|
+
setStatus?.("expired");
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
return false;
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
signal
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
async function authorize(signal) {
|
|
940
|
+
console.log(chalk3.cyan("\n\u{1F517} \u6B63\u5728\u83B7\u53D6\u95F2\u9C7C\u6388\u6743\u5730\u5740..."));
|
|
941
|
+
const { authData, qrUrl, setStatus, closeServer } = await generateAuthQR();
|
|
942
|
+
console.log(chalk3.green("\u2705 \u6388\u6743\u4E8C\u7EF4\u7801\u5DF2\u751F\u6210\n"));
|
|
943
|
+
console.log(chalk3.cyan(` \u94FE\u63A5: ${qrUrl}`));
|
|
944
|
+
console.log(chalk3.gray(` \u6216\u590D\u5236\u94FE\u63A5\u6253\u5F00: ${authData.url}`));
|
|
945
|
+
openUrl(qrUrl);
|
|
946
|
+
console.log(chalk3.yellow("\n\u23F3 \u7B49\u5F85\u6388\u6743...\n"));
|
|
947
|
+
const expireMs = authData.expireTime ? Number.parseInt(authData.expireTime, 10) : 3e5;
|
|
948
|
+
const intervalMs = authData.pollInterval ? Number.parseInt(authData.pollInterval, 10) : 1e3;
|
|
949
|
+
try {
|
|
950
|
+
const result = await waitForAuth(authData.state, expireMs, intervalMs, signal, setStatus);
|
|
951
|
+
if (result.status === "success") return result;
|
|
952
|
+
throw new AuthError("\u95F2\u9C7C\u6388\u6743\u5931\u8D25: " + (result.status === "expired" ? "\u94FE\u63A5\u5DF2\u8FC7\u671F" : "\u672A\u77E5\u72B6\u6001"));
|
|
953
|
+
} finally {
|
|
954
|
+
closeServer();
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// src/commands/shared.ts
|
|
959
|
+
import chalk4 from "chalk";
|
|
960
|
+
function handleCommandError(error) {
|
|
961
|
+
if (error instanceof AuthError) {
|
|
962
|
+
console.error(chalk4.red(`
|
|
963
|
+
\u25B2 ${error.message}`));
|
|
964
|
+
console.error(chalk4.gray(`\u2192 \u8BF7\u5148\u8FD0\u884C: r2-cli auth login
|
|
965
|
+
`));
|
|
966
|
+
} else if (error instanceof ApiError) {
|
|
967
|
+
console.error(chalk4.red(`\u25B2 \u64CD\u4F5C\u5931\u8D25: ${error.message}`));
|
|
968
|
+
if (error.status) {
|
|
969
|
+
console.error(chalk4.gray(` \u72B6\u6001\u7801: ${error.status}`));
|
|
970
|
+
}
|
|
971
|
+
} else if (error instanceof StorageError) {
|
|
972
|
+
console.error(chalk4.red(`\u25B2 \u914D\u7F6E\u6587\u4EF6\u5F02\u5E38: ${error.message}`));
|
|
973
|
+
if (error.path) console.error(chalk4.gray(` \u8DEF\u5F84: ${error.path}`));
|
|
974
|
+
console.error(chalk4.gray(`\u2192 \u8BF7\u5C1D\u8BD5\u91CD\u65B0\u767B\u5F55: r2-cli auth login
|
|
975
|
+
`));
|
|
976
|
+
} else {
|
|
977
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
978
|
+
console.error(chalk4.red(`\u25B2 ${msg}`));
|
|
979
|
+
}
|
|
980
|
+
process.exit(1);
|
|
981
|
+
}
|
|
982
|
+
function agentError(msg) {
|
|
983
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
984
|
+
process.exit(1);
|
|
985
|
+
}
|
|
986
|
+
function agentAction(fn) {
|
|
987
|
+
return async (...args) => {
|
|
988
|
+
try {
|
|
989
|
+
await fn(...args);
|
|
990
|
+
} catch (error) {
|
|
991
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
992
|
+
agentError(msg);
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
var SENSITIVE_KEYS = /* @__PURE__ */ new Set(["accessToken", "refreshExpireIn"]);
|
|
997
|
+
function sanitizeShops(shops) {
|
|
998
|
+
return shops.map((shop) => {
|
|
999
|
+
const safe = {};
|
|
1000
|
+
for (const [key, value] of Object.entries(shop)) {
|
|
1001
|
+
if (!SENSITIVE_KEYS.has(key)) safe[key] = value;
|
|
1002
|
+
}
|
|
1003
|
+
return safe;
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// src/commands/auth/login.ts
|
|
1008
|
+
function createLoginCommand() {
|
|
1009
|
+
const command = new Command("login");
|
|
1010
|
+
command.description("\u626B\u7801\u767B\u5F55 Round2AI \u8D26\u6237").option("--json", "\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");
|
|
1011
|
+
const pollCmd = new Command("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(agentAction(async (options) => {
|
|
1012
|
+
const service = getLoginService();
|
|
1013
|
+
const result = await service.waitForLogin(
|
|
1014
|
+
options.token,
|
|
1015
|
+
Number.parseInt(options.expire, 10),
|
|
1016
|
+
Number.parseInt(options.interval, 10)
|
|
1017
|
+
);
|
|
1018
|
+
console.log(JSON.stringify({ success: true, ...result }));
|
|
1019
|
+
}));
|
|
1020
|
+
command.addCommand(pollCmd);
|
|
1021
|
+
command.action(async (options) => {
|
|
1022
|
+
try {
|
|
1023
|
+
if (options.json) {
|
|
1024
|
+
const service = getLoginService();
|
|
1025
|
+
const { qrData, qrUrl, setStatus, closeServer } = await service.generateQR();
|
|
1026
|
+
const expireMs = Number.parseInt(qrData.expireTime, 10);
|
|
1027
|
+
const intervalMs = Number.parseInt(qrData.pollInterval, 10);
|
|
1028
|
+
console.log(JSON.stringify({
|
|
1029
|
+
qrToken: qrData.qrToken,
|
|
1030
|
+
expireTimeMs: expireMs,
|
|
1031
|
+
pollIntervalMs: intervalMs,
|
|
1032
|
+
url: `https://m.puresnake.com/r2/auth/login?qrToken=${qrData.qrContent}&from=wechat`,
|
|
1033
|
+
qrUrl
|
|
1034
|
+
}, null, 2));
|
|
1035
|
+
openUrl(qrUrl);
|
|
1036
|
+
try {
|
|
1037
|
+
const result = await service.waitForLogin(qrData.qrToken, expireMs, intervalMs, void 0, setStatus, true);
|
|
1038
|
+
console.log(JSON.stringify({ success: true, userInfo: result.userInfo }));
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1041
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1042
|
+
} finally {
|
|
1043
|
+
setTimeout(closeServer, 1e3);
|
|
1044
|
+
}
|
|
1045
|
+
} else {
|
|
1046
|
+
await getLoginService().login();
|
|
1047
|
+
}
|
|
1048
|
+
} catch (error) {
|
|
1049
|
+
if (options.json) {
|
|
1050
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1051
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1052
|
+
process.exit(1);
|
|
1053
|
+
}
|
|
1054
|
+
handleCommandError(error);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
return command;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// src/commands/auth/logout.ts
|
|
1061
|
+
import { Command as Command2 } from "commander";
|
|
1062
|
+
function createLogoutCommand() {
|
|
1063
|
+
const command = new Command2("logout");
|
|
1064
|
+
command.description("\u9000\u51FA\u767B\u5F55");
|
|
1065
|
+
command.action(async () => {
|
|
1066
|
+
try {
|
|
1067
|
+
const loginService = getLoginService();
|
|
1068
|
+
await loginService.logout();
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
handleCommandError(error);
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
return command;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// src/commands/auth/status.ts
|
|
1077
|
+
import { Command as Command3 } from "commander";
|
|
1078
|
+
function createStatusCommand() {
|
|
1079
|
+
const command = new Command3("status");
|
|
1080
|
+
command.description("\u67E5\u770B\u767B\u5F55\u72B6\u6001");
|
|
1081
|
+
command.action(async () => {
|
|
1082
|
+
try {
|
|
1083
|
+
const loginService = getLoginService();
|
|
1084
|
+
await loginService.status();
|
|
1085
|
+
} catch (error) {
|
|
1086
|
+
handleCommandError(error);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
return command;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// src/commands/auth/xianyu.ts
|
|
1093
|
+
import { Command as Command4 } from "commander";
|
|
1094
|
+
function createXianyuAuthCommand() {
|
|
1095
|
+
const command = new Command4("xianyu");
|
|
1096
|
+
command.description("\u95F2\u9C7C\u5E97\u94FA\u6388\u6743").option("--json", "\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");
|
|
1097
|
+
const pollCmd = new Command4("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(agentAction(async (options) => {
|
|
1098
|
+
const result = await waitForAuth(
|
|
1099
|
+
options.state,
|
|
1100
|
+
Number.parseInt(options.expire, 10),
|
|
1101
|
+
Number.parseInt(options.interval, 10)
|
|
1102
|
+
);
|
|
1103
|
+
if (result.status === "success") {
|
|
1104
|
+
console.log(JSON.stringify({ success: true, shopId: result.shopId, shopName: result.shopName }));
|
|
1105
|
+
} else {
|
|
1106
|
+
agentError(`\u6388\u6743\u72B6\u6001: ${result.status}`);
|
|
1107
|
+
}
|
|
1108
|
+
}));
|
|
1109
|
+
command.addCommand(pollCmd);
|
|
1110
|
+
command.action(async (options) => {
|
|
1111
|
+
try {
|
|
1112
|
+
if (options.json) {
|
|
1113
|
+
const { authData, qrUrl, setStatus, closeServer } = await generateAuthQR();
|
|
1114
|
+
const expireMs = authData.expireTime ? Number.parseInt(authData.expireTime, 10) : 3e5;
|
|
1115
|
+
const intervalMs = authData.pollInterval ? Number.parseInt(authData.pollInterval, 10) : 1e3;
|
|
1116
|
+
console.log(JSON.stringify({
|
|
1117
|
+
state: authData.state,
|
|
1118
|
+
expireTimeMs: expireMs,
|
|
1119
|
+
pollIntervalMs: intervalMs,
|
|
1120
|
+
qrUrl
|
|
1121
|
+
}, null, 2));
|
|
1122
|
+
openUrl(qrUrl);
|
|
1123
|
+
try {
|
|
1124
|
+
const result = await waitForAuth(authData.state, expireMs, intervalMs, void 0, setStatus);
|
|
1125
|
+
if (result.status === "success") {
|
|
1126
|
+
console.log(JSON.stringify({ success: true, shopId: result.shopId, shopName: result.shopName }));
|
|
1127
|
+
} else {
|
|
1128
|
+
console.log(JSON.stringify({ success: false, error: `\u6388\u6743\u72B6\u6001: ${result.status}` }));
|
|
1129
|
+
process.exit(1);
|
|
1130
|
+
}
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1133
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1134
|
+
process.exit(1);
|
|
1135
|
+
} finally {
|
|
1136
|
+
setTimeout(closeServer, 1e3);
|
|
1137
|
+
}
|
|
1138
|
+
} else {
|
|
1139
|
+
await authorize();
|
|
1140
|
+
}
|
|
1141
|
+
} catch (error) {
|
|
1142
|
+
if (options.json) {
|
|
1143
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1144
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1145
|
+
process.exit(1);
|
|
1146
|
+
}
|
|
1147
|
+
handleCommandError(error);
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
return command;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
// src/commands/goods/index.ts
|
|
1154
|
+
import { Command as Command12 } from "commander";
|
|
1155
|
+
|
|
1156
|
+
// src/commands/goods/up/index.ts
|
|
1157
|
+
import { Command as Command5 } from "commander";
|
|
1158
|
+
import chalk5 from "chalk";
|
|
1159
|
+
import { select, input, confirm } from "@inquirer/prompts";
|
|
1160
|
+
|
|
1161
|
+
// src/services/api/modules/goods.ts
|
|
1162
|
+
var client3 = new ApiClientService();
|
|
1163
|
+
function toParams(obj) {
|
|
1164
|
+
const params = new URLSearchParams();
|
|
1165
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1166
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
1167
|
+
params.append(key, String(value));
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
return params;
|
|
1171
|
+
}
|
|
1172
|
+
async function listingUpXianyu(params) {
|
|
1173
|
+
return client3.post("mms/goods/listing/up/xianyu", params);
|
|
1174
|
+
}
|
|
1175
|
+
async function getListingInfo(params) {
|
|
1176
|
+
return client3.get("mms/goods/listing/get", toParams({ ...params }));
|
|
1177
|
+
}
|
|
1178
|
+
async function listingDownXianyu(params) {
|
|
1179
|
+
return client3.post("mms/goods/listing/down/xianyu", params);
|
|
1180
|
+
}
|
|
1181
|
+
async function listingUpdatePrice(params) {
|
|
1182
|
+
return client3.post("mms/goods/listing/update/xyPrice", params);
|
|
1183
|
+
}
|
|
1184
|
+
async function getListingList(params) {
|
|
1185
|
+
return client3.get("mms/goods/listing/list", params ? toParams({ ...params }) : void 0);
|
|
1186
|
+
}
|
|
1187
|
+
async function getUserShopList() {
|
|
1188
|
+
const data = await client3.get("mms/user/shop/list");
|
|
1189
|
+
return data ?? [];
|
|
1190
|
+
}
|
|
1191
|
+
async function getUserStockList() {
|
|
1192
|
+
const data = await client3.get("mms/user/stock/list");
|
|
1193
|
+
return data ?? [];
|
|
1194
|
+
}
|
|
1195
|
+
async function getSelectGoodsList(params) {
|
|
1196
|
+
const queryParams = params ? toParams({ ...params }) : void 0;
|
|
1197
|
+
return client3.get("mms/seller/goods/select/list", queryParams);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// src/commands/goods/up/index.ts
|
|
1201
|
+
var LISTING_POLL_INTERVAL = 2e3;
|
|
1202
|
+
var LISTING_POLL_TIMEOUT = 1e4;
|
|
1203
|
+
function isProcessing(info) {
|
|
1204
|
+
const status = info.status?.toLowerCase() ?? "";
|
|
1205
|
+
return status === "" || status === "init" || status === "pending" || status === "processing";
|
|
1206
|
+
}
|
|
1207
|
+
async function pollListingStatus(stockGoodsId, shopId, platform, json) {
|
|
1208
|
+
if (!json) {
|
|
1209
|
+
process.stdout.write(chalk5.cyan("\u23F3 \u6B63\u5728\u67E5\u8BE2\u4E0A\u67B6\u8FDB\u5EA6..."));
|
|
1210
|
+
}
|
|
1211
|
+
const result = await poll(
|
|
1212
|
+
() => getListingInfo({ stockGoodsId, shopId, platform }),
|
|
1213
|
+
{
|
|
1214
|
+
interval: LISTING_POLL_INTERVAL,
|
|
1215
|
+
timeout: LISTING_POLL_TIMEOUT,
|
|
1216
|
+
condition: (data) => !isProcessing(data)
|
|
1217
|
+
}
|
|
1218
|
+
);
|
|
1219
|
+
if (!json) {
|
|
1220
|
+
process.stdout.write("\r" + " ".repeat(30) + "\r");
|
|
1221
|
+
}
|
|
1222
|
+
return result;
|
|
1223
|
+
}
|
|
1224
|
+
function createUpCommand() {
|
|
1225
|
+
const command = new Command5("up");
|
|
1226
|
+
command.description("\u4E0A\u67B6\u5546\u54C1\u5230\u95F2\u9C7C");
|
|
1227
|
+
command.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(async (options) => {
|
|
1228
|
+
try {
|
|
1229
|
+
if (options.stockGoodsId && options.shopId && options.price) {
|
|
1230
|
+
const stockGoodsId2 = Number(options.stockGoodsId);
|
|
1231
|
+
const shopId = options.shopId;
|
|
1232
|
+
const price = Number(options.price);
|
|
1233
|
+
const platform = options.platform;
|
|
1234
|
+
const result = await listingUpXianyu({ stockGoodsId: stockGoodsId2, shopId, price, platform });
|
|
1235
|
+
const listingInfo2 = await pollListingStatus(stockGoodsId2, shopId, platform, options.json);
|
|
1236
|
+
if (options.json) {
|
|
1237
|
+
console.log(JSON.stringify({ success: true, data: { submit: result, listing: listingInfo2 } }, null, 2));
|
|
1238
|
+
} else {
|
|
1239
|
+
const statusOk2 = listingInfo2.status?.toLowerCase() !== "failed";
|
|
1240
|
+
console.log(statusOk2 ? chalk5.green("\u2713 \u4E0A\u67B6\u6210\u529F") : chalk5.red("\u2717 \u4E0A\u67B6\u5931\u8D25"));
|
|
1241
|
+
console.log(JSON.stringify(listingInfo2, null, 2));
|
|
1242
|
+
}
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
const shops = await getUserShopList();
|
|
1246
|
+
if (shops.length === 0) {
|
|
1247
|
+
console.log(chalk5.yellow("\u6CA1\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF0C\u8BF7\u5148\u8FD0\u884C r2-cli auth xianyu \u6388\u6743"));
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const selectedShop = await select({
|
|
1251
|
+
message: "\u9009\u62E9\u5E97\u94FA",
|
|
1252
|
+
choices: shops.map((s) => ({ name: `${s.shopName} (${s.platform})`, value: s.shopId }))
|
|
1253
|
+
});
|
|
1254
|
+
const stocks = await getUserStockList();
|
|
1255
|
+
if (stocks.length === 0) {
|
|
1256
|
+
console.log(chalk5.yellow("\u6CA1\u6709\u53EF\u7528\u7684\u4ED3\u5E93"));
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
const selectedStock = await select({
|
|
1260
|
+
message: "\u9009\u62E9\u4ED3\u5E93",
|
|
1261
|
+
choices: stocks.map((s) => ({ name: s.stockName, value: s.stockId }))
|
|
1262
|
+
});
|
|
1263
|
+
const goodsList = await getSelectGoodsList({ stockId: selectedStock, size: 100 });
|
|
1264
|
+
if (!goodsList.items?.length) {
|
|
1265
|
+
console.log(chalk5.yellow("\u8BE5\u4ED3\u5E93\u6CA1\u6709\u53EF\u9009\u7684\u5546\u54C1"));
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
const selectedGoods = await select({
|
|
1269
|
+
message: "\u9009\u62E9\u5546\u54C1",
|
|
1270
|
+
choices: goodsList.items.map((g) => ({
|
|
1271
|
+
name: `${g.goodsName} ${g.size ? `| ${g.size}` : ""} | \xA5${g.salePrice}`,
|
|
1272
|
+
value: g.stockGoodsId
|
|
1273
|
+
}))
|
|
1274
|
+
});
|
|
1275
|
+
const priceInput = await input({
|
|
1276
|
+
message: "\u8F93\u5165\u4E0A\u67B6\u4EF7\u683C",
|
|
1277
|
+
default: goodsList.items.find((g) => g.stockGoodsId === selectedGoods)?.salePrice?.toString() ?? "",
|
|
1278
|
+
validate: (v) => {
|
|
1279
|
+
const n = Number(v);
|
|
1280
|
+
return n > 0 ? true : "\u4EF7\u683C\u5FC5\u987B\u4E3A\u6B63\u6570";
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
const confirmed = await confirm({
|
|
1284
|
+
message: `\u786E\u8BA4\u4E0A\u67B6\uFF1F\u4EF7\u683C \xA5${priceInput}`,
|
|
1285
|
+
default: true
|
|
1286
|
+
});
|
|
1287
|
+
if (!confirmed) {
|
|
1288
|
+
console.log(chalk5.gray("\u5DF2\u53D6\u6D88"));
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
const stockGoodsId = Number(selectedGoods);
|
|
1292
|
+
await listingUpXianyu({
|
|
1293
|
+
stockGoodsId,
|
|
1294
|
+
shopId: selectedShop,
|
|
1295
|
+
price: Number(priceInput),
|
|
1296
|
+
platform: "xianyu"
|
|
1297
|
+
});
|
|
1298
|
+
console.log(chalk5.green("\u2713 \u4E0A\u67B6\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u67E5\u8BE2\u8FDB\u5EA6..."));
|
|
1299
|
+
const listingInfo = await pollListingStatus(stockGoodsId, selectedShop, "xianyu");
|
|
1300
|
+
const statusOk = listingInfo.status?.toLowerCase() !== "failed";
|
|
1301
|
+
console.log(statusOk ? chalk5.green("\u2713 \u4E0A\u67B6\u6210\u529F") : chalk5.red("\u2717 \u4E0A\u67B6\u5931\u8D25"));
|
|
1302
|
+
console.log(JSON.stringify(listingInfo, null, 2));
|
|
1303
|
+
} catch (error) {
|
|
1304
|
+
handleCommandError(error);
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
return command;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// src/commands/goods/shops.ts
|
|
1311
|
+
import { Command as Command6 } from "commander";
|
|
1312
|
+
import chalk6 from "chalk";
|
|
1313
|
+
function createShopsCommand() {
|
|
1314
|
+
const command = new Command6("shops");
|
|
1315
|
+
command.description("\u67E5\u770B\u6240\u6709\u5DF2\u6388\u6743\u5E97\u94FA\uFF08\u8DE8\u5E73\u53F0\uFF09");
|
|
1316
|
+
command.option("--json", "\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");
|
|
1317
|
+
command.action(async (options) => {
|
|
1318
|
+
try {
|
|
1319
|
+
const shops = await getUserShopList();
|
|
1320
|
+
if (options.json) {
|
|
1321
|
+
console.log(JSON.stringify(sanitizeShops(shops), null, 2));
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
if (!shops.length) {
|
|
1325
|
+
console.log(chalk6.yellow("\u672A\u627E\u5230\u5DF2\u6388\u6743\u7684\u5E97\u94FA"));
|
|
1326
|
+
console.log(chalk6.gray(" \u63D0\u793A: \u8BF7\u5148\u5728\u7B2C\u4E8C\u56DE\u5408 APP \u4E2D\u6388\u6743\u5E97\u94FA"));
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
const { ShopsTable: ShopsTable2 } = await Promise.resolve().then(() => (init_ShopsTable(), ShopsTable_exports));
|
|
1330
|
+
const { renderComponent: renderComponent2 } = await Promise.resolve().then(() => (init_render(), render_exports));
|
|
1331
|
+
renderComponent2(ShopsTable2, { shops, platform: "all" });
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
handleCommandError(error);
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
return command;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// src/commands/goods/stocks.ts
|
|
1340
|
+
import { Command as Command7 } from "commander";
|
|
1341
|
+
import chalk7 from "chalk";
|
|
1342
|
+
function createStocksCommand() {
|
|
1343
|
+
const command = new Command7("stocks");
|
|
1344
|
+
command.description("\u67E5\u770B\u6240\u6709\u4ED3\u5E93");
|
|
1345
|
+
command.option("--json", "\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");
|
|
1346
|
+
command.action(async (options) => {
|
|
1347
|
+
try {
|
|
1348
|
+
const stocks = await getUserStockList();
|
|
1349
|
+
if (options.json) {
|
|
1350
|
+
console.log(JSON.stringify(stocks, null, 2));
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
if (!stocks.length) {
|
|
1354
|
+
console.log(chalk7.yellow("\u672A\u627E\u5230\u4ED3\u5E93\u4FE1\u606F"));
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
const { StocksTable: StocksTable2 } = await Promise.resolve().then(() => (init_StocksTable(), StocksTable_exports));
|
|
1358
|
+
const { renderComponent: renderComponent2 } = await Promise.resolve().then(() => (init_render(), render_exports));
|
|
1359
|
+
renderComponent2(StocksTable2, { stocks });
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
handleCommandError(error);
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
return command;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// src/commands/goods/list.ts
|
|
1368
|
+
import { Command as Command8 } from "commander";
|
|
1369
|
+
import chalk8 from "chalk";
|
|
1370
|
+
function createListCommand() {
|
|
1371
|
+
const command = new Command8("list");
|
|
1372
|
+
command.description("\u67E5\u770B\u4ED3\u5E93\u4E2D\u7684\u9009\u54C1\u5546\u54C1");
|
|
1373
|
+
command.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", "20").option("--json", "\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");
|
|
1374
|
+
command.action(
|
|
1375
|
+
async (options) => {
|
|
1376
|
+
try {
|
|
1377
|
+
const result = await getSelectGoodsList({
|
|
1378
|
+
stockId: options.stockId || void 0,
|
|
1379
|
+
stockGoodsId: options.stockGoodsId || void 0,
|
|
1380
|
+
page: Number(options.page) || 1,
|
|
1381
|
+
size: Number(options.size) || 20
|
|
1382
|
+
});
|
|
1383
|
+
const data = result ?? { items: [], total: 0 };
|
|
1384
|
+
if (options.json) {
|
|
1385
|
+
if (!data.items?.length) {
|
|
1386
|
+
console.log(JSON.stringify({ ...data, 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));
|
|
1387
|
+
} else {
|
|
1388
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1389
|
+
}
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
if (!data.items?.length) {
|
|
1393
|
+
console.log(chalk8.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"));
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
console.log(chalk8.cyan(`
|
|
1397
|
+
\u9009\u54C1\u5546\u54C1\uFF08\u5171 ${data.total} \u4EF6\uFF0C\u7B2C ${data.page} \u9875\uFF09
|
|
1398
|
+
`));
|
|
1399
|
+
for (const item of data.items) {
|
|
1400
|
+
console.log(
|
|
1401
|
+
` ${chalk8.bold(item.goodsName)} ${item.size ? chalk8.gray(`| ${item.size}`) : ""}`
|
|
1402
|
+
);
|
|
1403
|
+
console.log(
|
|
1404
|
+
` \u54C1\u724C: ${item.brand} \u5EFA\u8BAE\u552E\u4EF7: \xA5${item.salePrice} stockGoodsId: ${chalk8.green(item.stockGoodsId)}`
|
|
1405
|
+
);
|
|
1406
|
+
console.log(chalk8.gray(` \u5206\u7C7B: ${item.cate1Name} > ${item.cate2Name} > ${item.cate3Name}`));
|
|
1407
|
+
console.log();
|
|
1408
|
+
}
|
|
1409
|
+
} catch (error) {
|
|
1410
|
+
if (options.json) {
|
|
1411
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1412
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1413
|
+
process.exit(1);
|
|
1414
|
+
}
|
|
1415
|
+
handleCommandError(error);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
);
|
|
1419
|
+
return command;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// src/commands/goods/listing.ts
|
|
1423
|
+
import { Command as Command9 } from "commander";
|
|
1424
|
+
import chalk9 from "chalk";
|
|
1425
|
+
var STATUS_MAP = {
|
|
1426
|
+
init: "\u5F85\u4E0A\u67B6",
|
|
1427
|
+
up: "\u5DF2\u4E0A\u67B6",
|
|
1428
|
+
down: "\u5DF2\u4E0B\u67B6",
|
|
1429
|
+
fail: "\u5931\u8D25"
|
|
1430
|
+
};
|
|
1431
|
+
function createListingCommand() {
|
|
1432
|
+
const command = new Command9("listing");
|
|
1433
|
+
command.description("\u67E5\u8BE2\u4E0A\u67B6\u5546\u54C1\u5217\u8868");
|
|
1434
|
+
command.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\uFF09").option("-p, --platform <platform>", "\u5E73\u53F0", "xianyu").option("--json", "\u8F93\u51FA JSON\uFF08\u4F9B AI Agent \u4F7F\u7528\uFF09");
|
|
1435
|
+
command.action(
|
|
1436
|
+
async (options) => {
|
|
1437
|
+
try {
|
|
1438
|
+
const result = await getListingList({
|
|
1439
|
+
id: options.id,
|
|
1440
|
+
stockGoodsId: options.stockGoodsId ? Number(options.stockGoodsId) : void 0,
|
|
1441
|
+
shopId: options.shopId,
|
|
1442
|
+
stockId: options.stockId,
|
|
1443
|
+
status: options.status,
|
|
1444
|
+
platform: options.platform
|
|
1445
|
+
});
|
|
1446
|
+
const data = result ?? { list: [], total: 0 };
|
|
1447
|
+
if (options.json) {
|
|
1448
|
+
if (!data.list?.length) {
|
|
1449
|
+
console.log(JSON.stringify({ ...data, hint: "\u6682\u65E0\u4E0A\u67B6\u8BB0\u5F55" }, null, 2));
|
|
1450
|
+
} else {
|
|
1451
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1452
|
+
}
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
if (!data.list?.length) {
|
|
1456
|
+
console.log(chalk9.yellow("\u6682\u65E0\u4E0A\u67B6\u8BB0\u5F55"));
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
console.log(chalk9.green(`\u2705 \u5171 ${data.total} \u6761\u8BB0\u5F55
|
|
1460
|
+
`));
|
|
1461
|
+
for (const item of data.list) {
|
|
1462
|
+
const statusText = STATUS_MAP[item.status] ?? item.status;
|
|
1463
|
+
console.log(` ID: ${item.id} | \u72B6\u6001: ${statusText} | \u4EF7\u683C: ${item.price} | stockGoodsId: ${item.stockGoodsId}`);
|
|
1464
|
+
}
|
|
1465
|
+
} catch (error) {
|
|
1466
|
+
if (options.json) {
|
|
1467
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1468
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1469
|
+
process.exit(1);
|
|
1470
|
+
}
|
|
1471
|
+
handleCommandError(error);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
);
|
|
1475
|
+
return command;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// src/commands/goods/down.ts
|
|
1479
|
+
import { Command as Command10 } from "commander";
|
|
1480
|
+
import chalk10 from "chalk";
|
|
1481
|
+
function createDownCommand() {
|
|
1482
|
+
const command = new Command10("down");
|
|
1483
|
+
command.description("\u4E0B\u67B6\u95F2\u9C7C\u5546\u54C1");
|
|
1484
|
+
command.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");
|
|
1485
|
+
command.action(
|
|
1486
|
+
async (options) => {
|
|
1487
|
+
try {
|
|
1488
|
+
if (!options.id && !(options.stockGoodsId && options.shopId)) {
|
|
1489
|
+
if (options.json) {
|
|
1490
|
+
console.log(JSON.stringify({ success: false, error: "\u8BF7\u6307\u5B9A\u4E0B\u67B6\u6761\u4EF6\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>" }));
|
|
1491
|
+
process.exit(1);
|
|
1492
|
+
}
|
|
1493
|
+
console.log(chalk10.yellow("\u8BF7\u6307\u5B9A\u4E0B\u67B6\u6761\u4EF6\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>"));
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
const params = {};
|
|
1497
|
+
if (options.id) params.id = options.id;
|
|
1498
|
+
if (options.stockGoodsId) params.stockGoodsId = Number(options.stockGoodsId);
|
|
1499
|
+
if (options.shopId) params.shopId = options.shopId;
|
|
1500
|
+
if (!options.json) console.log(chalk10.cyan("\u{1F4E6} \u6B63\u5728\u4E0B\u67B6\u5546\u54C1..."));
|
|
1501
|
+
const result = await listingDownXianyu(params);
|
|
1502
|
+
if (options.json) {
|
|
1503
|
+
console.log(JSON.stringify({ success: true, data: result }, null, 2));
|
|
1504
|
+
} else {
|
|
1505
|
+
console.log(chalk10.green("\u2705 \u4E0B\u67B6\u6210\u529F"));
|
|
1506
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1507
|
+
}
|
|
1508
|
+
} catch (error) {
|
|
1509
|
+
if (options.json) {
|
|
1510
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1511
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1512
|
+
process.exit(1);
|
|
1513
|
+
}
|
|
1514
|
+
handleCommandError(error);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
);
|
|
1518
|
+
return command;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// src/commands/goods/price.ts
|
|
1522
|
+
import { Command as Command11 } from "commander";
|
|
1523
|
+
import chalk11 from "chalk";
|
|
1524
|
+
function createPriceCommand() {
|
|
1525
|
+
const command = new Command11("price");
|
|
1526
|
+
command.description("\u4FEE\u6539\u95F2\u9C7C\u4E0A\u67B6\u5546\u54C1\u4EF7\u683C");
|
|
1527
|
+
command.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");
|
|
1528
|
+
command.action(
|
|
1529
|
+
async (options) => {
|
|
1530
|
+
try {
|
|
1531
|
+
if (!options.price) {
|
|
1532
|
+
if (options.json) {
|
|
1533
|
+
console.log(JSON.stringify({ success: false, error: "--price <amount> \u4E3A\u5FC5\u586B\u53C2\u6570" }));
|
|
1534
|
+
process.exit(1);
|
|
1535
|
+
}
|
|
1536
|
+
console.log(chalk11.yellow("--price <amount> \u4E3A\u5FC5\u586B\u53C2\u6570"));
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
if (!options.id && !(options.stockGoodsId && options.shopId)) {
|
|
1540
|
+
if (options.json) {
|
|
1541
|
+
console.log(JSON.stringify({ success: false, error: "\u8BF7\u6307\u5B9A\u5546\u54C1\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>" }));
|
|
1542
|
+
process.exit(1);
|
|
1543
|
+
}
|
|
1544
|
+
console.log(chalk11.yellow("\u8BF7\u6307\u5B9A\u5546\u54C1\uFF1A--id <id> \u6216 --stock-goods-id <id> --shop-id <id>"));
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
const params = { price: Number(options.price) };
|
|
1548
|
+
if (options.id) params.id = options.id;
|
|
1549
|
+
if (options.stockGoodsId) params.stockGoodsId = Number(options.stockGoodsId);
|
|
1550
|
+
if (options.shopId) params.shopId = options.shopId;
|
|
1551
|
+
if (!options.json) console.log(chalk11.cyan(`\u{1F4B0} \u6B63\u5728\u4FEE\u6539\u4EF7\u683C\u4E3A ${options.price}...`));
|
|
1552
|
+
const result = await listingUpdatePrice(params);
|
|
1553
|
+
if (options.json) {
|
|
1554
|
+
console.log(JSON.stringify({ success: true, data: result }, null, 2));
|
|
1555
|
+
} else {
|
|
1556
|
+
console.log(chalk11.green("\u2705 \u4EF7\u683C\u4FEE\u6539\u6210\u529F"));
|
|
1557
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1558
|
+
}
|
|
1559
|
+
} catch (error) {
|
|
1560
|
+
if (options.json) {
|
|
1561
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1562
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
1563
|
+
process.exit(1);
|
|
1564
|
+
}
|
|
1565
|
+
handleCommandError(error);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
);
|
|
1569
|
+
return command;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
// src/commands/goods/index.ts
|
|
1573
|
+
function createGoodsCommand() {
|
|
1574
|
+
const command = new Command12("goods");
|
|
1575
|
+
command.description("\u5546\u54C1\u7BA1\u7406");
|
|
1576
|
+
command.addCommand(createShopsCommand());
|
|
1577
|
+
command.addCommand(createStocksCommand());
|
|
1578
|
+
command.addCommand(createListCommand());
|
|
1579
|
+
command.addCommand(createListingCommand());
|
|
1580
|
+
command.addCommand(createDownCommand());
|
|
1581
|
+
command.addCommand(createPriceCommand());
|
|
1582
|
+
command.addCommand(createUpCommand());
|
|
1583
|
+
return command;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
// src/commands/uninstall.ts
|
|
1587
|
+
import { Command as Command13 } from "commander";
|
|
1588
|
+
import chalk12 from "chalk";
|
|
1589
|
+
import { promises as fs3 } from "node:fs";
|
|
1590
|
+
import path3 from "node:path";
|
|
1591
|
+
import os2 from "node:os";
|
|
1592
|
+
import { spawn } from "node:child_process";
|
|
1593
|
+
var PKG_NAME = "@round2ai/r2-cli";
|
|
1594
|
+
function createUninstallCommand() {
|
|
1595
|
+
const command = new Command13("uninstall");
|
|
1596
|
+
command.description("\u5378\u8F7D R2-CLI \u5E76\u6E05\u9664\u6240\u6709\u914D\u7F6E");
|
|
1597
|
+
command.action(async () => {
|
|
1598
|
+
try {
|
|
1599
|
+
console.log(chalk12.yellow("\n\u26A0\uFE0F \u5373\u5C06\u6267\u884C\u4EE5\u4E0B\u64CD\u4F5C\uFF1A"));
|
|
1600
|
+
console.log(chalk12.gray(` 1. \u5220\u9664\u914D\u7F6E\u76EE\u5F55 ~/.r2-cli/`));
|
|
1601
|
+
console.log(chalk12.gray(` 2. \u5168\u5C40\u5378\u8F7D ${PKG_NAME}
|
|
1602
|
+
`));
|
|
1603
|
+
const { confirm: confirm2 } = await import("@inquirer/prompts");
|
|
1604
|
+
const confirmed = await confirm2({ message: "\u786E\u8BA4\u5378\u8F7D\uFF1F", default: false });
|
|
1605
|
+
if (!confirmed) {
|
|
1606
|
+
console.log(chalk12.gray("\u5DF2\u53D6\u6D88\u5378\u8F7D"));
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
const configDir = path3.join(os2.homedir(), ".r2-cli");
|
|
1610
|
+
try {
|
|
1611
|
+
await fs3.rm(configDir, { recursive: true, force: true });
|
|
1612
|
+
console.log(chalk12.green("\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u6E05\u9664"));
|
|
1613
|
+
} catch {
|
|
1614
|
+
console.log(chalk12.yellow("\u26A0\uFE0F \u914D\u7F6E\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u5220\u9664\uFF08\u53EF\u5FFD\u7565\uFF09"));
|
|
1615
|
+
}
|
|
1616
|
+
console.log(chalk12.cyan(`\u6B63\u5728\u5378\u8F7D ${PKG_NAME}...`));
|
|
1617
|
+
const child = spawn("npm", ["uninstall", "-g", PKG_NAME], {
|
|
1618
|
+
stdio: "inherit",
|
|
1619
|
+
shell: true
|
|
1620
|
+
});
|
|
1621
|
+
child.on("exit", (code) => {
|
|
1622
|
+
if (code === 0) {
|
|
1623
|
+
console.log(chalk12.green(`
|
|
1624
|
+
\u2705 ${PKG_NAME} \u5DF2\u5378\u8F7D`));
|
|
1625
|
+
} else {
|
|
1626
|
+
console.log(chalk12.yellow(`
|
|
1627
|
+
\u26A0\uFE0F npm \u5378\u8F7D\u5931\u8D25 (exit code: ${code})`));
|
|
1628
|
+
console.log(chalk12.gray(" \u5982\u901A\u8FC7 yarn/pnpm \u5B89\u88C5\uFF0C\u8BF7\u624B\u52A8\u5378\u8F7D"));
|
|
1629
|
+
}
|
|
1630
|
+
process.exit(code ?? 1);
|
|
1631
|
+
});
|
|
1632
|
+
} catch (error) {
|
|
1633
|
+
handleCommandError(error);
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
return command;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// src/commands/setup.ts
|
|
1640
|
+
function setupCommands(program2) {
|
|
1641
|
+
const authCommand = program2.command("auth").description("\u6388\u6743\u7BA1\u7406");
|
|
1642
|
+
authCommand.addCommand(createLoginCommand());
|
|
1643
|
+
authCommand.addCommand(createLogoutCommand());
|
|
1644
|
+
authCommand.addCommand(createStatusCommand());
|
|
1645
|
+
authCommand.addCommand(createXianyuAuthCommand());
|
|
1646
|
+
program2.addCommand(createGoodsCommand());
|
|
1647
|
+
program2.addCommand(createUninstallCommand());
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// src/services/update-check/index.ts
|
|
1651
|
+
import chalk13 from "chalk";
|
|
1652
|
+
var PKG_NAME2 = "@round2ai/r2-cli";
|
|
1653
|
+
var REGISTRY_URLS = [
|
|
1654
|
+
`https://registry.npmmirror.com/${encodeURIComponent(PKG_NAME2)}/latest`,
|
|
1655
|
+
`https://registry.npmjs.org/${encodeURIComponent(PKG_NAME2)}/latest`
|
|
1656
|
+
];
|
|
1657
|
+
var FETCH_TIMEOUT_MS = 5e3;
|
|
1658
|
+
async function fetchVersionFromRegistry(url) {
|
|
1659
|
+
const controller = new AbortController();
|
|
1660
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
1661
|
+
try {
|
|
1662
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
1663
|
+
if (!res.ok) return null;
|
|
1664
|
+
return (await res.json()).version ?? null;
|
|
1665
|
+
} catch {
|
|
1666
|
+
return null;
|
|
1667
|
+
} finally {
|
|
1668
|
+
clearTimeout(timer);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
async function fetchLatestVersion() {
|
|
1672
|
+
const results = await Promise.allSettled(REGISTRY_URLS.map(fetchVersionFromRegistry));
|
|
1673
|
+
for (const r of results) {
|
|
1674
|
+
if (r.status === "fulfilled" && r.value) return r.value;
|
|
1675
|
+
}
|
|
1676
|
+
return null;
|
|
1677
|
+
}
|
|
1678
|
+
function isNewer(latest, current) {
|
|
1679
|
+
const la = latest.split(".").map(Number);
|
|
1680
|
+
const cu = current.split(".").map(Number);
|
|
1681
|
+
for (let i = 0; i < 3; i++) {
|
|
1682
|
+
if ((la[i] ?? 0) !== (cu[i] ?? 0)) return (la[i] ?? 0) > (cu[i] ?? 0);
|
|
1683
|
+
}
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
async function checkForUpdate(currentVersion) {
|
|
1687
|
+
const latest = await fetchLatestVersion();
|
|
1688
|
+
if (!latest) return;
|
|
1689
|
+
if (isNewer(latest, currentVersion)) {
|
|
1690
|
+
showUpdateNotification(currentVersion, latest);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
function showUpdateNotification(current, latest) {
|
|
1694
|
+
console.error(
|
|
1695
|
+
chalk13.yellow(`
|
|
1696
|
+
Update available: ${current} \u2192 ${latest}`) + chalk13.gray(`
|
|
1697
|
+
Run: npm update -g ${PKG_NAME2}
|
|
1698
|
+
`)
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// src/entrypoints/r2-cli.tsx
|
|
1703
|
+
async function displayWelcomeMessage() {
|
|
1704
|
+
const { default: figlet } = await import("figlet");
|
|
1705
|
+
console.log(
|
|
1706
|
+
chalk14.cyan.bold(
|
|
1707
|
+
figlet.textSync("R2-CLI", {
|
|
1708
|
+
font: "Standard",
|
|
1709
|
+
horizontalLayout: "full"
|
|
1710
|
+
})
|
|
1711
|
+
)
|
|
1712
|
+
);
|
|
1713
|
+
console.log(chalk14.gray(" \u5411 AI \u5F00\u653E\u4E8C\u624B\u6F6E\u5962\u4EA4\u6613\u5168\u94FE\u8DEF\u80FD\u529B\n"));
|
|
1714
|
+
}
|
|
1715
|
+
function setupCliApp() {
|
|
1716
|
+
const program2 = new Command15();
|
|
1717
|
+
program2.name("r2-cli").description("R2-CLI\uFF0C\u5411 AI \u5F00\u653E\u4E8C\u624B\u6F6E\u5962\u4EA4\u6613\u5168\u94FE\u8DEF\u80FD\u529B");
|
|
1718
|
+
const pkgPaths = [
|
|
1719
|
+
path4.join(import.meta.dirname, "../../package.json"),
|
|
1720
|
+
// 项目根目录
|
|
1721
|
+
path4.join(import.meta.dirname, "package.json")
|
|
1722
|
+
// dist 目录下
|
|
1723
|
+
];
|
|
1724
|
+
let version = "0.0.0";
|
|
1725
|
+
for (const p of pkgPaths) {
|
|
1726
|
+
try {
|
|
1727
|
+
version = JSON.parse(readFileSync(p, "utf-8")).version;
|
|
1728
|
+
break;
|
|
1729
|
+
} catch {
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
if (version === "0.0.0") {
|
|
1733
|
+
console.error(chalk14.yellow("Warning: unable to read version from package.json"));
|
|
1734
|
+
}
|
|
1735
|
+
program2.version(version, "-v, --version");
|
|
1736
|
+
const updateCheckPromise2 = checkForUpdate(version);
|
|
1737
|
+
program2.configureOutput({
|
|
1738
|
+
writeErr: (str) => {
|
|
1739
|
+
console.error(chalk14.red(str.replace("error:", "").trim()));
|
|
1740
|
+
}
|
|
1741
|
+
});
|
|
1742
|
+
program2.action(async () => {
|
|
1743
|
+
await displayWelcomeMessage();
|
|
1744
|
+
program2.help();
|
|
1745
|
+
});
|
|
1746
|
+
setupCommands(program2);
|
|
1747
|
+
return { program: program2, updateCheckPromise: updateCheckPromise2 };
|
|
1748
|
+
}
|
|
1749
|
+
function handleSignal() {
|
|
1750
|
+
console.log(chalk14.gray("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
|
|
1751
|
+
process.exit(130);
|
|
1752
|
+
}
|
|
1753
|
+
process.on("SIGINT", handleSignal);
|
|
1754
|
+
process.on("SIGTERM", handleSignal);
|
|
1755
|
+
var { program, updateCheckPromise } = setupCliApp();
|
|
1756
|
+
program.parse(process.argv);
|
|
1757
|
+
updateCheckPromise.catch((e) => {
|
|
1758
|
+
console.error(chalk14.gray(`[update-check] ${e instanceof Error ? e.message : String(e)}`));
|
|
1759
|
+
});
|