@yixinkj/cli 1.0.5 → 1.0.7
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 +10 -10
- package/index.js +61 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,11 +15,11 @@ npx -y @yixinkj/cli@latest
|
|
|
15
15
|
推荐环境变量:
|
|
16
16
|
|
|
17
17
|
```text
|
|
18
|
-
|
|
19
|
-
YIXIN_AUTH_URL=
|
|
18
|
+
YIXIN_PHONE=你的手机号
|
|
19
|
+
YIXIN_AUTH_URL=http://47.237.81.135:3000/v1/token
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
`YIXIN_AUTH_URL` 已内置默认值,普通用户只需要填写 `YIXIN_PHONE`。也可以通过 MCP tool `configure_auth` 写入本机配置;环境变量优先于本机配置。
|
|
23
23
|
|
|
24
24
|
## 工具
|
|
25
25
|
|
|
@@ -29,15 +29,15 @@ YIXIN_AUTH_URL=https://你的授权服务域名/v1/token
|
|
|
29
29
|
|
|
30
30
|
```json
|
|
31
31
|
{
|
|
32
|
-
"
|
|
33
|
-
"authUrl": "
|
|
32
|
+
"phone": "客户授权手机号",
|
|
33
|
+
"authUrl": "http://47.237.81.135:3000/v1/token",
|
|
34
34
|
"skill": "ads"
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
执行流程:
|
|
39
39
|
|
|
40
|
-
1. 使用传入的 `
|
|
40
|
+
1. 使用传入的 `phone`、`authUrl` 向授权服务换取一次短期 token。
|
|
41
41
|
2. 验证成功后写入 `~/.yixin/config.json`。
|
|
42
42
|
3. 文件权限尽量设置为 `0600`。
|
|
43
43
|
4. 环境变量仍然优先;环境变量缺失时才读取本机配置。
|
|
@@ -56,8 +56,8 @@ YIXIN_AUTH_URL=https://你的授权服务域名/v1/token
|
|
|
56
56
|
|
|
57
57
|
1. 检查当前平台是否支持。
|
|
58
58
|
2. 如当前版本二进制尚未安装,则从公开 GitHub Release 下载对应平台包并解压到 `~/.yixin/bin`。
|
|
59
|
-
3. 从环境变量或 `~/.yixin/config.json`
|
|
60
|
-
4. 向授权服务提交 `{
|
|
59
|
+
3. 从环境变量或 `~/.yixin/config.json` 读取授权手机号;授权服务地址默认使用 `http://47.237.81.135:3000/v1/token`,也可由配置覆盖。
|
|
60
|
+
4. 向授权服务提交 `{ phone, skill, version }`。
|
|
61
61
|
5. 返回自检结果;不会生成广告报告。
|
|
62
62
|
|
|
63
63
|
### run_ads_report
|
|
@@ -72,8 +72,8 @@ YIXIN_AUTH_URL=https://你的授权服务域名/v1/token
|
|
|
72
72
|
|
|
73
73
|
执行流程:
|
|
74
74
|
|
|
75
|
-
1. 从环境变量或 `~/.yixin/config.json`
|
|
76
|
-
2. 向授权服务提交 `{
|
|
75
|
+
1. 从环境变量或 `~/.yixin/config.json` 读取授权手机号;授权服务地址默认使用 `http://47.237.81.135:3000/v1/token`,也可由配置覆盖。
|
|
76
|
+
2. 向授权服务提交 `{ phone, skill: "ads", version }`。
|
|
77
77
|
3. 获取短期授权 token。
|
|
78
78
|
4. 如当前版本二进制尚未安装,则从公开 GitHub Release 下载对应平台包并解压到 `~/.yixin/bin`。
|
|
79
79
|
5. 使用以下参数运行 `~/.yixin/bin/alibaba-cli-{platform}`:
|
package/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const CACHE_ROOT = path.join(os.homedir(), '.yixin');
|
|
|
21
21
|
const BIN_DIR = path.join(os.homedir(), '.yixin', 'bin');
|
|
22
22
|
const VERSION_FILE = path.join(CACHE_ROOT, 'version');
|
|
23
23
|
const CONFIG_FILE = path.join(CACHE_ROOT, 'config.json');
|
|
24
|
+
const DEFAULT_AUTH_URL = process.env.YIXIN_DEFAULT_AUTH_URL || 'http://47.237.81.135:3000/v1/token';
|
|
24
25
|
|
|
25
26
|
const PLATFORM_TARGETS = {
|
|
26
27
|
'darwin-arm64': {
|
|
@@ -115,16 +116,23 @@ function writeLocalConfig(config) {
|
|
|
115
116
|
|
|
116
117
|
function getAuthSettings() {
|
|
117
118
|
const localConfig = readLocalConfig();
|
|
118
|
-
const
|
|
119
|
+
const envPhone = String(process.env.YIXIN_PHONE || '').trim();
|
|
120
|
+
const envLegacyKey = String(process.env.YIXIN_KEY || '').trim();
|
|
119
121
|
const envAuthUrl = String(process.env.YIXIN_AUTH_URL || '').trim();
|
|
120
|
-
const
|
|
122
|
+
const localPhone = String(localConfig.yixinPhone || localConfig.yixinKey || '').trim();
|
|
121
123
|
const localAuthUrl = String(localConfig.yixinAuthUrl || '').trim();
|
|
124
|
+
const phone = envPhone || envLegacyKey || localPhone;
|
|
125
|
+
const authUrl = envAuthUrl || localAuthUrl || DEFAULT_AUTH_URL;
|
|
122
126
|
|
|
123
127
|
return {
|
|
124
|
-
|
|
125
|
-
authUrl
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
phone,
|
|
129
|
+
authUrl,
|
|
130
|
+
phoneSource: envPhone
|
|
131
|
+
? 'env:YIXIN_PHONE'
|
|
132
|
+
: (envLegacyKey ? 'env:YIXIN_KEY' : (localPhone ? CONFIG_FILE : 'missing')),
|
|
133
|
+
authUrlSource: envAuthUrl
|
|
134
|
+
? 'env:YIXIN_AUTH_URL'
|
|
135
|
+
: (localAuthUrl ? CONFIG_FILE : 'default')
|
|
128
136
|
};
|
|
129
137
|
}
|
|
130
138
|
|
|
@@ -226,8 +234,21 @@ function chmodExecutables(target) {
|
|
|
226
234
|
}
|
|
227
235
|
}
|
|
228
236
|
|
|
237
|
+
function clearMacQuarantine() {
|
|
238
|
+
if (process.platform !== 'darwin' || !fs.existsSync(BIN_DIR)) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const result = spawnSync('xattr', ['-dr', 'com.apple.quarantine', BIN_DIR], {
|
|
242
|
+
encoding: 'utf8'
|
|
243
|
+
});
|
|
244
|
+
if (result.error && result.error.code !== 'ENOENT') {
|
|
245
|
+
console.error(`[yixin] macOS 安全隔离标记清理失败:${result.error.message}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
229
249
|
async function ensureInstalled(target) {
|
|
230
250
|
if (isInstalled(target)) {
|
|
251
|
+
clearMacQuarantine();
|
|
231
252
|
chmodExecutables(target);
|
|
232
253
|
return;
|
|
233
254
|
}
|
|
@@ -241,6 +262,7 @@ async function ensureInstalled(target) {
|
|
|
241
262
|
console.error(`[yixin] 正在下载 ${url}`);
|
|
242
263
|
await downloadFile(url, archivePath);
|
|
243
264
|
extractArchive(archivePath, target);
|
|
265
|
+
clearMacQuarantine();
|
|
244
266
|
chmodExecutables(target);
|
|
245
267
|
|
|
246
268
|
for (const name of target.binaries) {
|
|
@@ -256,14 +278,14 @@ async function ensureInstalled(target) {
|
|
|
256
278
|
}
|
|
257
279
|
}
|
|
258
280
|
|
|
259
|
-
async function requestToken({
|
|
281
|
+
async function requestToken({ phone, skill, version, authUrl }) {
|
|
260
282
|
const normalizedAuthUrl = String(authUrl || '').trim();
|
|
261
283
|
if (!normalizedAuthUrl) {
|
|
262
284
|
throw new Error('未配置授权服务器地址,请添加 YIXIN_AUTH_URL');
|
|
263
285
|
}
|
|
264
286
|
|
|
265
287
|
const url = new URL(normalizedAuthUrl);
|
|
266
|
-
const body = JSON.stringify({
|
|
288
|
+
const body = JSON.stringify({ phone, skill, version });
|
|
267
289
|
const client = url.protocol === 'https:' ? https : http;
|
|
268
290
|
|
|
269
291
|
return new Promise((resolve, reject) => {
|
|
@@ -308,15 +330,12 @@ async function requestToken({ key, skill, version, authUrl }) {
|
|
|
308
330
|
|
|
309
331
|
async function authorize(skill) {
|
|
310
332
|
const settings = getAuthSettings();
|
|
311
|
-
const
|
|
312
|
-
if (!
|
|
313
|
-
throw new Error('
|
|
314
|
-
}
|
|
315
|
-
if (!settings.authUrl) {
|
|
316
|
-
throw new Error('未配置授权服务器地址,请在 MCP 客户端环境变量里添加 YIXIN_AUTH_URL,或调用 configure_auth 写入本机配置');
|
|
333
|
+
const phone = settings.phone;
|
|
334
|
+
if (!phone) {
|
|
335
|
+
throw new Error('未配置授权手机号,请在 MCP 客户端环境变量里添加 YIXIN_PHONE=手机号,或调用 configure_auth 写入本机配置');
|
|
317
336
|
}
|
|
318
337
|
|
|
319
|
-
const auth = await requestToken({
|
|
338
|
+
const auth = await requestToken({ phone, skill, version: VERSION, authUrl: settings.authUrl });
|
|
320
339
|
if (!auth || auth.valid !== true || !auth.token) {
|
|
321
340
|
throw new Error(auth && auth.reason ? auth.reason : '授权失败');
|
|
322
341
|
}
|
|
@@ -373,19 +392,20 @@ async function checkAuth({ skill }) {
|
|
|
373
392
|
`skill: ${normalizedSkill}`,
|
|
374
393
|
`platform: ${target.id}`,
|
|
375
394
|
`binary: ${binaryPath(target)}`,
|
|
376
|
-
`
|
|
395
|
+
`phone_source: ${settings.phoneSource}`,
|
|
377
396
|
`auth_url_source: ${settings.authUrlSource}`,
|
|
378
397
|
`config_file: ${CONFIG_FILE}`
|
|
379
398
|
].join('\n');
|
|
380
399
|
}
|
|
381
400
|
|
|
382
|
-
async function configureAuth({
|
|
383
|
-
const
|
|
384
|
-
const
|
|
401
|
+
async function configureAuth({ phone, authUrl, skill }) {
|
|
402
|
+
const normalizedPhone = String(phone || '').trim();
|
|
403
|
+
const hasCustomAuthUrl = authUrl !== undefined && authUrl !== null && String(authUrl).trim() !== '';
|
|
404
|
+
const normalizedAuthUrl = hasCustomAuthUrl ? String(authUrl).trim() : DEFAULT_AUTH_URL;
|
|
385
405
|
const normalizedSkill = String(skill || 'ads').trim() || 'ads';
|
|
386
406
|
|
|
387
|
-
if (!
|
|
388
|
-
throw new Error('
|
|
407
|
+
if (!normalizedPhone) {
|
|
408
|
+
throw new Error('phone 不能为空');
|
|
389
409
|
}
|
|
390
410
|
if (!normalizedAuthUrl) {
|
|
391
411
|
throw new Error('authUrl 不能为空');
|
|
@@ -397,7 +417,7 @@ async function configureAuth({ key, authUrl, skill }) {
|
|
|
397
417
|
}
|
|
398
418
|
|
|
399
419
|
const auth = await requestToken({
|
|
400
|
-
|
|
420
|
+
phone: normalizedPhone,
|
|
401
421
|
skill: normalizedSkill,
|
|
402
422
|
version: VERSION,
|
|
403
423
|
authUrl: normalizedAuthUrl
|
|
@@ -407,16 +427,23 @@ async function configureAuth({ key, authUrl, skill }) {
|
|
|
407
427
|
}
|
|
408
428
|
|
|
409
429
|
const existingConfig = readLocalConfig();
|
|
410
|
-
|
|
430
|
+
const nextConfig = {
|
|
411
431
|
...existingConfig,
|
|
412
|
-
|
|
413
|
-
yixinAuthUrl: normalizedAuthUrl,
|
|
432
|
+
yixinPhone: normalizedPhone,
|
|
414
433
|
updatedAt: new Date().toISOString()
|
|
415
|
-
}
|
|
434
|
+
};
|
|
435
|
+
delete nextConfig.yixinKey;
|
|
436
|
+
if (hasCustomAuthUrl) {
|
|
437
|
+
nextConfig.yixinAuthUrl = normalizedAuthUrl;
|
|
438
|
+
} else {
|
|
439
|
+
delete nextConfig.yixinAuthUrl;
|
|
440
|
+
}
|
|
441
|
+
writeLocalConfig(nextConfig);
|
|
416
442
|
|
|
417
443
|
return [
|
|
418
444
|
'Yixin 授权配置已写入本机',
|
|
419
445
|
`skill: ${normalizedSkill}`,
|
|
446
|
+
`auth_url: ${hasCustomAuthUrl ? normalizedAuthUrl : `${DEFAULT_AUTH_URL} (default)`}`,
|
|
420
447
|
`config_file: ${CONFIG_FILE}`,
|
|
421
448
|
'后续 check_auth/run_ads_report 会优先使用环境变量;环境变量缺失时使用本机配置'
|
|
422
449
|
].join('\n');
|
|
@@ -432,24 +459,24 @@ function registerTools(server) {
|
|
|
432
459
|
'configure_auth',
|
|
433
460
|
{
|
|
434
461
|
title: 'Configure Auth',
|
|
435
|
-
description: '
|
|
462
|
+
description: '验证并保存译心授权手机号到本机配置;授权服务地址默认内置,也可用 authUrl 或 YIXIN_AUTH_URL 覆盖。',
|
|
436
463
|
inputSchema: {
|
|
437
|
-
|
|
464
|
+
phone: z
|
|
438
465
|
.string()
|
|
439
466
|
.min(1)
|
|
440
|
-
.describe('
|
|
467
|
+
.describe('客户授权手机号。'),
|
|
441
468
|
authUrl: z
|
|
442
469
|
.string()
|
|
443
|
-
.
|
|
444
|
-
.describe(
|
|
470
|
+
.optional()
|
|
471
|
+
.describe(`授权服务地址,默认 ${DEFAULT_AUTH_URL}。`),
|
|
445
472
|
skill: z
|
|
446
473
|
.string()
|
|
447
474
|
.optional()
|
|
448
475
|
.describe('授权能力名,默认 ads。')
|
|
449
476
|
}
|
|
450
477
|
},
|
|
451
|
-
async ({
|
|
452
|
-
const stdout = await configureAuth({
|
|
478
|
+
async ({ phone, authUrl, skill }) => {
|
|
479
|
+
const stdout = await configureAuth({ phone, authUrl, skill });
|
|
453
480
|
return {
|
|
454
481
|
content: [{ type: 'text', text: stdout }]
|
|
455
482
|
};
|
|
@@ -460,7 +487,7 @@ function registerTools(server) {
|
|
|
460
487
|
'check_auth',
|
|
461
488
|
{
|
|
462
489
|
title: 'Check Auth',
|
|
463
|
-
description: '检查译心 MCP
|
|
490
|
+
description: '检查译心 MCP 环境、二进制安装和授权手机号是否可用;不生成广告报告。',
|
|
464
491
|
inputSchema: {
|
|
465
492
|
skill: z
|
|
466
493
|
.string()
|