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.
Files changed (41) 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 +162 -0
  11. package/package.json +57 -6
  12. package/scripts/generate-registry.js +174 -0
  13. package/skills/yuanflow-skill/SKILL.md +60 -0
  14. package/skills/yuanflow-skill/yuanflow-cli/SKILL.md +207 -0
  15. package/src/agent-protocol.js +169 -0
  16. package/src/cli.js +382 -0
  17. package/src/config.js +31 -0
  18. package/src/registry.js +45 -0
  19. package/src/request.js +97 -0
  20. package/src/shortcuts.js +346 -0
  21. package/cli.js +0 -3
  22. package/src/ycloud/cli.js +0 -29
  23. package/src/ycloud/commands/analysis.js +0 -82
  24. package/src/ycloud/commands/auth.js +0 -191
  25. package/src/ycloud/commands/commands.js +0 -262
  26. package/src/ycloud/commands/compliance.js +0 -146
  27. package/src/ycloud/commands/config.js +0 -103
  28. package/src/ycloud/commands/health.js +0 -35
  29. package/src/ycloud/commands/index.js +0 -381
  30. package/src/ycloud/commands/kb.js +0 -82
  31. package/src/ycloud/commands/schema.js +0 -229
  32. package/src/ycloud/commands/shared.js +0 -30
  33. package/src/ycloud/commands/tool-registry.js +0 -209
  34. package/src/ycloud/commands/tool-runner.js +0 -226
  35. package/src/ycloud/commands/tool.js +0 -178
  36. package/src/ycloud/commands/version.js +0 -84
  37. package/src/ycloud/core/config.js +0 -78
  38. package/src/ycloud/core/http.js +0 -133
  39. package/src/ycloud/core/token.js +0 -30
  40. package/src/ycloud/resources/.gitkeep +0 -1
  41. package/src/ycloud/resources/tool_catalog_full.json +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 YuanFlow
3
+ Copyright (c) 2026 zktlove
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,77 +1,61 @@
1
1
  # yuanflow-cli
2
2
 
3
- Agent-friendly local CLI wrapper for YuanFlow cloud APIs.
3
+ YuanFlow npm 包,包含两个命令入口:
4
+
5
+ - `yuanflow-cli`:社媒 API 转 CLI,覆盖完整 registry、快捷命令、schema、dry-run 和 agent-json 输出。
6
+ - `yuanflow-skill`:把 `YuanFlow-skill` 注入到本机支持的 AI Agent skills 目录。
4
7
 
5
8
  ## 安装
6
9
 
10
+ 需要 Node.js 20 或更高版本。
11
+
7
12
  ```bash
8
13
  npm install -g yuanflow-cli
9
14
  ```
10
15
 
11
- ## 初始化 token
12
-
13
- 推荐直接写入本地配置:
16
+ 安装后可用:
14
17
 
15
18
  ```bash
16
- ycloud config set-token <your-token>
19
+ yuanflow-cli --help
20
+ yuanflow-skill list-agents
17
21
  ```
18
22
 
19
- 也支持环境变量:
23
+ ## API CLI
20
24
 
21
25
  ```bash
22
- export YUANCHUANG_API_TOKEN=<your-token>
26
+ yuanflow-cli config set-token <你的令牌>
27
+ yuanflow-cli config set-base-url https://open.yuanchuangai.com
28
+ yuanflow-cli douyin video-detail "https://v.douyin.com/xxx/" --format agent-json
29
+ yuanflow-cli shortcuts douyin
30
+ yuanflow-cli commands list
31
+ yuanflow-cli schema douyin.video-detail
32
+ yuanflow-cli list douyin
23
33
  ```
24
34
 
25
- Windows PowerShell:
35
+ 环境变量:
26
36
 
27
- ```powershell
28
- $env:YUANCHUANG_API_TOKEN="<your-token>"
37
+ ```bash
38
+ YUANFLOW_TOKEN=<你的令牌>
29
39
  ```
30
40
 
31
- ## 常用命令
41
+ ## Skill 安装器
32
42
 
33
43
  ```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
44
+ yuanflow-skill list-agents
45
+ yuanflow-skill list-skills
46
+ yuanflow-skill install
47
+ yuanflow-skill install --agent codex,cursor
48
+ yuanflow-skill install --project
49
+ yuanflow-skill install --dry-run
50
+ yuanflow-skill uninstall --agent codex
38
51
  ```
39
52
 
40
- ## 说明
41
-
42
- 发布包由仓库内独立的 NPM 封装目录维护,不直接在业务源码根目录做发包逻辑。
43
-
44
- ---
45
-
46
- 下面内容面向仓库维护者。
47
-
48
- ## 目录职责
49
-
50
- - 独立维护 NPM 发布所需的 `package.json`
51
- - 生成可发布的 `dist/` 目录
52
- - 放安装说明、打包脚本、发布收口逻辑
53
+ 安装器会自动发现 `YuanFlow-skill` 根目录和一级子目录中的 `SKILL.md`,并以 `yuanflow-skill` bundle 形式注入到目标 Agent。
53
54
 
54
- ## 源码来源
55
+ ## 开发检查
55
56
 
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
57
+ ```bash
58
+ npm test
59
+ npm run pack:check
60
+ npm run release:check
77
61
  ```
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../src/cli.js';
4
+ import { createAgentError } from '../src/agent-protocol.js';
5
+
6
+ function parseFormat(argv) {
7
+ const index = argv.indexOf('--format');
8
+ if (index === -1) {
9
+ return '';
10
+ }
11
+ return argv[index + 1] || '';
12
+ }
13
+
14
+ main(process.argv).catch((error) => {
15
+ if (parseFormat(process.argv.slice(2)) === 'agent-json') {
16
+ const { payload, exitCode } = createAgentError(
17
+ process.argv.slice(2, 4).filter((item) => !item.startsWith('--')).join(' '),
18
+ error,
19
+ );
20
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
21
+ process.exitCode = exitCode;
22
+ return;
23
+ }
24
+ console.error(error?.message || error);
25
+ process.exitCode = 1;
26
+ });
@@ -0,0 +1,334 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { execFileSync } = require('node:child_process');
6
+
7
+ const { getSupportedAgents, detectInstalledAgents, getAgentConfig } = require('../lib/skill-installer/agents.cjs');
8
+ const { discoverSkills } = require('../lib/skill-installer/discover-skills.cjs');
9
+ const { installSkills, uninstallSkills } = require('../lib/skill-installer/installer.cjs');
10
+ const { buildReleaseChecklist } = require('../lib/skill-installer/publish.cjs');
11
+ const { prepareSkillSource, readRepositoryConfig } = require('../lib/skill-installer/repo-source.cjs');
12
+
13
+ function print(message = '') {
14
+ process.stdout.write(`${message}\n`);
15
+ }
16
+
17
+ function printError(message) {
18
+ process.stderr.write(`${message}\n`);
19
+ }
20
+
21
+ function parseArgs(argv) {
22
+ const args = { _: [] };
23
+
24
+ for (let index = 0; index < argv.length; index += 1) {
25
+ const current = argv[index];
26
+
27
+ if (current === '--agent') {
28
+ args.agent = (argv[index + 1] || '')
29
+ .split(',')
30
+ .map((item) => item.trim())
31
+ .filter(Boolean);
32
+ index += 1;
33
+ continue;
34
+ }
35
+
36
+ if (current === '--mode') {
37
+ args.mode = argv[index + 1] || 'symlink';
38
+ index += 1;
39
+ continue;
40
+ }
41
+
42
+ if (current === '--scope') {
43
+ args.scope = argv[index + 1] || 'global';
44
+ index += 1;
45
+ continue;
46
+ }
47
+
48
+ if (current === '--skill') {
49
+ args.skill = (argv[index + 1] || '')
50
+ .split(',')
51
+ .map((item) => item.trim())
52
+ .filter(Boolean);
53
+ index += 1;
54
+ continue;
55
+ }
56
+
57
+ if (current === '--dry-run') {
58
+ args.dryRun = true;
59
+ continue;
60
+ }
61
+
62
+ if (current === '--project') {
63
+ args.scope = 'project';
64
+ continue;
65
+ }
66
+
67
+ if (current === '--global') {
68
+ args.scope = 'global';
69
+ continue;
70
+ }
71
+
72
+ if (current === '--postinstall') {
73
+ args.postinstall = true;
74
+ continue;
75
+ }
76
+
77
+ args._.push(current);
78
+ }
79
+
80
+ return args;
81
+ }
82
+
83
+ function shouldSkipPostinstall() {
84
+ if (process.env.YUANFLOW_SKILL_SKIP_POSTINSTALL === '1') {
85
+ return true;
86
+ }
87
+
88
+ const isGlobalInstall =
89
+ process.env.npm_config_global === 'true' || process.env.npm_config_location === 'global';
90
+
91
+ return !isGlobalInstall;
92
+ }
93
+
94
+ function getPackageRoot() {
95
+ return path.resolve(__dirname, '..');
96
+ }
97
+
98
+ function listAgents() {
99
+ const supportedAgents = getSupportedAgents();
100
+ const detectedAgents = detectInstalledAgents();
101
+
102
+ print('Supported agents:');
103
+ for (const agentName of supportedAgents) {
104
+ const marker = detectedAgents.includes(agentName) ? '[detected]' : '[not detected]';
105
+ print(`- ${agentName} ${marker}`);
106
+ }
107
+ }
108
+
109
+ async function withSkillSource(run) {
110
+ const packageRoot = getPackageRoot();
111
+ const prepared = await prepareSkillSource({ packageRoot });
112
+
113
+ try {
114
+ return await run(prepared.sourceRoot);
115
+ } finally {
116
+ prepared.cleanup();
117
+ }
118
+ }
119
+
120
+ async function listSkills() {
121
+ const skills = await withSkillSource((sourceRoot) => discoverSkills(sourceRoot));
122
+
123
+ print('Discovered skills:');
124
+ for (const skill of skills) {
125
+ print(`- ${skill.name} -> ${skill.sourceDir}`);
126
+ }
127
+ }
128
+
129
+ function resolveAgents(requestedAgents) {
130
+ if (requestedAgents && requestedAgents.length > 0) {
131
+ return requestedAgents.map((agentName) => getAgentConfig(agentName));
132
+ }
133
+
134
+ return detectInstalledAgents().map((agentName) => getAgentConfig(agentName));
135
+ }
136
+
137
+ function resolveSkills(sourceRoot, requestedSkillNames) {
138
+ const skills = discoverSkills(sourceRoot);
139
+
140
+ if (!requestedSkillNames || requestedSkillNames.length === 0) {
141
+ return skills;
142
+ }
143
+
144
+ const requested = new Set(requestedSkillNames.map((item) => item.toLowerCase()));
145
+ return skills.filter((skill) => requested.has(skill.name.toLowerCase()));
146
+ }
147
+
148
+ function printInstallResults(results) {
149
+ for (const result of results) {
150
+ const actionLabel = result.dryRun ? 'Would install' : 'Installed';
151
+ const overwriteLabel =
152
+ result.overwriteCanonical || result.overwriteTarget ? ' overwrite' : '';
153
+ print(
154
+ `${actionLabel} ${result.skillName} -> ${result.agentName} (${result.installedBy}, ${result.scope}${overwriteLabel})`
155
+ );
156
+ print(` ${result.targetDir}`);
157
+ }
158
+ }
159
+
160
+ function printUninstallResults(results) {
161
+ for (const result of results) {
162
+ const actionLabel = result.dryRun ? 'Would remove' : 'Removed';
163
+ print(`${actionLabel} ${result.skillName} -> ${result.agentName} (${result.scope})`);
164
+ print(` ${result.targetDir}`);
165
+ }
166
+ }
167
+
168
+ async function runInstall(options = {}) {
169
+ const packageRoot = getPackageRoot();
170
+ const agents = resolveAgents(options.agent);
171
+
172
+ if (agents.length === 0) {
173
+ print('No supported agent installation was detected. Nothing to install.');
174
+ return 0;
175
+ }
176
+
177
+ const results = await withSkillSource((sourceRoot) => {
178
+ const skills = resolveSkills(sourceRoot, options.skill);
179
+
180
+ if (skills.length === 0) {
181
+ print('No matching skills were found in the skill repository.');
182
+ return 1;
183
+ }
184
+
185
+ return installSkills({
186
+ packageRoot,
187
+ skills,
188
+ targetAgents: agents,
189
+ mode: options.mode || 'symlink',
190
+ scope: options.scope || 'global',
191
+ cwd: process.cwd(),
192
+ dryRun: Boolean(options.dryRun),
193
+ });
194
+ });
195
+
196
+ if (typeof results === 'number') {
197
+ return results;
198
+ }
199
+
200
+ printInstallResults(results);
201
+ return 0;
202
+ }
203
+
204
+ function runUpdate(options = {}) {
205
+ return runInstall(options);
206
+ }
207
+
208
+ async function runUninstall(options = {}) {
209
+ const agents = resolveAgents(options.agent);
210
+
211
+ if (agents.length === 0) {
212
+ print('No supported agent installation was detected. Nothing to remove.');
213
+ return 0;
214
+ }
215
+
216
+ const results = await withSkillSource((sourceRoot) => {
217
+ const skills = resolveSkills(sourceRoot, options.skill);
218
+
219
+ if (skills.length === 0) {
220
+ print('No matching skills were found in the skill repository.');
221
+ return 1;
222
+ }
223
+
224
+ return uninstallSkills({
225
+ bundleName: skills.find((skill) => skill.rootSkill)?.name || 'yuanflow-skill',
226
+ targetAgents: agents,
227
+ scope: options.scope || 'global',
228
+ cwd: process.cwd(),
229
+ dryRun: Boolean(options.dryRun),
230
+ });
231
+ });
232
+
233
+ if (typeof results === 'number') {
234
+ return results;
235
+ }
236
+
237
+ printUninstallResults(results);
238
+ return 0;
239
+ }
240
+
241
+ function runReleaseCheck() {
242
+ const packageRoot = getPackageRoot();
243
+ const packageJson = JSON.parse(
244
+ fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8')
245
+ );
246
+ const repoConfig = readRepositoryConfig(packageRoot);
247
+ const checklist = buildReleaseChecklist({
248
+ packageJson,
249
+ packageRoot,
250
+ repoConfig,
251
+ });
252
+
253
+ print('Release checklist:');
254
+ for (const item of checklist.items) {
255
+ print(`- ${item.ok ? 'OK' : 'FAIL'} ${item.label}`);
256
+ }
257
+
258
+ try {
259
+ const output = execFileSync('npm', ['view', packageJson.name, 'version', '--json'], {
260
+ cwd: packageRoot,
261
+ stdio: ['ignore', 'pipe', 'pipe'],
262
+ encoding: 'utf8',
263
+ }).trim();
264
+ if (output) {
265
+ print(`- INFO package name exists on npm: ${packageJson.name}`);
266
+ print(` latest published version: ${output.replace(/^"|"$/g, '')}`);
267
+ }
268
+ } catch {
269
+ print(`- INFO package name not found on npm or registry query failed: ${packageJson.name}`);
270
+ }
271
+
272
+ return checklist.ok ? 0 : 1;
273
+ }
274
+
275
+ function runPublishHelp() {
276
+ print('Publish flow for the npm installer package:');
277
+ print('1. npm test');
278
+ print('2. npm run pack:check');
279
+ print('3. npm run release:check');
280
+ print('4. npm publish --access public');
281
+ return 0;
282
+ }
283
+
284
+ async function main() {
285
+ const args = parseArgs(process.argv.slice(2));
286
+ const command = args._[0] || 'install';
287
+
288
+ if (args.postinstall && shouldSkipPostinstall()) {
289
+ return;
290
+ }
291
+
292
+ if (command === 'list-agents') {
293
+ listAgents();
294
+ return;
295
+ }
296
+
297
+ if (command === 'list-skills') {
298
+ await listSkills();
299
+ return;
300
+ }
301
+
302
+ if (command === 'install') {
303
+ process.exitCode = await runInstall(args);
304
+ return;
305
+ }
306
+
307
+ if (command === 'update') {
308
+ process.exitCode = await runUpdate(args);
309
+ return;
310
+ }
311
+
312
+ if (command === 'uninstall' || command === 'remove') {
313
+ process.exitCode = await runUninstall(args);
314
+ return;
315
+ }
316
+
317
+ if (command === 'release-check') {
318
+ process.exitCode = runReleaseCheck();
319
+ return;
320
+ }
321
+
322
+ if (command === 'publish-help') {
323
+ process.exitCode = runPublishHelp();
324
+ return;
325
+ }
326
+
327
+ printError(`Unsupported command: ${command}`);
328
+ process.exitCode = 1;
329
+ }
330
+
331
+ main().catch((error) => {
332
+ printError(error instanceof Error ? error.message : String(error));
333
+ process.exitCode = 1;
334
+ });