yuanflow-cli 0.1.0 → 0.1.2
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/LICENSE +1 -1
- package/README.md +34 -50
- package/bin/yuanflow-cli.js +26 -0
- package/bin/yuanflow-skill.cjs +334 -0
- package/generated/registry.json +24641 -0
- package/lib/skill-installer/agents.cjs +203 -0
- package/lib/skill-installer/discover-skills.cjs +79 -0
- package/lib/skill-installer/installer.cjs +300 -0
- package/lib/skill-installer/publish.cjs +53 -0
- package/lib/skill-installer/repo-source.cjs +162 -0
- package/package.json +57 -6
- package/scripts/generate-registry.js +174 -0
- package/skills/yuanflow-skill/SKILL.md +60 -0
- package/skills/yuanflow-skill/yuanflow-cli/SKILL.md +207 -0
- package/src/agent-protocol.js +169 -0
- package/src/cli.js +382 -0
- package/src/config.js +31 -0
- package/src/registry.js +45 -0
- package/src/request.js +97 -0
- package/src/shortcuts.js +346 -0
- package/cli.js +0 -3
- package/src/ycloud/cli.js +0 -29
- package/src/ycloud/commands/analysis.js +0 -82
- package/src/ycloud/commands/auth.js +0 -191
- package/src/ycloud/commands/commands.js +0 -262
- package/src/ycloud/commands/compliance.js +0 -146
- package/src/ycloud/commands/config.js +0 -103
- package/src/ycloud/commands/health.js +0 -35
- package/src/ycloud/commands/index.js +0 -381
- package/src/ycloud/commands/kb.js +0 -82
- package/src/ycloud/commands/schema.js +0 -229
- package/src/ycloud/commands/shared.js +0 -30
- package/src/ycloud/commands/tool-registry.js +0 -209
- package/src/ycloud/commands/tool-runner.js +0 -226
- package/src/ycloud/commands/tool.js +0 -178
- package/src/ycloud/commands/version.js +0 -84
- package/src/ycloud/core/config.js +0 -78
- package/src/ycloud/core/http.js +0 -133
- package/src/ycloud/core/token.js +0 -30
- package/src/ycloud/resources/.gitkeep +0 -1
- package/src/ycloud/resources/tool_catalog_full.json +0 -1
package/src/request.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { readConfig } from './config.js';
|
|
3
|
+
import { findEndpointByPath, normalizeSocialPath } from './registry.js';
|
|
4
|
+
|
|
5
|
+
export async function callEndpoint(socialPath, options = {}) {
|
|
6
|
+
const config = await readConfig();
|
|
7
|
+
const baseUrl = cleanBaseUrl(options.baseUrl || config.baseUrl);
|
|
8
|
+
const token = options.token || config.token || process.env.YUANFLOW_TOKEN || '';
|
|
9
|
+
const normalizedPath = normalizeSocialPath(socialPath);
|
|
10
|
+
const endpoint = findEndpointByPath(normalizedPath);
|
|
11
|
+
const method = options.method || endpoint?.method || 'POST';
|
|
12
|
+
const url = new URL(`/social${normalizedPath}`, baseUrl);
|
|
13
|
+
|
|
14
|
+
if (!token) {
|
|
15
|
+
throw new Error('缺少 token。请先执行 yuanflow-cli config set-token <你的令牌>');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const body = await resolveBody(options);
|
|
19
|
+
if (method.toUpperCase() === 'GET' && body && typeof body === 'object') {
|
|
20
|
+
for (const [key, value] of Object.entries(body)) {
|
|
21
|
+
if (value !== undefined && value !== null) {
|
|
22
|
+
url.searchParams.set(key, String(value));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (options.dryRun) {
|
|
28
|
+
return {
|
|
29
|
+
dryRun: true,
|
|
30
|
+
method: method.toUpperCase(),
|
|
31
|
+
url: url.toString(),
|
|
32
|
+
headers: {
|
|
33
|
+
Authorization: `Bearer ${maskToken(token)}`,
|
|
34
|
+
},
|
|
35
|
+
body: method.toUpperCase() === 'GET' ? undefined : body || {},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const response = await fetch(url, {
|
|
40
|
+
method: method.toUpperCase(),
|
|
41
|
+
headers: {
|
|
42
|
+
Authorization: `Bearer ${token}`,
|
|
43
|
+
Accept: 'application/json',
|
|
44
|
+
...(method.toUpperCase() === 'GET' ? {} : { 'Content-Type': 'application/json' }),
|
|
45
|
+
},
|
|
46
|
+
body: method.toUpperCase() === 'GET' ? undefined : JSON.stringify(body || {}),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const text = await response.text();
|
|
50
|
+
const payload = parseMaybeJson(text);
|
|
51
|
+
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const message = typeof payload === 'object' ? JSON.stringify(payload) : text;
|
|
54
|
+
throw new Error(`请求失败:HTTP ${response.status} ${message}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return payload;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function resolveBody(options) {
|
|
61
|
+
if (options.json) {
|
|
62
|
+
return JSON.parse(options.json);
|
|
63
|
+
}
|
|
64
|
+
if (options.file) {
|
|
65
|
+
const raw = await readFile(options.file, 'utf8');
|
|
66
|
+
return JSON.parse(raw);
|
|
67
|
+
}
|
|
68
|
+
if (options.body) {
|
|
69
|
+
return options.body;
|
|
70
|
+
}
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function cleanBaseUrl(value) {
|
|
75
|
+
return (value || 'https://open.yuanchuangai.com').replace(/\/+$/, '');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function parseMaybeJson(text) {
|
|
79
|
+
if (!text) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
return JSON.parse(text);
|
|
84
|
+
} catch {
|
|
85
|
+
return text;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function maskToken(token) {
|
|
90
|
+
if (!token) {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
if (token.length <= 10) {
|
|
94
|
+
return '***';
|
|
95
|
+
}
|
|
96
|
+
return `${token.slice(0, 6)}...${token.slice(-4)}`;
|
|
97
|
+
}
|
package/src/shortcuts.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
export const shortcuts = [
|
|
2
|
+
{
|
|
3
|
+
platform: 'douyin',
|
|
4
|
+
command: 'video-detail',
|
|
5
|
+
description: '抖音作品详情,适合用分享链接或作品链接查询作品基础数据。',
|
|
6
|
+
method: 'POST',
|
|
7
|
+
socialPath: '/douyin/app/v3/fetch_multi_video_v2',
|
|
8
|
+
positionals: [{ name: 'url', label: '作品链接' }],
|
|
9
|
+
options: [],
|
|
10
|
+
returns: '返回作品基础信息、作者信息、互动统计、媒体信息等字段,字段结构以上游实际响应为准。',
|
|
11
|
+
alternatives: [
|
|
12
|
+
'GET /social/douyin/app/v3/fetch_one_video_by_share_url?share_url=...',
|
|
13
|
+
'GET /social/douyin/web/fetch_one_video?aweme_id=...',
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
platform: 'douyin',
|
|
18
|
+
command: 'video-download',
|
|
19
|
+
description: '抖音视频播放/下载地址查询,常用于获取最高画质播放链接。',
|
|
20
|
+
method: 'GET',
|
|
21
|
+
socialPath: '/douyin/app/v3/fetch_video_high_quality_play_url',
|
|
22
|
+
positionals: [{ name: 'share_url', label: '作品链接或分享链接' }],
|
|
23
|
+
options: [{ flag: 'region', name: 'region', label: '地区,可选,如 CN' }],
|
|
24
|
+
returns: '返回视频播放地址、清晰度信息、媒体地址等;是否可直接下载取决于上游返回和目标平台限制。',
|
|
25
|
+
alternatives: [
|
|
26
|
+
'POST /social/douyin/app/v3/fetch_multi_video_high_quality_play_url',
|
|
27
|
+
'GET /social/douyin/web/fetch_video_high_quality_play_url',
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
platform: 'douyin',
|
|
32
|
+
command: 'user-profile',
|
|
33
|
+
description: '抖音作者主页信息查询,默认使用 sec_user_id。',
|
|
34
|
+
method: 'GET',
|
|
35
|
+
socialPath: '/douyin/web/handler_user_profile',
|
|
36
|
+
positionals: [{ name: 'sec_user_id', label: '作者 sec_user_id' }],
|
|
37
|
+
options: [],
|
|
38
|
+
returns: '返回作者昵称、头像、简介、粉丝关注统计、账号状态等用户资料字段。',
|
|
39
|
+
alternatives: [
|
|
40
|
+
'GET /social/douyin/web/handler_user_profile_v2?unique_id=...',
|
|
41
|
+
'GET /social/douyin/web/fetch_user_profile_by_uid?uid=...',
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
platform: 'douyin',
|
|
46
|
+
command: 'user-posts',
|
|
47
|
+
description: '抖音作者主页作品采集。',
|
|
48
|
+
method: 'GET',
|
|
49
|
+
socialPath: '/douyin/web/fetch_user_post_videos',
|
|
50
|
+
positionals: [{ name: 'sec_user_id', label: '作者 sec_user_id' }],
|
|
51
|
+
options: [
|
|
52
|
+
{ flag: 'cursor', name: 'max_cursor', label: '翻页游标' },
|
|
53
|
+
{ flag: 'count', name: 'count', label: '返回数量' },
|
|
54
|
+
{ flag: 'filter-type', name: 'filter_type', label: '筛选类型' },
|
|
55
|
+
{ flag: 'cookie', name: 'cookie', label: '可选 Cookie' },
|
|
56
|
+
],
|
|
57
|
+
returns: '返回作品列表、下一页游标、作者与作品基础字段,适合循环翻页采集。',
|
|
58
|
+
alternatives: ['GET /social/douyin/app/v3/fetch_user_post_videos'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
platform: 'douyin',
|
|
62
|
+
command: 'comments',
|
|
63
|
+
description: '抖音作品评论采集。',
|
|
64
|
+
method: 'GET',
|
|
65
|
+
socialPath: '/douyin/web/fetch_video_comments',
|
|
66
|
+
positionals: [{ name: 'aweme_id', label: '作品 aweme_id' }],
|
|
67
|
+
options: [
|
|
68
|
+
{ flag: 'cursor', name: 'cursor', label: '翻页游标' },
|
|
69
|
+
{ flag: 'count', name: 'count', label: '返回数量' },
|
|
70
|
+
],
|
|
71
|
+
returns: '返回评论列表、用户信息、评论统计和下一页游标。',
|
|
72
|
+
alternatives: ['GET /social/douyin/app/v3/fetch_video_comments'],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
platform: 'douyin',
|
|
76
|
+
command: 'hot-search',
|
|
77
|
+
description: '抖音热榜数据。',
|
|
78
|
+
method: 'GET',
|
|
79
|
+
socialPath: '/douyin/web/fetch_hot_search_result',
|
|
80
|
+
positionals: [],
|
|
81
|
+
options: [],
|
|
82
|
+
returns: '返回热榜条目、热度、排名等字段。',
|
|
83
|
+
alternatives: [],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
platform: 'xiaohongshu',
|
|
87
|
+
command: 'note-detail',
|
|
88
|
+
description: '小红书笔记详情查询。',
|
|
89
|
+
method: 'GET',
|
|
90
|
+
socialPath: '/xiaohongshu/web_v3/fetch_note_detail',
|
|
91
|
+
positionals: [{ name: 'note_id', label: '笔记 ID' }],
|
|
92
|
+
options: [{ flag: 'xsec-token', name: 'xsec_token', label: 'xsec_token,可选' }],
|
|
93
|
+
returns: '返回笔记正文、作者、图片/视频媒体、互动统计等字段。',
|
|
94
|
+
alternatives: ['GET /social/xiaohongshu/web/get_note_id_and_xsec_token?share_text=...'],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
platform: 'xiaohongshu',
|
|
98
|
+
command: 'note-comments',
|
|
99
|
+
description: '小红书笔记评论采集。',
|
|
100
|
+
method: 'GET',
|
|
101
|
+
socialPath: '/xiaohongshu/web_v3/fetch_note_comments',
|
|
102
|
+
positionals: [{ name: 'note_id', label: '笔记 ID' }],
|
|
103
|
+
options: [{ flag: 'cursor', name: 'cursor', label: '翻页游标' }],
|
|
104
|
+
returns: '返回评论列表、用户信息和下一页游标。',
|
|
105
|
+
alternatives: ['GET /social/xiaohongshu/web_v3/fetch_sub_comments'],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
platform: 'xiaohongshu',
|
|
109
|
+
command: 'search-notes',
|
|
110
|
+
description: '小红书笔记搜索。',
|
|
111
|
+
method: 'GET',
|
|
112
|
+
socialPath: '/xiaohongshu/web_v3/fetch_search_notes',
|
|
113
|
+
positionals: [{ name: 'keyword', label: '关键词' }],
|
|
114
|
+
options: [
|
|
115
|
+
{ flag: 'page', name: 'page', label: '页码' },
|
|
116
|
+
{ flag: 'sort', name: 'sort', label: '排序方式' },
|
|
117
|
+
{ flag: 'note-type', name: 'note_type', label: '笔记类型' },
|
|
118
|
+
],
|
|
119
|
+
returns: '返回搜索结果列表、笔记摘要、作者和分页信息。',
|
|
120
|
+
alternatives: ['GET /social/xiaohongshu/web/search_notes_v3'],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
platform: 'xiaohongshu',
|
|
124
|
+
command: 'search-users',
|
|
125
|
+
description: '小红书用户搜索。',
|
|
126
|
+
method: 'GET',
|
|
127
|
+
socialPath: '/xiaohongshu/web_v3/fetch_search_users',
|
|
128
|
+
positionals: [{ name: 'keyword', label: '关键词' }],
|
|
129
|
+
options: [{ flag: 'page', name: 'page', label: '页码' }],
|
|
130
|
+
returns: '返回用户列表、头像、简介、关注粉丝等摘要字段。',
|
|
131
|
+
alternatives: ['GET /social/xiaohongshu/web/search_users'],
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
platform: 'xiaohongshu',
|
|
135
|
+
command: 'user-notes',
|
|
136
|
+
description: '小红书作者主页笔记采集。',
|
|
137
|
+
method: 'GET',
|
|
138
|
+
socialPath: '/xiaohongshu/web/get_user_notes_v2',
|
|
139
|
+
positionals: [{ name: 'user_id', label: '作者 user_id' }],
|
|
140
|
+
options: [{ flag: 'cursor', name: 'lastCursor', label: '翻页游标' }],
|
|
141
|
+
returns: '返回作者笔记列表和下一页游标。',
|
|
142
|
+
alternatives: [],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
platform: 'bilibili',
|
|
146
|
+
command: 'video-detail',
|
|
147
|
+
description: 'B站视频详情,支持视频 URL。',
|
|
148
|
+
method: 'GET',
|
|
149
|
+
socialPath: '/bilibili/web/fetch_one_video_v3',
|
|
150
|
+
positionals: [{ name: 'url', label: '视频链接' }],
|
|
151
|
+
options: [],
|
|
152
|
+
returns: '返回视频标题、UP主、分P、统计、封面等基础信息。',
|
|
153
|
+
alternatives: [
|
|
154
|
+
'GET /social/bilibili/web/fetch_one_video?bv_id=...',
|
|
155
|
+
'GET /social/bilibili/app/fetch_one_video?bv_id=...',
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
platform: 'bilibili',
|
|
160
|
+
command: 'video-download',
|
|
161
|
+
description: 'B站视频播放信息查询,常用于获取可播放媒体信息。',
|
|
162
|
+
method: 'GET',
|
|
163
|
+
socialPath: '/bilibili/web/fetch_video_play_info',
|
|
164
|
+
positionals: [{ name: 'url', label: '视频链接' }],
|
|
165
|
+
options: [],
|
|
166
|
+
returns: '返回视频播放信息;如需要指定 cid,可改用 video-playurl。',
|
|
167
|
+
alternatives: ['GET /social/bilibili/web/fetch_video_playurl?bv_id=...&cid=...'],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
platform: 'bilibili',
|
|
171
|
+
command: 'video-playurl',
|
|
172
|
+
description: 'B站按 BV 号和 cid 获取视频流地址。',
|
|
173
|
+
method: 'GET',
|
|
174
|
+
socialPath: '/bilibili/web/fetch_video_playurl',
|
|
175
|
+
positionals: [
|
|
176
|
+
{ name: 'bv_id', label: 'BV 号' },
|
|
177
|
+
{ name: 'cid', label: '分P cid' },
|
|
178
|
+
],
|
|
179
|
+
options: [],
|
|
180
|
+
returns: '返回视频流地址与清晰度相关信息。',
|
|
181
|
+
alternatives: ['GET /social/bilibili/web/fetch_video_play_info?url=...'],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
platform: 'bilibili',
|
|
185
|
+
command: 'user-profile',
|
|
186
|
+
description: 'B站 UP 主信息查询。',
|
|
187
|
+
method: 'GET',
|
|
188
|
+
socialPath: '/bilibili/web/fetch_user_profile',
|
|
189
|
+
positionals: [{ name: 'uid', label: 'UP 主 uid' }],
|
|
190
|
+
options: [],
|
|
191
|
+
returns: '返回昵称、头像、简介、等级等用户资料。',
|
|
192
|
+
alternatives: ['GET /social/bilibili/app/fetch_user_info?user_id=...'],
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
platform: 'bilibili',
|
|
196
|
+
command: 'user-posts',
|
|
197
|
+
description: 'B站 UP 主投稿视频采集。',
|
|
198
|
+
method: 'GET',
|
|
199
|
+
socialPath: '/bilibili/web/fetch_user_post_videos',
|
|
200
|
+
positionals: [{ name: 'uid', label: 'UP 主 uid' }],
|
|
201
|
+
options: [
|
|
202
|
+
{ flag: 'page', name: 'pn', label: '页码' },
|
|
203
|
+
{ flag: 'order', name: 'order', label: '排序方式' },
|
|
204
|
+
],
|
|
205
|
+
returns: '返回投稿视频列表、分页和视频摘要字段。',
|
|
206
|
+
alternatives: ['GET /social/bilibili/app/fetch_user_videos?user_id=...'],
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
platform: 'bilibili',
|
|
210
|
+
command: 'search',
|
|
211
|
+
description: 'B站综合搜索。',
|
|
212
|
+
method: 'GET',
|
|
213
|
+
socialPath: '/bilibili/web/fetch_general_search',
|
|
214
|
+
positionals: [{ name: 'keyword', label: '关键词' }],
|
|
215
|
+
options: [
|
|
216
|
+
{ flag: 'order', name: 'order', label: '排序,默认 totalrank' },
|
|
217
|
+
{ flag: 'page', name: 'page', label: '页码,默认 1' },
|
|
218
|
+
{ flag: 'page-size', name: 'page_size', label: '每页数量,默认 20' },
|
|
219
|
+
{ flag: 'duration', name: 'duration', label: '时长筛选' },
|
|
220
|
+
],
|
|
221
|
+
defaults: { order: 'totalrank', page: '1', page_size: '20' },
|
|
222
|
+
returns: '返回搜索结果、视频摘要、UP主摘要和分页字段。',
|
|
223
|
+
alternatives: ['GET /social/bilibili/app/fetch_search_all'],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
platform: 'bilibili',
|
|
227
|
+
command: 'comments',
|
|
228
|
+
description: 'B站视频评论采集。',
|
|
229
|
+
method: 'GET',
|
|
230
|
+
socialPath: '/bilibili/web/fetch_video_comments',
|
|
231
|
+
positionals: [{ name: 'bv_id', label: 'BV 号' }],
|
|
232
|
+
options: [{ flag: 'page', name: 'pn', label: '页码' }],
|
|
233
|
+
returns: '返回评论列表、用户信息、互动统计和分页信息。',
|
|
234
|
+
alternatives: ['GET /social/bilibili/app/fetch_video_comments'],
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
platform: 'wechat',
|
|
238
|
+
command: 'channels-search',
|
|
239
|
+
description: '微信视频号综合搜索。',
|
|
240
|
+
method: 'GET',
|
|
241
|
+
socialPath: '/wechat_channels/fetch_search_ordinary',
|
|
242
|
+
positionals: [{ name: 'keywords', label: '关键词' }],
|
|
243
|
+
options: [],
|
|
244
|
+
returns: '返回视频号综合搜索结果。',
|
|
245
|
+
alternatives: ['GET /social/wechat_channels/fetch_search_latest?keywords=...'],
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
platform: 'wechat',
|
|
249
|
+
command: 'channels-latest',
|
|
250
|
+
description: '微信视频号最新视频搜索。',
|
|
251
|
+
method: 'GET',
|
|
252
|
+
socialPath: '/wechat_channels/fetch_search_latest',
|
|
253
|
+
positionals: [{ name: 'keywords', label: '关键词' }],
|
|
254
|
+
options: [],
|
|
255
|
+
returns: '返回按最新排序的视频号搜索结果。',
|
|
256
|
+
alternatives: ['GET /social/wechat_channels/fetch_search_ordinary?keywords=...'],
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
platform: 'wechat',
|
|
260
|
+
command: 'channels-user-search',
|
|
261
|
+
description: '微信视频号用户搜索。',
|
|
262
|
+
method: 'GET',
|
|
263
|
+
socialPath: '/wechat_channels/fetch_user_search',
|
|
264
|
+
positionals: [{ name: 'keywords', label: '关键词' }],
|
|
265
|
+
options: [{ flag: 'page', name: 'page', label: '页码' }],
|
|
266
|
+
returns: '返回视频号用户搜索结果和分页信息。',
|
|
267
|
+
alternatives: ['GET /social/wechat_channels/fetch_user_search_v2'],
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
platform: 'wechat',
|
|
271
|
+
command: 'channels-video-detail',
|
|
272
|
+
description: '微信视频号视频详情。',
|
|
273
|
+
method: 'GET',
|
|
274
|
+
socialPath: '/wechat_channels/fetch_video_detail',
|
|
275
|
+
positionals: [{ name: 'id', label: '视频 ID' }],
|
|
276
|
+
options: [{ flag: 'export-id', name: 'exportId', label: 'exportId,可选' }],
|
|
277
|
+
returns: '返回视频号视频详情、作者和媒体相关字段。',
|
|
278
|
+
alternatives: [],
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
platform: 'wechat',
|
|
282
|
+
command: 'channels-home',
|
|
283
|
+
description: '微信视频号主页采集,参数结构通常需要用 --json 传入上游要求的完整请求体。',
|
|
284
|
+
method: 'POST',
|
|
285
|
+
socialPath: '/wechat_channels/fetch_home_page',
|
|
286
|
+
positionals: [],
|
|
287
|
+
options: [],
|
|
288
|
+
returns: '返回视频号主页资料和作品列表,具体字段取决于请求体。',
|
|
289
|
+
alternatives: [],
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
platform: 'wechat',
|
|
293
|
+
command: 'mp-article-detail',
|
|
294
|
+
description: '微信公众号文章详情 JSON。',
|
|
295
|
+
method: 'GET',
|
|
296
|
+
socialPath: '/wechat_mp/web/fetch_mp_article_detail_json',
|
|
297
|
+
positionals: [{ name: 'url', label: '文章链接' }],
|
|
298
|
+
options: [],
|
|
299
|
+
returns: '返回公众号文章标题、正文结构、作者、发布时间等 JSON 字段。',
|
|
300
|
+
alternatives: ['GET /social/wechat_mp/web/fetch_mp_article_detail_html?url=...'],
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
platform: 'wechat',
|
|
304
|
+
command: 'mp-article-html',
|
|
305
|
+
description: '微信公众号文章详情 HTML。',
|
|
306
|
+
method: 'GET',
|
|
307
|
+
socialPath: '/wechat_mp/web/fetch_mp_article_detail_html',
|
|
308
|
+
positionals: [{ name: 'url', label: '文章链接' }],
|
|
309
|
+
options: [],
|
|
310
|
+
returns: '返回公众号文章 HTML 内容。',
|
|
311
|
+
alternatives: ['GET /social/wechat_mp/web/fetch_mp_article_detail_json?url=...'],
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
platform: 'wechat',
|
|
315
|
+
command: 'mp-article-list',
|
|
316
|
+
description: '微信公众号文章列表采集。',
|
|
317
|
+
method: 'GET',
|
|
318
|
+
socialPath: '/wechat_mp/web/fetch_mp_article_list',
|
|
319
|
+
positionals: [{ name: 'ghid', label: '公众号 ghid' }],
|
|
320
|
+
options: [{ flag: 'offset', name: 'offset', label: '偏移量' }],
|
|
321
|
+
returns: '返回公众号文章列表和分页偏移信息。',
|
|
322
|
+
alternatives: [],
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
platform: 'wechat',
|
|
326
|
+
command: 'mp-comments',
|
|
327
|
+
description: '微信公众号文章评论采集。',
|
|
328
|
+
method: 'GET',
|
|
329
|
+
socialPath: '/wechat_mp/web/fetch_mp_article_comment_list',
|
|
330
|
+
positionals: [{ name: 'url', label: '文章链接' }],
|
|
331
|
+
options: [
|
|
332
|
+
{ flag: 'comment-id', name: 'comment_id', label: 'comment_id,可选' },
|
|
333
|
+
{ flag: 'buffer', name: 'buffer', label: '分页 buffer,可选' },
|
|
334
|
+
],
|
|
335
|
+
returns: '返回文章评论列表、用户信息和分页 buffer。',
|
|
336
|
+
alternatives: ['GET /social/wechat_mp/web/fetch_mp_article_comment_reply_list'],
|
|
337
|
+
},
|
|
338
|
+
];
|
|
339
|
+
|
|
340
|
+
export function findShortcut(platform, command) {
|
|
341
|
+
return shortcuts.find((shortcut) => shortcut.platform === platform && shortcut.command === command);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export function listShortcuts(platform) {
|
|
345
|
+
return shortcuts.filter((shortcut) => (platform ? shortcut.platform === platform : true));
|
|
346
|
+
}
|
package/cli.js
DELETED
package/src/ycloud/cli.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { executeCommand } from "./commands/index.js";
|
|
4
|
-
|
|
5
|
-
const args = process.argv.slice(2);
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const { code, output } = await executeCommand(args);
|
|
9
|
-
process.stdout.write(output);
|
|
10
|
-
process.exitCode = code;
|
|
11
|
-
} catch (error) {
|
|
12
|
-
const mappedCode = error?.code || "INTERNAL_ERROR";
|
|
13
|
-
const mappedExitCode = error?.exitCode || 1;
|
|
14
|
-
const mappedRetryable = error?.retryable || false;
|
|
15
|
-
const payload = {
|
|
16
|
-
success: false,
|
|
17
|
-
command: args.slice(0, 2).join(" ").trim() || "unknown",
|
|
18
|
-
data: null,
|
|
19
|
-
warnings: [],
|
|
20
|
-
error: {
|
|
21
|
-
code: mappedCode,
|
|
22
|
-
message: error instanceof Error ? error.message : String(error),
|
|
23
|
-
retryable: mappedRetryable,
|
|
24
|
-
},
|
|
25
|
-
meta: {},
|
|
26
|
-
};
|
|
27
|
-
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
28
|
-
process.exitCode = mappedExitCode;
|
|
29
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { apiPost } from "../core/http.js";
|
|
2
|
-
import { getToken } from "../core/token.js";
|
|
3
|
-
import { getGlobalFlagsHelp, parseInteger } from "./shared.js";
|
|
4
|
-
|
|
5
|
-
export function getAnalysisHelp(subcommand) {
|
|
6
|
-
if (subcommand === "creator-profile") {
|
|
7
|
-
return `Analyze creator profile
|
|
8
|
-
|
|
9
|
-
Usage:
|
|
10
|
-
ycloud analysis creator-profile [flags]
|
|
11
|
-
|
|
12
|
-
Required Flags:
|
|
13
|
-
--profile-url string creator profile share URL
|
|
14
|
-
|
|
15
|
-
Optional Flags:
|
|
16
|
-
--video-limit int number of videos to analyze (default 20)
|
|
17
|
-
|
|
18
|
-
${getGlobalFlagsHelp()}
|
|
19
|
-
|
|
20
|
-
Examples:
|
|
21
|
-
ycloud analysis creator-profile --profile-url "https://v.douyin.com/xxxx/" --video-limit 20 --output json
|
|
22
|
-
|
|
23
|
-
Read on success:
|
|
24
|
-
data.profile
|
|
25
|
-
data.insights
|
|
26
|
-
|
|
27
|
-
Read on error:
|
|
28
|
-
error.code
|
|
29
|
-
error.message
|
|
30
|
-
error.retryable`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return `Analysis commands
|
|
34
|
-
|
|
35
|
-
Usage:
|
|
36
|
-
ycloud analysis <creator-profile> [flags]`;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function requireToken(context) {
|
|
40
|
-
const token = await getToken();
|
|
41
|
-
if (!token) {
|
|
42
|
-
return context.fail(
|
|
43
|
-
context.commandName,
|
|
44
|
-
"TOKEN_MISSING",
|
|
45
|
-
"缺少 YUANCHUANG_API_TOKEN",
|
|
46
|
-
3,
|
|
47
|
-
false,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return token;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function executeAnalysisCreatorProfile(context, tokens) {
|
|
54
|
-
const options = context.parseCommandFlags(tokens);
|
|
55
|
-
if (!options["profile-url"]) {
|
|
56
|
-
return context.fail(
|
|
57
|
-
"analysis creator-profile",
|
|
58
|
-
"BAD_ARGUMENT",
|
|
59
|
-
"缺少必填参数 --profile-url",
|
|
60
|
-
2,
|
|
61
|
-
false,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const token = await requireToken(context);
|
|
66
|
-
if (typeof token !== "string") {
|
|
67
|
-
return token;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const data = await apiPost("/v1/analysis/douyin/creator-profile", {
|
|
71
|
-
token,
|
|
72
|
-
traceId: context.globalOptions.traceId,
|
|
73
|
-
timeout: context.globalOptions.timeout,
|
|
74
|
-
baseUrl: context.globalOptions.baseUrl,
|
|
75
|
-
body: {
|
|
76
|
-
profile_url: options["profile-url"],
|
|
77
|
-
video_limit: parseInteger(options["video-limit"]) ?? 20,
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
return context.ok("analysis creator-profile", data);
|
|
82
|
-
}
|