yuanflow-cli 0.1.0 → 0.1.1

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.
Files changed (39) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +34 -50
  3. package/bin/yuanflow-cli.js +26 -0
  4. package/bin/yuanflow-skill.cjs +334 -0
  5. package/generated/registry.json +24641 -0
  6. package/lib/skill-installer/agents.cjs +203 -0
  7. package/lib/skill-installer/discover-skills.cjs +79 -0
  8. package/lib/skill-installer/installer.cjs +300 -0
  9. package/lib/skill-installer/publish.cjs +53 -0
  10. package/lib/skill-installer/repo-source.cjs +157 -0
  11. package/package.json +56 -6
  12. package/scripts/generate-registry.js +174 -0
  13. package/src/agent-protocol.js +169 -0
  14. package/src/cli.js +382 -0
  15. package/src/config.js +31 -0
  16. package/src/registry.js +45 -0
  17. package/src/request.js +97 -0
  18. package/src/shortcuts.js +346 -0
  19. package/cli.js +0 -3
  20. package/src/ycloud/cli.js +0 -29
  21. package/src/ycloud/commands/analysis.js +0 -82
  22. package/src/ycloud/commands/auth.js +0 -191
  23. package/src/ycloud/commands/commands.js +0 -262
  24. package/src/ycloud/commands/compliance.js +0 -146
  25. package/src/ycloud/commands/config.js +0 -103
  26. package/src/ycloud/commands/health.js +0 -35
  27. package/src/ycloud/commands/index.js +0 -381
  28. package/src/ycloud/commands/kb.js +0 -82
  29. package/src/ycloud/commands/schema.js +0 -229
  30. package/src/ycloud/commands/shared.js +0 -30
  31. package/src/ycloud/commands/tool-registry.js +0 -209
  32. package/src/ycloud/commands/tool-runner.js +0 -226
  33. package/src/ycloud/commands/tool.js +0 -178
  34. package/src/ycloud/commands/version.js +0 -84
  35. package/src/ycloud/core/config.js +0 -78
  36. package/src/ycloud/core/http.js +0 -133
  37. package/src/ycloud/core/token.js +0 -30
  38. package/src/ycloud/resources/.gitkeep +0 -1
  39. package/src/ycloud/resources/tool_catalog_full.json +0 -1
@@ -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
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import "./src/ycloud/cli.js";
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
- }
@@ -1,191 +0,0 @@
1
- import { apiGet } from "../core/http.js";
2
- import { getConfigPath, maskToken } from "../core/config.js";
3
- import { getToken, getTokenWithSource } from "../core/token.js";
4
- import { getGlobalFlagsHelp, parseInteger } from "./shared.js";
5
-
6
- export function getAuthHelp(subcommand) {
7
- if (subcommand === "validate") {
8
- return `Validate current API token
9
-
10
- Usage:
11
- ycloud auth validate [flags]
12
-
13
- Optional Flags:
14
- none
15
-
16
- ${getGlobalFlagsHelp()}
17
-
18
- Examples:
19
- ycloud auth validate --output json
20
-
21
- Read on success:
22
- success
23
- data
24
-
25
- Read on error:
26
- error.code
27
- error.message
28
- error.retryable`;
29
- }
30
-
31
- if (subcommand === "info") {
32
- return `Get current token account info
33
-
34
- Usage:
35
- ycloud auth info [flags]
36
-
37
- Optional Flags:
38
- none
39
-
40
- ${getGlobalFlagsHelp()}
41
-
42
- Examples:
43
- ycloud auth info --output json
44
-
45
- Read on success:
46
- data
47
-
48
- Read on error:
49
- error.code
50
- error.message
51
- error.retryable`;
52
- }
53
-
54
- if (subcommand === "charges") {
55
- return `List token billing charge records
56
-
57
- Usage:
58
- ycloud auth charges [flags]
59
-
60
- Optional Flags:
61
- --model-id string filter by model id
62
- --charge-type string filter by charge type
63
- --user-level string filter by user level
64
- --start-at string ISO datetime start
65
- --end-at string ISO datetime end
66
- --limit int page size, default 20
67
- --offset int offset, default 0
68
-
69
- ${getGlobalFlagsHelp()}
70
-
71
- Examples:
72
- ycloud auth charges --limit 20 --output json
73
-
74
- Read on success:
75
- data
76
-
77
- Read on error:
78
- error.code
79
- error.message
80
- error.retryable`;
81
- }
82
-
83
- if (subcommand === "status") {
84
- return `Show current token source and masked token
85
-
86
- Usage:
87
- ycloud auth status [flags]
88
-
89
- Optional Flags:
90
- none
91
-
92
- ${getGlobalFlagsHelp()}
93
- `;
94
- }
95
-
96
- return `Auth commands
97
-
98
- Usage:
99
- ycloud auth <validate|info|charges|status> [flags]`;
100
- }
101
-
102
- async function requireToken(context) {
103
- const token = await getToken();
104
- if (!token) {
105
- return context.fail(
106
- context.commandName,
107
- "TOKEN_MISSING",
108
- "缺少 YUANCHUANG_API_TOKEN",
109
- 3,
110
- false,
111
- );
112
- }
113
- return token;
114
- }
115
-
116
- export async function executeAuthInfo(context) {
117
- const token = await requireToken(context);
118
- if (typeof token !== "string") {
119
- return token;
120
- }
121
- const data = await apiGet("/v1/auth/info", {
122
- token,
123
- traceId: context.globalOptions.traceId,
124
- timeout: context.globalOptions.timeout,
125
- baseUrl: context.globalOptions.baseUrl,
126
- });
127
- return context.ok("auth info", data);
128
- }
129
-
130
- export async function executeAuthValidate(context) {
131
- const token = await requireToken(context);
132
- if (typeof token !== "string") {
133
- return token;
134
- }
135
- const data = await apiGet("/v1/auth/validate", {
136
- token,
137
- traceId: context.globalOptions.traceId,
138
- timeout: context.globalOptions.timeout,
139
- baseUrl: context.globalOptions.baseUrl,
140
- });
141
- return context.ok("auth validate", data);
142
- }
143
-
144
- export async function executeAuthCharges(context, tokens) {
145
- const token = await requireToken(context);
146
- if (typeof token !== "string") {
147
- return token;
148
- }
149
-
150
- const options = context.parseCommandFlags(tokens);
151
- const query = new URLSearchParams();
152
- const mapping = {
153
- "model-id": "model_id",
154
- "charge-type": "charge_type",
155
- "user-level": "user_level",
156
- "start-at": "start_at",
157
- "end-at": "end_at",
158
- };
159
-
160
- for (const [flag, field] of Object.entries(mapping)) {
161
- if (options[flag] !== undefined) {
162
- query.set(field, String(options[flag]));
163
- }
164
- }
165
-
166
- if (options.limit !== undefined) {
167
- query.set("limit", String(parseInteger(options.limit) ?? 20));
168
- }
169
- if (options.offset !== undefined) {
170
- query.set("offset", String(parseInteger(options.offset) ?? 0));
171
- }
172
-
173
- const suffix = query.toString() ? `?${query.toString()}` : "";
174
- const data = await apiGet(`/v1/auth/charges${suffix}`, {
175
- token,
176
- traceId: context.globalOptions.traceId,
177
- timeout: context.globalOptions.timeout,
178
- baseUrl: context.globalOptions.baseUrl,
179
- });
180
- return context.ok("auth charges", data);
181
- }
182
-
183
- export async function executeAuthStatus(context) {
184
- const { token, source } = await getTokenWithSource();
185
- return context.ok("auth status", {
186
- token_present: Boolean(token),
187
- token_source: source,
188
- token_masked: maskToken(token),
189
- config_path: getConfigPath(),
190
- });
191
- }