yuanflow-cli 0.1.40 → 0.1.42

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 (35) hide show
  1. package/README.md +121 -10
  2. package/generated/registry.json +985 -984
  3. package/package.json +1 -1
  4. package/scripts/generate-registry.js +1 -1
  5. package/skills/yuanflow-skill/README.md +16 -12
  6. package/skills/yuanflow-skill/SKILL.md +41 -11
  7. package/skills/yuanflow-skill/{OSS → YuanFlow}/346/226/207/344/273/266/344/270/255/350/275/254/345/267/245/345/205/267/SKILL.md +13 -13
  8. package/skills/yuanflow-skill/yuanflow-cli/SKILL.md +8 -8
  9. package/skills/yuanflow-skill//344/270/252/344/272/272/345/210/233/344/275/234/345/272/223/SKILL.md +2 -2
  10. package/skills/yuanflow-skill//344/275/234/345/223/201/344/270/213/350/275/275/347/273/274/345/220/210/345/267/245/345/205/267/SKILL.md +4 -4
  11. package/skills/yuanflow-skill//344/275/234/345/223/201/350/257/204/350/256/272/351/207/207/351/233/206/SKILL.md +4 -4
  12. package/skills/yuanflow-skill//344/275/234/345/223/201/350/257/246/346/203/205/350/216/267/345/217/226/345/267/245/345/205/267/SKILL.md +3 -3
  13. package/skills/yuanflow-skill//345/205/254/344/274/227/345/217/267/347/224/237/346/210/220/344/270/216/345/217/221/345/270/203/SKILL.md +3 -3
  14. package/skills/yuanflow-skill//345/205/254/344/274/227/345/217/267/347/224/237/346/210/220/344/270/216/345/217/221/345/270/203/tests/test_wechat_draft.py +176 -0
  15. package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/SKILL.md +1 -1
  16. package/skills/yuanflow-skill//345/270/220/345/217/267/347/233/221/346/216/247/SKILL.md +3 -3
  17. package/skills/yuanflow-skill//347/224/237/345/233/276/346/212/200/350/203/275/SKILL.md +1 -1
  18. package/skills/yuanflow-skill//347/273/274/345/220/210/346/220/234/347/264/242/345/267/245/345/205/267/SKILL.md +3 -3
  19. package/skills/yuanflow-skill//347/273/274/345/220/210/347/224/250/346/210/267/346/220/234/347/264/242/345/267/245/345/205/267/SKILL.md +3 -3
  20. package/skills/yuanflow-skill//350/207/252/345/252/222/344/275/223/346/265/217/350/247/210/345/231/250/350/207/252/345/212/250/345/214/226/SKILL.md +1 -1
  21. package/skills/yuanflow-skill//350/207/252/345/252/222/344/275/223/347/237/245/350/257/206/345/272/223/SKILL.md +4 -4
  22. package/skills/yuanflow-skill//350/247/206/350/247/211/347/220/206/350/247/243/SKILL.md +174 -0
  23. package/skills/yuanflow-skill//350/247/206/351/242/221/346/212/225/346/265/201/347/255/226/347/225/245/SKILL.md +1 -1
  24. package/skills/yuanflow-skill//350/247/206/351/242/221/346/213/206/350/247/243/SKILL.md +245 -0
  25. package/skills/yuanflow-skill//350/247/206/351/242/221/346/231/272/350/203/275/345/211/252/350/276/221/SKILL.md +4 -4
  26. package/skills/yuanflow-skill//351/237/263/350/247/206/351/242/221/345/234/250/347/272/277/350/275/254/346/226/207/345/255/227/SKILL.md +11 -11
  27. package/skills/yuanflow-skill//351/243/236/344/271/246/345/256/230/346/226/271/346/212/200/350/203/275/SKILL.md +1 -1
  28. package/src/agent-protocol.js +8 -5
  29. package/src/ai-tools.js +835 -0
  30. package/src/cli.js +36 -2
  31. package/src/comment-collector.js +1 -1
  32. package/src/oss-tools.js +11 -11
  33. package/src/shortcuts.js +3 -3
  34. package/src/trending-tools.js +1 -1
  35. package/src/work-tools.js +4 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuanflow-cli",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "description": "YuanFlow 自媒体 API CLI 与 Skill 安装器。",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -66,7 +66,7 @@ async function main() {
66
66
  command,
67
67
  aliases: [],
68
68
  method: method.toUpperCase(),
69
- upstreamPath: rawPath,
69
+ sourcePath: rawPath,
70
70
  socialPath,
71
71
  summary: cleanText(operation.summary || ''),
72
72
  bodyExample: extractBodyExample(operation),
@@ -7,16 +7,16 @@ YuanFlow Skill 是 `yuanflow-cli` 的 Agent Skill 仓库,用于把社媒平台
7
7
  - `SKILL.md`:总入口,负责分流和索引。
8
8
  - `yuanflow-cli/`:API CLI 子 Skill,说明 `yuanflow-cli` 的安装、配置、命令发现、schema 查询、dry-run 和 agent-json 调用方式。
9
9
  - `自媒体知识库/`:自媒体知识库渐进查询 Skill,走 `yuanflow-cli knowledge`。
10
- - `OSS文件中转工具/`:OSS 临时上传、签名链接、对象复制 Skill,走 `yuanflow-cli oss`。
11
- - `生图技能/`:图片生成与编辑 Skill,优先走 YuanFlow 内置 `yuanflow_image_request`。
10
+ - `视觉理解/`:通用型图片、视频画面理解 Skill,走 `yuanflow-cli ai qwen3-vl-plus`,支持图片/视频 URL 和本地图片/视频上传。
11
+ - `视频拆解/`:自媒体创作场景的对标视频拆解 Skill,先查自媒体知识库对标拆解规则,再用 `qwen3-vl-plus` 上传视频并按规则拆解。
12
+ - `YuanFlow文件中转工具/`:YuanFlow 文件中转、签名链接、对象复制 Skill,内部兼容命令走 `yuanflow-cli oss`。
13
+ - `生图技能/`:图片生成与编辑 Skill,优先走 YuanFlow-main 内置环境的 `yuanflow_image_request`。
12
14
  - `公众号生成与发布/`:公众号文章创作、主题预览、微信内联 HTML 排版、正文图片上传和草稿箱推送 Skill。
13
15
  - `小红书运营/`:小红书选题调研、笔记搜索、账号分析、评论采集、文案创作、发布前检查和互动操作 Skill;不建议浏览器自动发布作品,除非用户明确无视平台识别和限流风险并强制要求。
14
- - `热门内容整理/`:一次性查询视频总榜、低粉爆款、高完播率、高涨粉率、高点赞率,并结合用户创作方向输出建议。
15
- - `创作总监/`:负责内容方向把控、创新判断、复查验收和跨技能创作统筹。
16
16
  - `视频智能剪辑/`:主音频 + B-roll 素材智能剪辑 Skill,先查自媒体知识库的视频剪辑策略,保存 `strategy_snapshot.json`,再通过 ASR/forced alignment 导入 `audio_alignment.json`,按 1 秒 1 帧抽帧并回写视觉理解,由 Agent 生成 `timeline_plan` 和 EDL,交给 `yuanflow-cli video` 校验和渲染。
17
17
  - `HTML报告生成/`:单页 HTML 报告生成 Skill,内置 9 种米色留白报告模板。
18
18
  - `本地音视频转文字/`:本地 SenseVoice 音视频转文字 Skill,首次明确使用时按需下载模型。
19
- - `音视频在线转文字/`:通过 YuanFlow 在线 ASR 接口把音频或视频转成干净文本,视频会先抽取音频并通过 OSS 中转。
19
+ - `音视频在线转文字/`:通过 YuanFlow 在线 ASR 接口把音频或视频转成干净文本,视频会先抽取音频并通过 YuanFlow 文件中转。
20
20
  - `自媒体浏览器自动化/`:自媒体平台专用浏览器自动化 Skill,用于登录态隔离、Cookie/profile 本地保存、页面采集和作品发布流程。
21
21
  - `帐号监控/`:帐号搜索、主页资料、主页作品、历史快照、变化对比和 HTML 可视化分流 Skill。
22
22
  - `个人创作库/`:长期保存、整理、复盘和复用用户认可的自媒体合格产出物。
@@ -35,14 +35,16 @@ YuanFlow Skill 是 `yuanflow-cli` 的 Agent Skill 仓库,用于把社媒平台
35
35
  - 查看可用 API 命令、快捷命令和 schema。
36
36
  - 让本地 Agent 稳定调用 `yuanflow-cli` 并解析 JSON 输出。
37
37
  - 查询自媒体知识库公开方向、方法包和规则摘要。
38
- - 上传文件到临时 OSS、生成签名链接或复制 OSS 对象。
38
+ - 对图片、视频、本地媒体文件或媒体 URL 做通用画面理解、内容描述、可见文字识别、画面对比和细节检查。
39
+ - 对自媒体对标视频、爆款视频、竞品视频做内容结构、开头钩子、脚本节奏、镜头节奏和可复用创作方法拆解;开始前先查自媒体知识库规则,视频 URL 先解析并保存本地。
40
+ - 上传文件到 YuanFlow 文件中转、生成签名链接或复制文件对象。
39
41
  - 生成图片、编辑图片,并缓存返回 URL 或 base64 图片。生成图片必填 `prompt`,可选 `size / quality / style / n / response_format`;编辑图片必须通过 multipart 上传本地图片。
40
42
  - 把自媒体分析、数据复盘、文案方案、账号监控、知识梳理和执行计划生成可直接打开的单页 HTML 报告。
41
43
  - 生成或改写公众号文章,进入主题选择预览后导出微信公众号编辑器可粘贴 HTML,或推送到公众号草稿箱。
42
- - 处理小红书单段或全流程任务,例如只写文案、只采集笔记、只分析账号、只采集评论、只做点赞收藏评论回复,或完整执行图文/视频发布流程;每轮开始前必须明确任务边界。
44
+ - 处理小红书单段或全流程任务,例如只写文案、只采集笔记、只分析账号、只采集评论、只做点赞收藏评论回复,或完整执行图文/视频发布流程;每轮开始前必须明确任务边界。写小红书文案前先查自媒体知识库方法论,遇到封面或正文插图生成时先确认 4:3 或 3:4 比例并调用生图技能。
43
45
  - 在用户要求智能剪辑、自动剪辑、主音频匹配 B-roll、重排视频画面或生成剪辑预览时,使用视频智能剪辑 Skill;第一版先查规则库,导入策略快照,用“音视频在线转文字”或 forced alignment 建立音频对齐,抽帧频率固定 1 秒 1 帧,再回写视觉理解结果,最后生成 `timeline_plan` 和 EDL。
44
46
  - 在用户明确要求本地转写时,把本地音频或视频转成文字;视频会先抽取音频,模型和缓存都保存在 Skill 自己目录下。
45
- - 在用户要求在线转写、云端转写或 doubao-asr 时,把本地音频或视频经 OSS 中转后提交在线 ASR,默认只返回干净文本。
47
+ - 在用户要求在线转写、云端转写或 doubao-asr 时,把本地音频或视频经 YuanFlow 文件中转后提交在线 ASR,默认只返回干净文本。
46
48
  - 在用户要求自媒体平台浏览器自动化、账号登录态隔离、Cookie/profile 保存、平台页面采集或作品发布时,使用专用自媒体浏览器自动化 Skill;普通网页浏览和搜索仍使用通用浏览器能力。
47
49
  - 监控抖音、小红书、微博、知乎、Bilibili、TikTok、YouTube、Twitter/X 帐号主页,保存快照并对比历史变化;抖音链路优先使用 `get-sec-user-id -> user-profile -> user-posts -> works detail`。
48
50
  - 在用户要求保存、归档、复盘或复用已完成创作成果时,把选题、标题、文案、脚本、封面、剪辑思路、发布计划和数据复盘沉淀进个人创作库。
@@ -53,7 +55,7 @@ YuanFlow Skill 是 `yuanflow-cli` 的 Agent Skill 仓库,用于把社媒平台
53
55
 
54
56
  这套 Skill 同时支持两种环境:
55
57
 
56
- - YuanFlow 主程序内:优先使用内置工具 `yuanflow_cli_call`、`yuanflow_gateway_request` 或 `yuanflow_image_request`,token 由主程序认证系统注入,不要求用户安装 npm 或配置 token。
58
+ - YuanFlow-main 内置环境:优先使用内置工具 `yuanflow_cli_call`、`yuanflow_gateway_request` 或 `yuanflow_image_request`,token YuanFlow-main 内置环境注入,不要求用户安装 npm 或配置 token。
57
59
  - 外部 Agent 内:优先使用本地 `yuanflow-cli`;如果本地没有,再通过 npm 安装。
58
60
 
59
61
  外部 Agent 独立使用时,推荐环境变量:
@@ -107,6 +109,10 @@ yuanflow-skill list-skills
107
109
  │ └─ SKILL.md
108
110
  ├─ 自媒体知识库
109
111
  │ └─ SKILL.md
112
+ ├─ 视觉理解
113
+ │ └─ SKILL.md
114
+ ├─ 视频拆解
115
+ │ └─ SKILL.md
110
116
  ├─ 生图技能
111
117
  │ └─ SKILL.md
112
118
  ├─ 公众号生成与发布
@@ -116,8 +122,6 @@ yuanflow-skill list-skills
116
122
  │ ├─ references/
117
123
  │ └─ tests/
118
124
  ├─ 小红书运营
119
- ├─ 热门内容整理
120
- ├─ 创作总监
121
125
  │ ├─ SKILL.md
122
126
  │ └─ references/
123
127
  ├─ 视频智能剪辑
@@ -154,7 +158,7 @@ yuanflow-skill list-skills
154
158
  │ └─ SKILL.md
155
159
  ├─ 直播投流策略
156
160
  │ └─ SKILL.md
157
- └─ OSS文件中转工具
161
+ └─ YuanFlow文件中转工具
158
162
  └─ SKILL.md
159
163
  ```
160
164
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: YuanFlow技能总入口
3
- description: 当用户需要处理自媒体平台接口工作流、平台数据查询、命令发现、生图、OSS 文件中转、知识库查询、HTML 报告生成,或需要在 YuanFlow 子技能之间选择合适能力时使用。
3
+ description: 当用户需要处理自媒体平台接口工作流、平台数据查询、命令发现、生图、YuanFlow 文件中转、知识库查询、HTML 报告生成,或需要在 YuanFlow 子技能之间选择合适能力时使用。
4
4
  ---
5
5
 
6
6
  # YuanFlow Skill
@@ -19,7 +19,9 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
19
19
  - `综合搜索工具/`
20
20
  - `综合用户搜索工具/`
21
21
  - `自媒体知识库/`
22
- - `OSS文件中转工具/`
22
+ - `视觉理解/`
23
+ - `视频拆解/`
24
+ - `YuanFlow文件中转工具/`
23
25
  - `生图技能/`
24
26
  - `公众号生成与发布/`
25
27
  - `小红书运营/`
@@ -45,9 +47,9 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
45
47
 
46
48
  执行本 Skill 前,先判断当前运行环境:
47
49
 
48
- 1. 如果当前 Agent 可用 YuanFlow 内置工具,例如 `yuanflow_cli_call`、`yuanflow_gateway_request` 或 `yuanflow_image_request`,优先使用 YuanFlow 内置工具。不要要求用户安装 npm,也不要要求用户配置 token。
49
- 2. 如果当前不在 YuanFlow 内,且本地可执行 `yuanflow-cli --help`,使用本地 CLI。
50
- 3. 如果当前不在 YuanFlow 内,且本地没有 `yuanflow-cli`,再提示用户安装 `npm install -g yuanflow-cli`。
50
+ 1. 如果当前 Agent 可用 YuanFlow-main 内置工具,例如 `yuanflow_cli_call`、`yuanflow_gateway_request` 或 `yuanflow_image_request`,优先使用 YuanFlow-main 内置工具。不要要求用户安装 npm,也不要要求用户配置 token。
51
+ 2. 如果当前不在 YuanFlow-main 内置环境,且本地可执行 `yuanflow-cli --help`,使用本地 CLI。
52
+ 3. 如果当前不在 YuanFlow-main 内置环境,且本地没有 `yuanflow-cli`,再提示用户安装 `npm install -g yuanflow-cli`。
51
53
 
52
54
  不要在回复、日志或文件中暴露 token。
53
55
 
@@ -179,17 +181,17 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
179
181
 
180
182
  - `帐号监控`
181
183
 
182
- ### 10. 走 `OSS文件中转工具`
184
+ ### 10. 走 `YuanFlow文件中转工具`
183
185
 
184
186
  遇到下面这些需求,优先进入这个子 Skill:
185
187
 
186
- - 上传图片、音频、视频、文档到临时 OSS。
187
- - 为已有 OSS 对象生成签名访问链接。
188
- - 复制 OSS 对象,或为其它自媒体流程准备文件中转链接。
188
+ - 上传图片、音频、视频、文档到 YuanFlow 文件中转。
189
+ - 为已有文件对象生成签名访问链接。
190
+ - 复制文件对象,或为其它自媒体流程准备文件中转链接。
189
191
 
190
192
  子 Skill 名称:
191
193
 
192
- - `OSS文件中转工具`
194
+ - `YuanFlow文件中转工具`
193
195
 
194
196
  ### 11. 走 `自媒体浏览器自动化`
195
197
 
@@ -211,7 +213,7 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
211
213
 
212
214
  - 生成图片、画图、出图、做海报、生成视觉素材。
213
215
  - 编辑图片、修改本地图片、基于已有图片做变化。
214
- - 调用 YuanFlow 内置图片生成或图片编辑接口。
216
+ - 调用 YuanFlow-main 内置图片生成或图片编辑接口。
215
217
 
216
218
  子 Skill 名称:
217
219
 
@@ -293,6 +295,34 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
293
295
 
294
296
  - `音视频在线转文字`
295
297
 
298
+ ### 19. 走 `视觉理解`
299
+
300
+ 遇到下面这些需求,优先进入这个子 Skill:
301
+
302
+ - 用户提交图片、视频、本地媒体文件或媒体 URL,要求识别画面、描述内容、提取画面信息、检查视觉细节。
303
+ - 用户要求对图片或视频做通用理解、画面总结、可见文字识别、场景判断或多媒体对比。
304
+ - 用户明确要使用 `qwen3-vl-plus` 做图片/视频理解。
305
+
306
+ 这是通用型画面理解 Skill,只使用 `yuanflow-cli ai qwen3-vl-plus`。如果用户目标是自媒体对标、爆款复盘、脚本结构、镜头节奏或内容创作拆解,改用 `视频拆解`。
307
+
308
+ 子 Skill 名称:
309
+
310
+ - `视觉理解`
311
+
312
+ ### 20. 走 `视频拆解`
313
+
314
+ 遇到下面这些需求,优先进入这个子 Skill:
315
+
316
+ - 用户提交对标视频、本地视频或视频 URL,要求做自媒体创作方向的视频拆解。
317
+ - 用户要求分析爆款结构、开头钩子、脚本节奏、镜头节奏、转化设计、可复用创作模板。
318
+ - 用户希望从竞品视频、对标账号视频里提炼内容创作方法。
319
+
320
+ 这个 Skill 开始前必须先使用 `自媒体知识库` 查询与对标拆解相关的规则。如果用户提交的是视频 URL,先用作品解析/下载相关工具保存到本地,再通过 `yuanflow-cli ai qwen3-vl-plus --video-file` 上传拆解。
321
+
322
+ 子 Skill 名称:
323
+
324
+ - `视频拆解`
325
+
296
326
  ## 多需求时怎么处理
297
327
 
298
328
  如果用户一次提了多段流程,不要强行塞进一个子 Skill,按阶段拆开:
@@ -1,26 +1,26 @@
1
1
  ---
2
- name: OSS文件中转工具
3
- description: 当用户需要把本地文件上传到 YuanFlow 临时 OSS、生成对象签名访问链接、复制 OSS 对象,或为自媒体工作流准备图片、音频、视频、文档中转链接时使用。
2
+ name: YuanFlow文件中转工具
3
+ description: 当用户需要把本地文件上传到 YuanFlow 文件中转、生成对象签名访问链接、复制文件对象,或为自媒体工作流准备图片、音频、视频、文档中转链接时使用。
4
4
  emoji: 🔗
5
5
  ---
6
6
 
7
- # OSS 文件中转工具
7
+ # YuanFlow 文件中转工具
8
8
 
9
- 这个 Skill 负责使用 YuanFlow OSS 原子能力。它只处理文件中转、签名链接和对象复制,不负责社媒数据采集。
9
+ 这个 Skill 负责使用 YuanFlow 文件中转能力。CLI 内部兼容命令仍叫 `oss`,但对用户说明时统一称为 YuanFlow 文件中转。它只处理文件中转、签名链接和对象复制,不负责社媒数据采集。
10
10
 
11
11
  ## 环境判断
12
12
 
13
- 1. 在 YuanFlow 主程序内,优先调用内置工具 `yuanflow_cli_call`。
13
+ 1. 在 YuanFlow-main 内置环境,优先调用内置工具 `yuanflow_cli_call`。
14
14
  2. 在外部 Agent 中,如果本地有 `yuanflow-cli`,直接执行 CLI。
15
15
  3. 如果外部环境没有 CLI,再提示用户安装 `npm install -g yuanflow-cli`。
16
16
 
17
- 不要要求用户手动填写 token。YuanFlow 主程序会注入认证 token;外部 CLI 使用 `YUANCHUANG_API_TOKEN`。
17
+ 不要要求用户手动填写 token。YuanFlow-main 内置环境会注入认证 token;外部 CLI 使用 `YUANCHUANG_API_TOKEN`。
18
18
 
19
19
  ## 能做什么
20
20
 
21
- - 上传本地图片、音频、视频、文档到临时 OSS。
22
- - 为已有 OSS 对象生成临时签名 URL。
23
- - 把一个 OSS 对象复制到另一个 key。
21
+ - 上传本地图片、音频、视频、文档到 YuanFlow 文件中转。
22
+ - 为已有文件对象生成临时签名 URL。
23
+ - 把一个文件对象复制到另一个 key。
24
24
  - 为后续自媒体创作、发布、转写、封面处理等流程提供临时文件链接。
25
25
 
26
26
  ## 命令
@@ -37,7 +37,7 @@ yuanflow-cli oss temp-upload \
37
37
  可选参数:
38
38
 
39
39
  - `--filename`:指定上传文件名。
40
- - `--key`:指定 OSS 对象 key。
40
+ - `--key`:指定文件对象 key。
41
41
  - `--content-type`:MIME 类型,默认 `application/octet-stream`。
42
42
 
43
43
  ### 生成签名链接
@@ -70,9 +70,9 @@ yuanflow-cli oss copy \
70
70
  - `--source-bucket`:源 bucket。
71
71
  - `--target-bucket`:目标 bucket。
72
72
 
73
- ## YuanFlow 内置工具调用示例
73
+ ## YuanFlow-main 内置工具调用示例
74
74
 
75
- 在 YuanFlow 主程序内,调用 `yuanflow_cli_call`,参数数组不要包含 token:
75
+ 在 YuanFlow-main 内置环境,调用 `yuanflow_cli_call`,参数数组不要包含 token:
76
76
 
77
77
  ```json
78
78
  {
@@ -95,4 +95,4 @@ yuanflow-cli oss copy \
95
95
  - 不上传密钥、cookie、账号凭据、配置文件、隐私文件。
96
96
  - 不把签名 URL 写入公开文档或长期日志。
97
97
  - 返回结果中优先说明 `bucket`、`key`、`expires_at`,只有用户确实需要访问链接时才展示 `signed_url`。
98
- - 在 YuanFlow 主程序中,如果工具策略限制本地文件上传,不要绕过限制,改为让用户通过受控上传入口完成。
98
+ - 在 YuanFlow-main 内置环境中,如果工具策略限制本地文件上传,不要绕过限制,改为让用户通过受控上传入口完成。
@@ -22,12 +22,12 @@ emoji: ⚙️
22
22
 
23
23
  优先级如下:
24
24
 
25
- 1. YuanFlow 内置工具:如果当前工具列表里存在 `yuanflow_cli_call`,使用它调用社媒接口。
25
+ 1. YuanFlow-main 内置工具:如果当前工具列表里存在 `yuanflow_cli_call`,使用它调用社媒接口。
26
26
  2. YuanFlow 网关工具:如果只有 `yuanflow_gateway_request`,可用它访问受控服务接口。
27
27
  3. 本地 CLI:如果当前环境可执行 `yuanflow-cli --help`,使用本地 CLI。
28
28
  4. 安装提示:只有以上都不可用时,才提示用户安装 `npm install -g yuanflow-cli`。
29
29
 
30
- 在 YuanFlow 主程序内,不要提示用户配置 token;token 由主程序 KEY 认证注入。
30
+ 在 YuanFlow-main 内置环境,不要提示用户配置 token;token YuanFlow-main 内置环境注入。
31
31
  在外部 Agent 环境中,使用环境变量 `YUANCHUANG_API_TOKEN`,也可以使用本地 `config set-token`。
32
32
 
33
33
  ## 外部 Agent 安装和更新
@@ -65,7 +65,7 @@ yuanflow-cli --help
65
65
  $env:YUANCHUANG_API_TOKEN="<你的令牌>"
66
66
  ```
67
67
 
68
- 保存 Yuan API 令牌和服务地址:
68
+ 保存 YuanFlow API 令牌和服务地址:
69
69
 
70
70
  ```powershell
71
71
  yuanflow-cli config set-token <你的令牌>
@@ -88,7 +88,7 @@ yuanflow-cli douyin hot-search
88
88
 
89
89
  ## Agent 调用规则
90
90
 
91
- 给 AI Agent 使用时,先查命令和 schema,再调用接口。YuanFlow 内置环境下,优先调用 `yuanflow_cli_call`;外部 Agent 环境下,优先调用 `yuanflow-cli`。
91
+ 给 AI Agent 使用时,先查命令和 schema,再调用接口。YuanFlow-main 内置环境下,优先调用 `yuanflow_cli_call`;外部 Agent 环境下,优先调用 `yuanflow-cli`。
92
92
 
93
93
  ```powershell
94
94
  yuanflow-cli commands list
@@ -113,10 +113,10 @@ yuanflow-cli schema douyin.video-detail
113
113
 
114
114
  | 错误码 | 含义 |
115
115
  | --- | --- |
116
- | `TOKEN_MISSING` | 没有配置 Yuan API token |
116
+ | `TOKEN_MISSING` | 没有配置 YuanFlow API token |
117
117
  | `BAD_ARGUMENT` | 参数或命令写错 |
118
118
  | `AUTH_INVALID` | token 无效或权限不足 |
119
- | `UPSTREAM_ERROR` | 上游平台或服务报错 |
119
+ | `PLATFORM_SERVICE_ERROR` | 平台服务或 YuanFlow API 报错 |
120
120
  | `NETWORK_ERROR` | 网络或超时错误 |
121
121
  | `INTERNAL_ERROR` | 未分类错误 |
122
122
 
@@ -200,7 +200,7 @@ yuanflow-cli comments collect --platform douyin --target "https://v.douyin.com/x
200
200
  - `--prefer fallback`:主接口失败时切换备用接口。
201
201
  - `--extra`:JSON 字符串,用于公众号 `content_id` 等补充参数。
202
202
 
203
- 在 YuanFlow 主程序内,用 `yuanflow_cli_call` 调用时传参数数组:
203
+ 在 YuanFlow-main 内置环境,用 `yuanflow_cli_call` 调用时传参数数组:
204
204
 
205
205
  ```json
206
206
  {
@@ -237,7 +237,7 @@ yuanflow-cli schema search.xiaohongshu.content
237
237
  yuanflow-cli schema search.instagram.users
238
238
  ```
239
239
 
240
- YuanFlow 主程序内使用时仍通过 `yuanflow_cli_call` 传参数数组,token 由主程序注入。
240
+ YuanFlow-main 内置环境使用时仍通过 `yuanflow_cli_call` 传参数数组,token 由 YuanFlow-main 内置环境注入。
241
241
 
242
242
  ### 小红书
243
243
 
@@ -142,9 +142,9 @@ meta/
142
142
  2. 读取对应内容和 `performance-reviews/`。
143
143
  3. 总结可复用结构、表达方式、失败点和下一次优化方向。
144
144
 
145
- ## YuanFlow 内置使用方式
145
+ ## YuanFlow-main 内置环境使用方式
146
146
 
147
- 在 YuanFlow 主程序内,本 Skill 是托管 CLI Skill 的一个整体目录。不要把 `library/` 下的分类当成独立 Skill 安装,也不要在子目录里创建 `SKILL.md`。
147
+ 在 YuanFlow-main 内置环境,本 Skill 是托管 CLI Skill 的一个整体目录。不要把 `library/` 下的分类当成独立 Skill 安装,也不要在子目录里创建 `SKILL.md`。
148
148
 
149
149
  如果需要写入文件,优先使用当前 Skill 的真实目录:
150
150
 
@@ -15,7 +15,7 @@ emoji: ⬇️
15
15
 
16
16
  # 作品下载综合工具
17
17
 
18
- 本技能把用户的“下载作品、获取播放地址、获取视频流信息”需求稳定映射到 `yuanflow-cli works download`。在 YuanFlow 主程序内,优先调用受控工具 `yuanflow_cli_call`;它会由主程序认证系统注入 `YUANCHUANG_API_TOKEN`,不要让用户粘贴 KEY,不要在回复、日志或文件里暴露 token。
18
+ 本技能把用户的“下载作品、获取播放地址、获取视频流信息”需求稳定映射到 `yuanflow-cli works download`。在 YuanFlow-main 内置环境,优先调用受控工具 `yuanflow_cli_call`;它会由 YuanFlow-main 内置环境注入 `YUANCHUANG_API_TOKEN`,不要让用户粘贴 KEY,不要在回复、日志或文件里暴露 token。
19
19
 
20
20
  ## 什么时候使用
21
21
 
@@ -25,15 +25,15 @@ emoji: ⬇️
25
25
  - 用户给出抖音、B站、YouTube、西瓜视频链接或作品 ID。
26
26
  - 用户只想先确认作品是否有可用播放/下载地址。
27
27
 
28
- 不要用于批量抓取、绕过平台限制、破解权限、去除平台风控、下载私密或未授权内容。该工具只返回上游接口提供的播放/下载地址候选或视频流信息;真正保存到本地文件如需后续执行,必须先确认用户授权和保存路径。
28
+ 不要用于批量抓取、绕过平台限制、破解权限、去除平台风控、下载私密或未授权内容。该工具只返回 YuanFlow API 提供的播放/下载地址候选或视频流信息;真正保存到本地文件如需后续执行,必须先确认用户授权和保存路径。
29
29
 
30
30
  ## 调用优先级
31
31
 
32
- 1. YuanFlow 主程序内:调用 `yuanflow_cli_call`,参数数组从 `works download` 开始。
32
+ 1. YuanFlow-main 内置环境:调用 `yuanflow_cli_call`,参数数组从 `works download` 开始。
33
33
  2. 外部 Agent 且本机有 CLI:执行 `yuanflow-cli works download ...`。
34
34
  3. 外部 Agent 且没有 CLI:再提示用户安装 `npm install -g yuanflow-cli`。
35
35
 
36
- YuanFlow 内置调用示例:
36
+ YuanFlow-main 内置环境调用示例:
37
37
 
38
38
  ```json
39
39
  {
@@ -23,7 +23,7 @@ emoji: 💬
23
23
 
24
24
  # 作品评论采集
25
25
 
26
- 本技能把用户的评论采集需求稳定映射到 `yuanflow-cli comments collect`。在 YuanFlow 主程序内,优先使用受控工具 `yuanflow_cli_call`;它会由主程序认证系统注入 `YUANCHUANG_API_TOKEN`,不要让用户粘贴 KEY,不要在回复、日志或文件里暴露 token。
26
+ 本技能把用户的评论采集需求稳定映射到 `yuanflow-cli comments collect`。在 YuanFlow-main 内置环境,优先使用受控工具 `yuanflow_cli_call`;它会由 YuanFlow-main 内置环境注入 `YUANCHUANG_API_TOKEN`,不要让用户粘贴 KEY,不要在回复、日志或文件里暴露 token。
27
27
 
28
28
  ## 什么时候使用
29
29
 
@@ -37,11 +37,11 @@ emoji: 💬
37
37
 
38
38
  ## 调用优先级
39
39
 
40
- 1. YuanFlow 主程序内:调用 `yuanflow_cli_call`,参数数组从 `comments collect` 开始。
40
+ 1. YuanFlow-main 内置环境:调用 `yuanflow_cli_call`,参数数组从 `comments collect` 开始。
41
41
  2. 外部 Agent 且本机有 CLI:执行 `yuanflow-cli comments collect ...`。
42
42
  3. 外部 Agent 且没有 CLI:再提示用户安装 `npm install -g yuanflow-cli`。
43
43
 
44
- YuanFlow 内置调用示例:
44
+ YuanFlow-main 内置环境调用示例:
45
45
 
46
46
  ```json
47
47
  {
@@ -164,6 +164,6 @@ Agent 不需要直接拼接口地址,只需要选对 `platform`、`action` 和
164
164
  - `TOKEN_MISSING`:提示先完成 YuanFlow KEY 认证或外部 CLI 环境变量配置。
165
165
  - `BAD_ARGUMENT`:检查平台、action、target、comment-id、cursor。
166
166
  - `AUTH_INVALID`:认证无效或权限不足。
167
- - `UPSTREAM_ERROR`、`NETWORK_ERROR`:说明上游或网络失败,可稍后重试,或在有备用能力的平台加 `--prefer fallback`。
167
+ - `PLATFORM_SERVICE_ERROR`、`NETWORK_ERROR`:说明平台服务或网络失败,可稍后重试,或在有备用能力的平台加 `--prefer fallback`。
168
168
 
169
169
  不要展示完整 Authorization 请求头、token、cookie 或敏感账号信息。
@@ -12,7 +12,7 @@ emoji: 📄
12
12
 
13
13
  # 作品详情获取工具
14
14
 
15
- 本技能把用户的“查询单个作品详情、解析作品链接、获取作品元数据”需求稳定映射到 `yuanflow-cli works detail`。在 YuanFlow 主程序内,优先调用受控工具 `yuanflow_cli_call`;它会由主程序认证系统注入 `YUANCHUANG_API_TOKEN`,不要让用户粘贴 KEY,不要在回复、日志或文件里暴露 token。
15
+ 本技能把用户的“查询单个作品详情、解析作品链接、获取作品元数据”需求稳定映射到 `yuanflow-cli works detail`。在 YuanFlow-main 内置环境,优先调用受控工具 `yuanflow_cli_call`;它会由 YuanFlow-main 内置环境注入 `YUANCHUANG_API_TOKEN`,不要让用户粘贴 KEY,不要在回复、日志或文件里暴露 token。
16
16
 
17
17
  ## 什么时候使用
18
18
 
@@ -26,11 +26,11 @@ emoji: 📄
26
26
 
27
27
  ## 调用优先级
28
28
 
29
- 1. YuanFlow 主程序内:调用 `yuanflow_cli_call`,参数数组从 `works detail` 开始。
29
+ 1. YuanFlow-main 内置环境:调用 `yuanflow_cli_call`,参数数组从 `works detail` 开始。
30
30
  2. 外部 Agent 且本机有 CLI:执行 `yuanflow-cli works detail ...`。
31
31
  3. 外部 Agent 且没有 CLI:再提示用户安装 `npm install -g yuanflow-cli`。
32
32
 
33
- YuanFlow 内置调用示例:
33
+ YuanFlow-main 内置环境调用示例:
34
34
 
35
35
  ```json
36
36
  {
@@ -19,7 +19,7 @@ emoji: 📰
19
19
  3. 开始输出正文之前,必须先和用户核对大概字数范围,例如 800-1200 字、1500-2000 字、3000 字以上;如果用户没有给出范围,先询问,不要直接写完整正文。
20
20
  4. 是否需要正文插图、插图数量、插图来源和大概插入位置。
21
21
  - 用户提供图片时:先梳理每张图适合插入的段落位置,再进入排版、上传和草稿箱链路。
22
- - 用户要求生成正文插图时:先使用 YuanFlow 内置生图技能生成图片,再把生成图片作为正文插图素材进入上传链路。
22
+ - 用户要求生成正文插图时:先使用 生图技能生成图片,再把生成图片作为正文插图素材进入上传链路。
23
23
  - 用户没有要求正文插图时:不要擅自生成插图;只处理文字正文和可选封面。
24
24
  5. 排版结果使用 Markdown 还是 HTML。
25
25
  - 如果选择 HTML,会把 Markdown 转成微信公众号编辑器可粘贴的内联样式 HTML。
@@ -132,7 +132,7 @@ python scripts/wechat_draft.py \
132
132
  除非用户在本轮已明确指定某个主题 ID,否则不得直接执行 `wechat_format.py --theme ... --output ...`。正确顺序是:
133
133
 
134
134
  1. 文章正文确认或生成后,先准备 Markdown 正文。
135
- 2. 如果当前 YuanFlow 主程序工具列表里存在 `wechat_theme_gallery_update`,必须优先调用这个受控工具,传入已确认的 `markdown` 正文或受控 `markdown_path`。该工具会直接运行主题画廊脚本并写入右侧内容创作工作台,避免 Agent 手动复制主题预览 HTML 时丢字段。
135
+ 2. 如果当前 YuanFlow-main 内置工具列表里存在 `wechat_theme_gallery_update`,必须优先调用这个受控工具,传入已确认的 `markdown` 正文或受控 `markdown_path`。该工具会直接运行主题画廊脚本并写入右侧内容创作工作台,避免 Agent 手动复制主题预览 HTML 时丢字段。
136
136
  3. 如果没有 `wechat_theme_gallery_update`,再执行主题画廊命令,基于正文生成 20 个核心主题预览:
137
137
 
138
138
  ```bash
@@ -202,7 +202,7 @@ python scripts/wechat_format.py --input article.md --theme newspaper --output di
202
202
 
203
203
  ## 封面
204
204
 
205
- 封面不使用第三方生成接口。需要封面时,使用 YuanFlow 内置生图技能生成。
205
+ 封面不使用第三方生成接口。需要封面时,使用 生图技能生成。
206
206
 
207
207
  生成封面前同样必须先查看 `生图技能/references/image-prompt-reference.md` 的标题、目录或小节名,选择与文章定位最接近的封面、海报、知识卡、商业科技视觉或信息图方向作为参考;只需进入相近方向阅读,不需要完整扫完所有提示词。封面提示词要把文章主题、目标读者、视觉主元素、构图层级、比例、中文文字规则和负面约束写清楚,避免只写“生成一张某主题封面图”这类空泛需求。
208
208
 
@@ -0,0 +1,176 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import sys
5
+ import unittest
6
+ from pathlib import Path
7
+ from tempfile import TemporaryDirectory
8
+ from unittest.mock import patch
9
+
10
+
11
+ ROOT = Path(__file__).resolve().parents[1]
12
+ SCRIPTS = ROOT / "scripts"
13
+ if str(SCRIPTS) not in sys.path:
14
+ sys.path.insert(0, str(SCRIPTS))
15
+
16
+ import wechat_draft # noqa: E402
17
+
18
+
19
+ class FakeResponse:
20
+ def __init__(self, payload: dict, status_code: int = 200) -> None:
21
+ self._payload = payload
22
+ self.status_code = status_code
23
+ self.text = json.dumps(payload, ensure_ascii=False)
24
+
25
+ def json(self) -> dict:
26
+ return self._payload
27
+
28
+
29
+ class WechatDraftTests(unittest.TestCase):
30
+ def test_push_draft_uploads_article_images_cover_and_adds_draft(self) -> None:
31
+ with TemporaryDirectory() as temp_dir:
32
+ root = Path(temp_dir)
33
+ article_image = root / "article.jpg"
34
+ cover_image = root / "cover.jpg"
35
+ article_image.write_bytes(b"fake-image")
36
+ cover_image.write_bytes(b"fake-cover")
37
+ article = root / "article.md"
38
+ article.write_text(
39
+ "# 测试文章\n\n正文第一段。\n\n![正文图](article.jpg)\n\n正文第二段。",
40
+ encoding="utf-8",
41
+ )
42
+ credentials = root / "credentials.txt"
43
+ credentials.write_text("AppID:wx-test\nAppSecret:secret-test", encoding="utf-8")
44
+ output_dir = root / "dist"
45
+
46
+ calls: list[dict] = []
47
+
48
+ def fake_request(method: str, url: str, **kwargs):
49
+ calls.append({"method": method, "url": url, "kwargs": kwargs})
50
+ if "cgi-bin/token" in url:
51
+ return FakeResponse({"access_token": "token-test", "expires_in": 7200})
52
+ if "media/uploadimg" in url:
53
+ return FakeResponse({"url": "https://mmbiz.qpic.cn/article-image.jpg"})
54
+ if "material/add_material" in url:
55
+ return FakeResponse({"media_id": "cover-media-id", "url": "https://mmbiz.qpic.cn/cover.jpg"})
56
+ if "draft/add" in url:
57
+ self.assertNotIn("json", kwargs)
58
+ raw_body = kwargs.get("data")
59
+ self.assertIsInstance(raw_body, bytes)
60
+ self.assertIn("application/json; charset=utf-8", kwargs.get("headers", {}).get("Content-Type", ""))
61
+ self.assertIn("测试文章".encode("utf-8"), raw_body)
62
+ self.assertNotIn(b"\\u6d4b\\u8bd5", raw_body)
63
+ payload = json.loads(raw_body.decode("utf-8"))
64
+ content = payload["articles"][0]["content"]
65
+ self.assertIn("https://mmbiz.qpic.cn/article-image.jpg", content)
66
+ self.assertIn("cover-media-id", json.dumps(payload, ensure_ascii=False))
67
+ self.assertLessEqual(len(payload["articles"][0]["digest"].encode("utf-8")), 54)
68
+ self.assertLessEqual(len(payload["articles"][0]["title"].encode("utf-8")), 64)
69
+ return FakeResponse({"media_id": "draft-media-id"})
70
+ raise AssertionError(f"unexpected url: {url}")
71
+
72
+ args = wechat_draft.argparse.Namespace(
73
+ input=str(article),
74
+ theme="wechat-native",
75
+ title="",
76
+ author="YuanFlow",
77
+ digest="",
78
+ content_source_url="",
79
+ cover_image=str(cover_image),
80
+ thumb_media_id="",
81
+ cover_material_type="image",
82
+ output_dir=str(output_dir),
83
+ credentials_file=str(credentials),
84
+ app_id="",
85
+ app_secret="",
86
+ push_draft=True,
87
+ update_draft=False,
88
+ draft_media_id="",
89
+ draft_index=0,
90
+ json=True,
91
+ )
92
+ with patch.object(wechat_draft.requests, "request", side_effect=fake_request):
93
+ result = wechat_draft.run(args)
94
+
95
+ self.assertTrue(result["ok"])
96
+ self.assertTrue(result["pushed"])
97
+ self.assertEqual(result["draft"]["media_id"], "draft-media-id")
98
+ self.assertEqual(result["article_images"][0]["url"], "https://mmbiz.qpic.cn/article-image.jpg")
99
+ self.assertTrue((output_dir / "wechat.html").exists())
100
+ self.assertTrue((output_dir / "draft_payload.json").exists())
101
+ called_urls = "\n".join(call["url"] for call in calls)
102
+ self.assertIn("cgi-bin/token", called_urls)
103
+ self.assertIn("media/uploadimg", called_urls)
104
+ self.assertIn("material/add_material", called_urls)
105
+ self.assertIn("draft/add", called_urls)
106
+
107
+ def test_update_draft_replaces_article_by_media_id_and_index(self) -> None:
108
+ with TemporaryDirectory() as temp_dir:
109
+ root = Path(temp_dir)
110
+ article_image = root / "article.jpg"
111
+ article_image.write_bytes(b"fake-image")
112
+ article = root / "article.md"
113
+ article.write_text(
114
+ "# 更新文章\n\n正文第一段。\n\n![正文图](article.jpg)\n\n正文第二段。",
115
+ encoding="utf-8",
116
+ )
117
+ credentials = root / "credentials.txt"
118
+ credentials.write_text("AppID:wx-test\nAppSecret:secret-test", encoding="utf-8")
119
+ output_dir = root / "dist"
120
+
121
+ calls: list[dict] = []
122
+
123
+ def fake_request(method: str, url: str, **kwargs):
124
+ calls.append({"method": method, "url": url, "kwargs": kwargs})
125
+ if "cgi-bin/token" in url:
126
+ return FakeResponse({"access_token": "token-test", "expires_in": 7200})
127
+ if "media/uploadimg" in url:
128
+ return FakeResponse({"url": "https://mmbiz.qpic.cn/updated-image.jpg"})
129
+ if "draft/update" in url:
130
+ raw_body = kwargs.get("data")
131
+ self.assertIsInstance(raw_body, bytes)
132
+ payload = json.loads(raw_body.decode("utf-8"))
133
+ self.assertEqual(payload["media_id"], "draft-media-id")
134
+ self.assertEqual(payload["index"], 0)
135
+ self.assertIsInstance(payload["articles"], dict)
136
+ self.assertEqual(payload["articles"]["title"], "更新文章")
137
+ self.assertIn("https://mmbiz.qpic.cn/updated-image.jpg", payload["articles"]["content"])
138
+ self.assertNotIn("thumb_media_id", payload["articles"])
139
+ return FakeResponse({"errcode": 0, "errmsg": "ok"})
140
+ raise AssertionError(f"unexpected url: {url}")
141
+
142
+ args = wechat_draft.argparse.Namespace(
143
+ input=str(article),
144
+ theme="wechat-native",
145
+ title="",
146
+ author="YuanFlow",
147
+ digest="",
148
+ content_source_url="",
149
+ cover_image="",
150
+ thumb_media_id="",
151
+ cover_material_type="image",
152
+ output_dir=str(output_dir),
153
+ credentials_file=str(credentials),
154
+ app_id="",
155
+ app_secret="",
156
+ push_draft=False,
157
+ update_draft=True,
158
+ draft_media_id="draft-media-id",
159
+ draft_index=0,
160
+ json=True,
161
+ )
162
+ with patch.object(wechat_draft.requests, "request", side_effect=fake_request):
163
+ result = wechat_draft.run(args)
164
+
165
+ self.assertTrue(result["ok"])
166
+ self.assertTrue(result["pushed"])
167
+ self.assertEqual(result["operation"], "update")
168
+ called_urls = "\n".join(call["url"] for call in calls)
169
+ self.assertIn("cgi-bin/token", called_urls)
170
+ self.assertIn("media/uploadimg", called_urls)
171
+ self.assertIn("draft/update", called_urls)
172
+ self.assertNotIn("draft/add", called_urls)
173
+
174
+
175
+ if __name__ == "__main__":
176
+ unittest.main()
@@ -42,7 +42,7 @@ emoji: 📕
42
42
 
43
43
  ## YuanFlow 调用优先级
44
44
 
45
- 1. 当前在 YuanFlow 内时,优先使用受控工具 `yuanflow_cli_call`,不要让用户手动安装 npm,也不要暴露 token。
45
+ 1. 当前在 YuanFlow-main 内置环境时,优先使用受控工具 `yuanflow_cli_call`,不要让用户手动安装 npm,也不要暴露 token。
46
46
  2. 数据读取优先使用 `yuanflow-cli` 已有小红书接口和通用自媒体 Skill。
47
47
  3. 登录、发布、浏览器任务优先使用 YuanFlow 独立浏览器配置和自媒体浏览器自动化能力。
48
48
  4. 当前环境没有受控工具但本地存在 `yuanflow-cli` 时,再使用本地 CLI。