yuanflow-cli 0.1.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YuanFlow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # yuanflow-cli
2
+
3
+ Agent-friendly local CLI wrapper for YuanFlow cloud APIs.
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g yuanflow-cli
9
+ ```
10
+
11
+ ## 初始化 token
12
+
13
+ 推荐直接写入本地配置:
14
+
15
+ ```bash
16
+ ycloud config set-token <your-token>
17
+ ```
18
+
19
+ 也支持环境变量:
20
+
21
+ ```bash
22
+ export YUANCHUANG_API_TOKEN=<your-token>
23
+ ```
24
+
25
+ Windows PowerShell:
26
+
27
+ ```powershell
28
+ $env:YUANCHUANG_API_TOKEN="<your-token>"
29
+ ```
30
+
31
+ ## 常用命令
32
+
33
+ ```bash
34
+ ycloud auth status
35
+ ycloud commands list --output json
36
+ ycloud health check --output json
37
+ ycloud social bilibili-fetch-one-video-v3 --url "https://www.bilibili.com/video/BV1GJ411x7h7" --output json
38
+ ```
39
+
40
+ ## 说明
41
+
42
+ 发布包由仓库内独立的 NPM 封装目录维护,不直接在业务源码根目录做发包逻辑。
43
+
44
+ ---
45
+
46
+ 下面内容面向仓库维护者。
47
+
48
+ ## 目录职责
49
+
50
+ - 独立维护 NPM 发布所需的 `package.json`
51
+ - 生成可发布的 `dist/` 目录
52
+ - 放安装说明、打包脚本、发布收口逻辑
53
+
54
+ ## 源码来源
55
+
56
+ 当前发布包源码来自仓库主源码目录:
57
+
58
+ - `../../src/ycloud`
59
+
60
+ 打包脚本会把这部分源码复制到:
61
+
62
+ - `./dist/src/ycloud`
63
+
64
+ 这样做的目的很简单:
65
+
66
+ - NPM 封装逻辑和 CLI 主源码分离
67
+ - 后续调整发布逻辑时,不容易和 CLI 开发逻辑冲突
68
+
69
+ ## 常用命令
70
+
71
+ ```powershell
72
+ npm run build
73
+ npm run check:version-sync
74
+ npm run check:publish
75
+ npm run pack:dry-run
76
+ npm run pack
77
+ ```
package/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import "./src/ycloud/cli.js";
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "yuanflow-cli",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "NPM packaging wrapper for YuanFlow CLI",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "bin": {
11
+ "ycloud": "cli.js"
12
+ },
13
+ "files": [
14
+ "cli.js",
15
+ "src",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "engines": {
20
+ "node": ">=20"
21
+ }
22
+ }
@@ -0,0 +1,29 @@
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
+ }
@@ -0,0 +1,82 @@
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
+ }
@@ -0,0 +1,191 @@
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
+ }
@@ -0,0 +1,262 @@
1
+ import { getGlobalFlagsHelp } from "./shared.js";
2
+
3
+ export function getCommandsHelp(subcommand) {
4
+ if (subcommand === "list") {
5
+ return `List all exposed CLI commands for Agent usage
6
+
7
+ Usage:
8
+ ycloud commands list
9
+
10
+ Optional Flags:
11
+ none
12
+
13
+ ${getGlobalFlagsHelp()}
14
+ `;
15
+ }
16
+
17
+ if (subcommand === "describe") {
18
+ return `Describe one exposed command
19
+
20
+ Usage:
21
+ ycloud commands describe <command-key>
22
+
23
+ Optional Flags:
24
+ none
25
+
26
+ ${getGlobalFlagsHelp()}
27
+
28
+ Examples:
29
+ ycloud commands describe auth.validate
30
+ ycloud commands describe social.bilibili-fetch-one-video-v3
31
+ `;
32
+ }
33
+
34
+ return `Commands discovery
35
+
36
+ Usage:
37
+ ycloud commands <list|describe> [flags]`;
38
+ }
39
+
40
+ function buildStaticCommands() {
41
+ return [
42
+ {
43
+ key: "auth.validate",
44
+ command: "auth validate",
45
+ kind: "api",
46
+ description: "Validate current API token",
47
+ api_path: "/v1/auth/validate",
48
+ method: "GET",
49
+ flags: [],
50
+ },
51
+ {
52
+ key: "auth.info",
53
+ command: "auth info",
54
+ kind: "api",
55
+ description: "Get current token account info",
56
+ api_path: "/v1/auth/info",
57
+ method: "GET",
58
+ flags: [],
59
+ },
60
+ {
61
+ key: "auth.charges",
62
+ command: "auth charges",
63
+ kind: "api",
64
+ description: "List token billing charge records",
65
+ api_path: "/v1/auth/charges",
66
+ method: "GET",
67
+ flags: [
68
+ { flag: "--model-id", required: false },
69
+ { flag: "--charge-type", required: false },
70
+ { flag: "--user-level", required: false },
71
+ { flag: "--start-at", required: false },
72
+ { flag: "--end-at", required: false },
73
+ { flag: "--limit", required: false },
74
+ { flag: "--offset", required: false },
75
+ ],
76
+ },
77
+ {
78
+ key: "auth.status",
79
+ command: "auth status",
80
+ kind: "local",
81
+ description: "Show current token source and masked token",
82
+ flags: [],
83
+ },
84
+ {
85
+ key: "health.check",
86
+ command: "health check",
87
+ kind: "api",
88
+ description: "Check cloud service health",
89
+ api_path: "/v1/health",
90
+ method: "GET",
91
+ flags: [],
92
+ },
93
+ {
94
+ key: "version.check",
95
+ command: "version check",
96
+ kind: "api",
97
+ description: "Check remote version update information",
98
+ api_path: "/v1/version/check",
99
+ method: "GET",
100
+ flags: [
101
+ { flag: "--app-id", required: false },
102
+ { flag: "--platform", required: false },
103
+ { flag: "--channel", required: false },
104
+ { flag: "--current-version", required: false },
105
+ { flag: "--current-build", required: false },
106
+ ],
107
+ },
108
+ {
109
+ key: "tool.catalog",
110
+ command: "tool catalog",
111
+ kind: "api",
112
+ description: "List server tool catalog",
113
+ api_path: "/v1/tools/catalog",
114
+ method: "GET",
115
+ flags: [],
116
+ },
117
+ {
118
+ key: "tool.execute",
119
+ command: "tool execute",
120
+ kind: "local",
121
+ description: "Execute only registered tool_id values through CLI",
122
+ flags: [
123
+ { flag: "--tool-id", required: true },
124
+ { flag: "--params", required: false },
125
+ { flag: "--params-file", required: false },
126
+ { flag: "--session-id", required: false },
127
+ { flag: "--idempotency-key", required: false },
128
+ ],
129
+ },
130
+ {
131
+ key: "kb.search",
132
+ command: "kb search",
133
+ kind: "api",
134
+ description: "Search knowledge base content",
135
+ api_path: "/v1/knowledge-base/search",
136
+ method: "POST",
137
+ flags: [
138
+ { flag: "--query", required: true },
139
+ { flag: "--top-k", required: false },
140
+ { flag: "--min-score", required: false },
141
+ { flag: "--course-name", required: false },
142
+ ],
143
+ },
144
+ {
145
+ key: "analysis.creator-profile",
146
+ command: "analysis creator-profile",
147
+ kind: "api",
148
+ description: "Analyze Douyin creator profile",
149
+ api_path: "/v1/analysis/douyin/creator-profile",
150
+ method: "POST",
151
+ flags: [
152
+ { flag: "--profile-url", required: true },
153
+ { flag: "--video-limit", required: false },
154
+ ],
155
+ },
156
+ {
157
+ key: "compliance.check",
158
+ command: "compliance check",
159
+ kind: "api",
160
+ description: "Check compliance risk for content",
161
+ api_path: "/v1/compliance/check",
162
+ method: "POST",
163
+ flags: [
164
+ { flag: "--content", required: false },
165
+ { flag: "--content-file", required: false },
166
+ { flag: "--project-id", required: false },
167
+ { flag: "--metadata", required: false },
168
+ { flag: "--metadata-file", required: false },
169
+ ],
170
+ },
171
+ {
172
+ key: "config.set-token",
173
+ command: "config set-token",
174
+ kind: "local",
175
+ description: "Store token into local CLI config file",
176
+ flags: [{ flag: "<token>", required: true }],
177
+ },
178
+ {
179
+ key: "config.get",
180
+ command: "config get",
181
+ kind: "local",
182
+ description: "Read current CLI config",
183
+ flags: [],
184
+ },
185
+ {
186
+ key: "config.clear-token",
187
+ command: "config clear-token",
188
+ kind: "local",
189
+ description: "Clear stored token from local CLI config",
190
+ flags: [],
191
+ },
192
+ ];
193
+ }
194
+
195
+ function buildToolCommands(toolRegistry, catalogMap) {
196
+ const rows = [];
197
+ for (const [domain, domainConfig] of Object.entries(toolRegistry)) {
198
+ for (const [subcommand, commandConfig] of Object.entries(domainConfig.commands)) {
199
+ const catalogItem = catalogMap.get(commandConfig.toolId);
200
+ const properties = catalogItem?.schema?.properties || {};
201
+ const flags = Object.keys(properties).map((name) => ({
202
+ flag: `--${name.replace(/_/g, "-")}`,
203
+ required: (catalogItem?.schema?.required || []).includes(name),
204
+ }));
205
+ rows.push({
206
+ key: `${domain}.${subcommand}`,
207
+ command: `${domain} ${subcommand}`,
208
+ kind: "tool",
209
+ description: catalogItem?.description || commandConfig.description,
210
+ tool_id: commandConfig.toolId,
211
+ exposed: true,
212
+ flags,
213
+ });
214
+ }
215
+ }
216
+ return rows;
217
+ }
218
+
219
+ export function buildExposedCommands(toolRegistry, catalogMap) {
220
+ return [
221
+ ...buildStaticCommands().map((item) => ({ ...item, exposed: true })),
222
+ ...buildToolCommands(toolRegistry, catalogMap),
223
+ ].sort((left, right) => left.command.localeCompare(right.command));
224
+ }
225
+
226
+ export async function executeCommandsList(context, exposedCommands) {
227
+ return context.ok("commands list", {
228
+ commands: exposedCommands.map((item) => ({
229
+ key: item.key,
230
+ command: item.command,
231
+ kind: item.kind,
232
+ exposed: true,
233
+ description: item.description,
234
+ })),
235
+ });
236
+ }
237
+
238
+ export async function executeCommandsDescribe(context, tokens, exposedCommands) {
239
+ const key = tokens[0];
240
+ if (!key) {
241
+ return context.fail(
242
+ "commands describe",
243
+ "BAD_ARGUMENT",
244
+ "缺少命令标识,例如 social.bilibili-fetch-one-video-v3",
245
+ 2,
246
+ false,
247
+ );
248
+ }
249
+
250
+ const match = exposedCommands.find((item) => item.key === key);
251
+ if (!match) {
252
+ return context.fail(
253
+ "commands describe",
254
+ "BAD_ARGUMENT",
255
+ `未找到命令: ${key}`,
256
+ 2,
257
+ false,
258
+ );
259
+ }
260
+
261
+ return context.ok("commands describe", match);
262
+ }