eprolo-cli 1.0.31 → 1.0.32
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/bin/eprolo-cli.js +250 -176
- package/package.json +1 -1
package/bin/eprolo-cli.js
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
const https = require("https");
|
|
8
7
|
|
|
9
|
-
const VERIFY_URL = "https://wixtest.eprolo.com/v1/auth/verify-code";
|
|
10
8
|
const CONFIG_DIR = path.join(os.homedir(), ".dxb-toolkit");
|
|
11
9
|
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
12
10
|
|
|
13
11
|
// ---------------------------------------------------------------------------
|
|
14
|
-
// 凭据文件读写(~/.dxb-toolkit/config.json)
|
|
12
|
+
// D3 · 凭据文件读写(~/.dxb-toolkit/config.json)
|
|
13
|
+
// 框架判定连接成功的唯一依据:凭据文件出现
|
|
14
|
+
// 框架读顶层明文 account 字段做授权卡片标签
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
16
16
|
|
|
17
17
|
function readConfig() {
|
|
@@ -21,6 +21,7 @@ function readConfig() {
|
|
|
21
21
|
|
|
22
22
|
function writeConfig(config) {
|
|
23
23
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
24
|
+
// 原子写:临时文件 + rename,避免 MCP 进程读到半截 JSON
|
|
24
25
|
const tmp = CONFIG_FILE + ".tmp";
|
|
25
26
|
fs.writeFileSync(tmp, JSON.stringify(config, null, 2), "utf8");
|
|
26
27
|
fs.renameSync(tmp, CONFIG_FILE);
|
|
@@ -56,72 +57,29 @@ function readFlag(argv, flag) {
|
|
|
56
57
|
return argv[idx + 1];
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
function splitIds(value) {
|
|
61
|
+
if (!value) return [];
|
|
62
|
+
return String(value).split(",").map((item) => item.trim()).filter(Boolean);
|
|
63
|
+
}
|
|
62
64
|
|
|
63
|
-
function
|
|
64
|
-
return
|
|
65
|
-
const target = new URL(url);
|
|
66
|
-
const payload = JSON.stringify(body);
|
|
67
|
-
const req = https.request(
|
|
68
|
-
{
|
|
69
|
-
hostname: target.hostname,
|
|
70
|
-
port: target.port || 443,
|
|
71
|
-
path: target.pathname + target.search,
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers: {
|
|
74
|
-
"Content-Type": "application/json",
|
|
75
|
-
"Content-Length": Buffer.byteLength(payload)
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
(res) => {
|
|
79
|
-
const chunks = [];
|
|
80
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
81
|
-
res.on("end", () => {
|
|
82
|
-
const text = Buffer.concat(chunks).toString("utf8");
|
|
83
|
-
let data;
|
|
84
|
-
try {
|
|
85
|
-
data = text ? JSON.parse(text) : {};
|
|
86
|
-
} catch (_) {
|
|
87
|
-
data = { raw: text };
|
|
88
|
-
}
|
|
89
|
-
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
90
|
-
const err = new Error(`HTTP ${res.statusCode}`);
|
|
91
|
-
err.response = data;
|
|
92
|
-
reject(err);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
resolve(data);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
req.on("error", reject);
|
|
100
|
-
req.write(payload);
|
|
101
|
-
req.end();
|
|
102
|
-
});
|
|
65
|
+
function taskKey(action) {
|
|
66
|
+
return `${action}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
103
67
|
}
|
|
104
68
|
|
|
105
69
|
// ---------------------------------------------------------------------------
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
70
|
+
// D2 · login 命令
|
|
71
|
+
// 输入契约(框架 → CLI):
|
|
72
|
+
// userCode ← env 通道 process.env.DXB_USER_CODE
|
|
73
|
+
// defaultShop ← arg 通道 --default-shop(或 --default-store-name 兼容旧版)
|
|
74
|
+
// 行为契约:
|
|
75
|
+
// 成功 → 写凭据文件 + exit 0
|
|
76
|
+
// 失败 → 非零退出 + stderr 错误信息
|
|
77
|
+
// ❌ 禁止交互式 prompt(CLI 跑在非交互终端)
|
|
109
78
|
// ---------------------------------------------------------------------------
|
|
110
79
|
|
|
111
|
-
|
|
80
|
+
function login(argv) {
|
|
112
81
|
// env 通道:框架通过 fieldInjection 注入 DXB_USER_CODE
|
|
113
|
-
const userCode =
|
|
114
|
-
process.env.DXB_USER_CODE ||
|
|
115
|
-
readFlag(argv, "--user-code") ||
|
|
116
|
-
readFlag(argv, "--userCode");
|
|
117
|
-
|
|
118
|
-
if (!userCode) {
|
|
119
|
-
console.error(JSON.stringify({
|
|
120
|
-
success: false,
|
|
121
|
-
errorMessage: "缺少用户密文:请在授权弹窗中填写,或设置环境变量 DXB_USER_CODE"
|
|
122
|
-
}, null, 2));
|
|
123
|
-
process.exit(2);
|
|
124
|
-
}
|
|
82
|
+
const userCode = process.env.DXB_USER_CODE || readFlag(argv, "--user-code") || "mock-user-code";
|
|
125
83
|
|
|
126
84
|
// arg 通道:框架通过 fieldInjection 追加 --default-shop
|
|
127
85
|
const defaultShop =
|
|
@@ -129,194 +87,310 @@ async function login(argv) {
|
|
|
129
87
|
readFlag(argv, "--default-store-name") ||
|
|
130
88
|
readFlag(argv, "--store-name") ||
|
|
131
89
|
process.env.DXB_STORE_NAME ||
|
|
90
|
+
process.env.DXB_DEFAULT_STORE_NAME ||
|
|
132
91
|
null;
|
|
133
92
|
|
|
134
|
-
//
|
|
135
|
-
const
|
|
93
|
+
// 账号标识:用户在弹窗可填 accountAlias,或用 defaultShop 兜底
|
|
94
|
+
const account =
|
|
136
95
|
readFlag(argv, "--account") ||
|
|
137
96
|
process.env.DXB_ACCOUNT ||
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// 调用 verify-code 接口校验密文
|
|
141
|
-
let verifyResult;
|
|
142
|
-
try {
|
|
143
|
-
verifyResult = await postJson(VERIFY_URL, { 'openApiKey':userCode });
|
|
144
|
-
} catch (err) {
|
|
145
|
-
console.error(JSON.stringify({
|
|
146
|
-
success: false,
|
|
147
|
-
errorMessage: "密文无效或已吊销请到账号设置页重新复制",
|
|
148
|
-
detail: err.message,
|
|
149
|
-
response: err.response || null
|
|
150
|
-
}, null, 2));
|
|
151
|
-
process.exit(1);
|
|
152
|
-
}
|
|
97
|
+
defaultShop ||
|
|
98
|
+
"mock-account";
|
|
153
99
|
|
|
154
|
-
//
|
|
155
|
-
const account = accountAlias || verifyResult.accessToken || defaultShop || "unknown";
|
|
100
|
+
// 写凭据文件(D3 契约:顶层明文 account + version)
|
|
156
101
|
const config = {
|
|
157
|
-
account, //
|
|
102
|
+
account, // ← 顶层明文,框架读它做卡片标签(稳定契约,不可改名/挪位)
|
|
158
103
|
userCode,
|
|
159
|
-
accessToken: verifyResult.accessToken || null,
|
|
160
|
-
refreshToken: verifyResult.refreshToken || null,
|
|
161
|
-
defaultShop: defaultShop || verifyResult.defaultShop || null,
|
|
162
104
|
version: 1
|
|
163
105
|
};
|
|
106
|
+
if (defaultShop) config.defaultShop = defaultShop;
|
|
164
107
|
|
|
165
108
|
writeConfig(config);
|
|
166
109
|
|
|
167
|
-
//
|
|
110
|
+
// 不打印任何敏感值
|
|
168
111
|
console.log(JSON.stringify({
|
|
169
112
|
success: true,
|
|
170
113
|
connected: true,
|
|
171
114
|
account: config.account,
|
|
172
|
-
defaultShop: config.defaultShop
|
|
115
|
+
defaultShop: config.defaultShop || null
|
|
173
116
|
}, null, 2));
|
|
174
117
|
process.exit(0);
|
|
175
118
|
}
|
|
176
119
|
|
|
177
120
|
// ---------------------------------------------------------------------------
|
|
178
|
-
//
|
|
121
|
+
// auth status / auth logout
|
|
179
122
|
// ---------------------------------------------------------------------------
|
|
180
123
|
|
|
181
124
|
function authStatus() {
|
|
182
125
|
const config = readConfig();
|
|
183
|
-
const connected = fs.existsSync(CONFIG_FILE) && Boolean(config.userCode);
|
|
184
126
|
console.log(JSON.stringify({
|
|
185
|
-
connected,
|
|
127
|
+
connected: fs.existsSync(CONFIG_FILE),
|
|
186
128
|
account: config.account || null,
|
|
187
129
|
defaultShop: config.defaultShop || null
|
|
188
130
|
}, null, 2));
|
|
189
131
|
process.exit(0);
|
|
190
132
|
}
|
|
191
133
|
|
|
134
|
+
function authLogout() {
|
|
135
|
+
if (fs.existsSync(CONFIG_FILE)) fs.unlinkSync(CONFIG_FILE);
|
|
136
|
+
console.log(JSON.stringify({ success: true }, null, 2));
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
|
|
192
140
|
// ---------------------------------------------------------------------------
|
|
193
|
-
//
|
|
194
|
-
// 读取凭据文件 → 调用 verify-code 接口验证密文是否仍然有效
|
|
141
|
+
// 业务命令(mock,不调用真实 API)
|
|
195
142
|
// ---------------------------------------------------------------------------
|
|
196
143
|
|
|
197
|
-
|
|
144
|
+
function requireAuth(args) {
|
|
198
145
|
const config = readConfig();
|
|
146
|
+
const userCode = args.userCode || args.user_code || process.env.DXB_USER_CODE || config.userCode || "mock-user-code";
|
|
147
|
+
return { userCode };
|
|
148
|
+
}
|
|
199
149
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
config.userCode;
|
|
150
|
+
function requireTaskTarget(args) {
|
|
151
|
+
const config = readConfig();
|
|
152
|
+
const ptName = args.ptName;
|
|
153
|
+
const storeName =
|
|
154
|
+
args.storeName ||
|
|
155
|
+
args.defaultShop ||
|
|
156
|
+
args.defaultStoreName ||
|
|
157
|
+
process.env.DXB_STORE_NAME ||
|
|
158
|
+
config.defaultShop ||
|
|
159
|
+
config.defaultStoreName ||
|
|
160
|
+
"mock-store";
|
|
161
|
+
return { ptName, storeName };
|
|
162
|
+
}
|
|
214
163
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
connected: true,
|
|
220
|
-
valid: true,
|
|
221
|
-
account: config.account,
|
|
222
|
-
accountFromServer: result.account || null,
|
|
223
|
-
defaultShop: config.defaultShop
|
|
224
|
-
}, null, 2));
|
|
225
|
-
process.exit(0);
|
|
226
|
-
} catch (err) {
|
|
227
|
-
console.error(JSON.stringify({
|
|
228
|
-
success: false,
|
|
229
|
-
connected: false,
|
|
230
|
-
valid: false,
|
|
231
|
-
errorMessage: "凭据验证失败:密文无效或已过期,请重新登录",
|
|
232
|
-
detail: err.message,
|
|
233
|
-
response: err.response || null
|
|
234
|
-
}, null, 2));
|
|
235
|
-
process.exit(1);
|
|
164
|
+
async function postJson(baseUrl, pathName, body) {
|
|
165
|
+
const url = `${baseUrl}${pathName}`;
|
|
166
|
+
if (url.includes("/submit")) {
|
|
167
|
+
return { success: true, message: "Task submitted successfully", taskKey: body.taskKey };
|
|
236
168
|
}
|
|
169
|
+
if (url.includes("/aiReleaseStatus")) {
|
|
170
|
+
return { success: true, planId: body.planId, status: "processing" };
|
|
171
|
+
}
|
|
172
|
+
return { success: true, raw: body };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function printResult(data) {
|
|
176
|
+
console.log(JSON.stringify(data, null, 2));
|
|
237
177
|
}
|
|
238
178
|
|
|
239
179
|
// ---------------------------------------------------------------------------
|
|
240
|
-
//
|
|
180
|
+
// D4 · stdio MCP server stub
|
|
181
|
+
// 连接成功后框架会执行 npx -y @eprolo/eprolo-cli(无子命令)拉起 MCP
|
|
182
|
+
// stdout 只能输出 MCP 协议帧,调试日志走 stderr
|
|
241
183
|
// ---------------------------------------------------------------------------
|
|
242
184
|
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
185
|
+
function startMcpServer() {
|
|
186
|
+
// MCP stub:读凭据文件,通过 stdio 协议响应 tools/list 和 tools/call
|
|
187
|
+
const config = readConfig();
|
|
188
|
+
if (!config.userCode) {
|
|
189
|
+
console.error("未连接或凭据失效,请在 Accio Work 中重新连接");
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let inputBuffer = "";
|
|
194
|
+
process.stdin.setEncoding("utf8");
|
|
195
|
+
process.stdin.on("data", (chunk) => {
|
|
196
|
+
inputBuffer += chunk;
|
|
197
|
+
// MCP stdio 协议:消息以换行分隔的 JSON-RPC
|
|
198
|
+
let newlineIdx;
|
|
199
|
+
while ((newlineIdx = inputBuffer.indexOf("\n")) !== -1) {
|
|
200
|
+
const line = inputBuffer.slice(0, newlineIdx).trim();
|
|
201
|
+
inputBuffer = inputBuffer.slice(newlineIdx + 1);
|
|
202
|
+
if (line) handleMcpMessage(line);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
process.stdin.on("end", () => process.exit(0));
|
|
247
206
|
}
|
|
248
207
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
208
|
+
function handleMcpMessage(line) {
|
|
209
|
+
let msg;
|
|
210
|
+
try {
|
|
211
|
+
msg = JSON.parse(line);
|
|
212
|
+
} catch (_) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
252
215
|
|
|
253
|
-
|
|
254
|
-
console.log(`DXB CLI
|
|
216
|
+
const { id, method, params } = msg;
|
|
255
217
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
退出授权,删除凭据文件
|
|
218
|
+
if (method === "initialize") {
|
|
219
|
+
sendMcpResult(id, {
|
|
220
|
+
protocolVersion: "2024-11-05",
|
|
221
|
+
serverInfo: { name: "dxb-mcp", version: "1.0.0" },
|
|
222
|
+
capabilities: { tools: {} }
|
|
223
|
+
});
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
265
226
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
227
|
+
if (method === "tools/list") {
|
|
228
|
+
sendMcpResult(id, {
|
|
229
|
+
tools: [
|
|
230
|
+
{
|
|
231
|
+
name: "ai_release_products",
|
|
232
|
+
description: "AI 发品:用货源链接在指定店铺下自动发布商品",
|
|
233
|
+
inputSchema: {
|
|
234
|
+
type: "object",
|
|
235
|
+
properties: {
|
|
236
|
+
sourceUrlList: { type: "array", items: { type: "string" }, description: "货源链接列表" },
|
|
237
|
+
storeName: { type: "string", description: "目标授权店铺名(缺省用凭据里的默认店铺)" },
|
|
238
|
+
ptName: { type: "string", description: "目标平台,如 icbu" }
|
|
239
|
+
},
|
|
240
|
+
required: ["sourceUrlList"]
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "ai_release_status",
|
|
245
|
+
description: "查询 AI 发品计划状态",
|
|
246
|
+
inputSchema: {
|
|
247
|
+
type: "object",
|
|
248
|
+
properties: {
|
|
249
|
+
planId: { type: "string", description: "发品计划 ID" },
|
|
250
|
+
storeName: { type: "string", description: "目标授权店铺名" }
|
|
251
|
+
},
|
|
252
|
+
required: ["planId"]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
270
259
|
|
|
271
|
-
|
|
272
|
-
|
|
260
|
+
if (method === "tools/call") {
|
|
261
|
+
const { name, arguments: args } = params;
|
|
262
|
+
if (name === "ai_release_products") {
|
|
263
|
+
sendMcpResult(id, {
|
|
264
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
265
|
+
success: true,
|
|
266
|
+
message: "Task submitted successfully",
|
|
267
|
+
taskKey: taskKey("ai_release_products")
|
|
268
|
+
}) }]
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (name === "ai_release_status") {
|
|
273
|
+
sendMcpResult(id, {
|
|
274
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
275
|
+
success: true,
|
|
276
|
+
planId: args.planId,
|
|
277
|
+
status: "processing"
|
|
278
|
+
}) }]
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
sendMcpError(id, -32601, `Unknown tool: ${name}`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
273
285
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
286
|
+
sendMcpError(id, -32601, `Unknown method: ${method}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function sendMcpResult(id, result) {
|
|
290
|
+
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function sendMcpError(id, code, message) {
|
|
294
|
+
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n");
|
|
280
295
|
}
|
|
281
296
|
|
|
282
297
|
// ---------------------------------------------------------------------------
|
|
283
|
-
//
|
|
298
|
+
// 入口分发(D2 + D4)
|
|
299
|
+
// argv 有 "auth login" → 走 D2 登录
|
|
300
|
+
// 否则默认起 stdio MCP(D4)
|
|
284
301
|
// ---------------------------------------------------------------------------
|
|
285
302
|
|
|
286
303
|
async function main() {
|
|
287
304
|
const argv = process.argv.slice(2);
|
|
288
|
-
const [group, command] = argv;
|
|
289
305
|
|
|
290
|
-
|
|
291
|
-
|
|
306
|
+
// D2 · login
|
|
307
|
+
if (argv[0] === "auth" && argv[1] === "login") {
|
|
308
|
+
login(argv.slice(2));
|
|
292
309
|
return;
|
|
293
310
|
}
|
|
294
311
|
|
|
295
|
-
if (
|
|
296
|
-
|
|
312
|
+
if (argv[0] === "auth" && argv[1] === "status") {
|
|
313
|
+
authStatus();
|
|
297
314
|
return;
|
|
298
315
|
}
|
|
299
316
|
|
|
300
|
-
if (
|
|
301
|
-
|
|
317
|
+
if (argv[0] === "auth" && argv[1] === "logout") {
|
|
318
|
+
authLogout();
|
|
302
319
|
return;
|
|
303
320
|
}
|
|
304
321
|
|
|
305
|
-
|
|
306
|
-
|
|
322
|
+
// 兼容旧版 CLI 命令(batch submit / status ai)
|
|
323
|
+
if (argv[0] === "batch" && argv[1] === "submit") {
|
|
324
|
+
const args = parseArgs(argv.slice(2));
|
|
325
|
+
if (!args.action) throw new Error("batch submit requires --action");
|
|
326
|
+
if (args.action !== "ai_release_products") {
|
|
327
|
+
throw new Error("Only ai_release_products is supported.");
|
|
328
|
+
}
|
|
329
|
+
const auth = requireAuth(args);
|
|
330
|
+
const target = requireTaskTarget(args);
|
|
331
|
+
const body = {
|
|
332
|
+
action: args.action,
|
|
333
|
+
taskKey: args.taskKey || taskKey(args.action),
|
|
334
|
+
userCode: auth.userCode,
|
|
335
|
+
storeName: target.storeName,
|
|
336
|
+
productIds: splitIds(args.productIds)
|
|
337
|
+
};
|
|
338
|
+
if (target.ptName) body.ptName = target.ptName;
|
|
339
|
+
if (args.dataJson) body.data = JSON.parse(args.dataJson);
|
|
340
|
+
if (args.sourceUrlList) body.sourceUrlList = splitIds(args.sourceUrlList);
|
|
341
|
+
printResult(await postJson("", "/submit", body));
|
|
307
342
|
return;
|
|
308
343
|
}
|
|
309
344
|
|
|
310
|
-
if (
|
|
311
|
-
|
|
345
|
+
if (argv[0] === "status" && argv[1] === "ai") {
|
|
346
|
+
const args = parseArgs(argv.slice(2));
|
|
347
|
+
if (!args.planId) throw new Error("status ai requires --plan-id");
|
|
348
|
+
const auth = requireAuth(args);
|
|
349
|
+
const target = requireTaskTarget(args);
|
|
350
|
+
printResult(await postJson("", "/aiReleaseStatus", {
|
|
351
|
+
planId: args.planId,
|
|
352
|
+
userCode: auth.userCode,
|
|
353
|
+
storeName: target.storeName
|
|
354
|
+
}));
|
|
312
355
|
return;
|
|
313
356
|
}
|
|
314
357
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
|
|
358
|
+
if (argv[0] === "--help" || argv[0] === "-h" || argv.length === 0) {
|
|
359
|
+
printHelp();
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// D4 · 默认起 stdio MCP server
|
|
364
|
+
startMcpServer();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function printHelp() {
|
|
368
|
+
console.log(`DXB CLI (cli-login 形态)
|
|
369
|
+
|
|
370
|
+
Usage:
|
|
371
|
+
eprolo-cli auth login [--default-shop <shop>] 登录并写凭据文件(框架通过 env 注入 DXB_USER_CODE)
|
|
372
|
+
eprolo-cli auth status 查看授权状态
|
|
373
|
+
eprolo-cli auth logout 退出授权
|
|
374
|
+
eprolo-cli batch submit --action ai_release_products --source-url-list <urls> [--store-name <shop>]
|
|
375
|
+
eprolo-cli status ai --plan-id <planId> [--store-name <shop>]
|
|
376
|
+
eprolo-cli 启动 stdio MCP server(框架连接成功后自动拉起)
|
|
377
|
+
|
|
378
|
+
Authorization:
|
|
379
|
+
框架通过 fieldInjection 把表单值递交给 CLI:
|
|
380
|
+
userCode → env 通道 → process.env.DXB_USER_CODE
|
|
381
|
+
defaultShop → arg 通道 → --default-shop
|
|
382
|
+
|
|
383
|
+
连接成功的唯一判定:凭据文件 ~/.dxb-toolkit/config.json 出现
|
|
384
|
+
凭据文件顶层明文 account 字段用于授权卡片标签
|
|
385
|
+
|
|
386
|
+
Credential file (~/.dxb-toolkit/config.json):
|
|
387
|
+
{
|
|
388
|
+
"account": "user@example.com", // 顶层明文,框架读
|
|
389
|
+
"userCode": "...",
|
|
390
|
+
"defaultShop": "shop-001",
|
|
391
|
+
"version": 1
|
|
392
|
+
}
|
|
393
|
+
`);
|
|
320
394
|
}
|
|
321
395
|
|
|
322
396
|
main().catch((err) => {
|
package/package.json
CHANGED