Compare commits

...

26 Commits

Author SHA1 Message Date
Jim Liu 宝玉 e4d4ec8334 chore: release v1.58.0 2026-03-08 22:30:46 -05:00
Jim Liu 宝玉 4935dc8b1a fix: surface agent-browser startup errors 2026-03-08 22:25:34 -05:00
Jim Liu 宝玉 c43ed57ffc Merge pull request #69 from liby/feat/xdg-config-path
feat: add XDG config path support for EXTEND.md
2026-03-08 22:19:52 -05:00
Jim Liu 宝玉 d96368492e Merge pull request #66 from luojiyin1987/fix/harden-command-exec-and-js-escaping
fix: harden command execution and JS literal escaping
2026-03-08 22:10:45 -05:00
Jim Liu 宝玉 cfc647fd38 Merge pull request #68 from luojiyin1987/docs/sync-readme-and-claude-deps
docs: sync README utility skills and CLAUDE dependency notes
2026-03-08 22:04:40 -05:00
Jim Liu 宝玉 5144335916 chore: release v1.57.0 2026-03-08 19:24:45 -05:00
Jim Liu 宝玉 fa82c3d910 refactor(baoyu-xhs-images): use skill interface instead of direct script invocation for image generation 2026-03-08 19:24:03 -05:00
Jim Liu 宝玉 90730bc551 refactor(baoyu-comic): use skill interface instead of direct script invocation for image generation 2026-03-08 19:24:02 -05:00
Jim Liu 宝玉 154ccfe3ff refactor: add openclaw metadata and rename SKILL_DIR to baseDir across all skills 2026-03-08 19:22:24 -05:00
Jim Liu 宝玉 93efa5aeb1 refactor(baoyu-comic): add openclaw metadata, baseDir rename, and decouple image skill path 2026-03-08 19:22:19 -05:00
Jim Liu 宝玉 40ccbed74a refactor(baoyu-danger-x-to-markdown): add openclaw metadata, baseDir rename, and dynamic script path 2026-03-08 19:22:18 -05:00
Jim Liu 宝玉 fbf2bc02c5 refactor(baoyu-danger-gemini-web): add openclaw metadata, baseDir rename, and dynamic script path 2026-03-08 19:22:18 -05:00
Jim Liu 宝玉 a37c80e142 feat: add ClawHub/OpenClaw publishing support 2026-03-08 19:22:13 -05:00
Jim Liu 宝玉 2e68aa64a4 chore: release v1.56.1 2026-03-08 17:42:38 -05:00
Bryan Lee a702513487 feat: add XDG config path support for EXTEND.md
Add $XDG_CONFIG_HOME/baoyu-skills/<skill>/EXTEND.md as second priority
path between project-level and legacy $HOME/.baoyu-skills/ paths.

Priority order:
1. .baoyu-skills/<skill>/EXTEND.md (project)
2. $XDG_CONFIG_HOME/baoyu-skills/<skill>/EXTEND.md (XDG, new)
3. $HOME/.baoyu-skills/<skill>/EXTEND.md (legacy fallback)

Updated: CLAUDE.md template, 16 SKILL.md files, 2 workflow.md
references, and 2 extend-config.ts runtime loaders.
2026-03-09 04:54:26 +08:00
Jim Liu 宝玉 059ebc759c fix(baoyu-post-to-weibo): simplify article image insertion with Backspace-based placeholder deletion 2026-03-08 15:49:54 -05:00
Jim Liu 宝玉 d4a5a34865 chore: release v1.56.0 2026-03-08 14:08:40 -05:00
Jim Liu 宝玉 b3b2f8ea36 feat(baoyu-xhs-images): streamline workflow with smart confirm (6→4 steps) 2026-03-08 14:07:59 -05:00
Jim Liu 宝玉 f19ed00cb2 fix(baoyu-post-to-wechat): improve image upload with file chooser interception 2026-03-08 14:07:55 -05:00
Jim Liu 宝玉 8e58855047 feat(baoyu-article-illustrator): add preset-first selection and categorized style presets 2026-03-08 14:07:53 -05:00
luojiyin 6b2b28b421 docs: fix CLAUDE dependency statement 2026-03-08 21:21:54 +08:00
luojiyin 0df63c3a0b docs: add markdown-to-html to README.zh utility skills 2026-03-08 21:21:54 +08:00
luojiyin 7834d632e0 docs: add markdown-to-html to README utility skills 2026-03-08 21:21:47 +08:00
luojiyin ca9a0a1404 fix: harden wechat agent-browser command and eval handling 2026-03-08 20:34:43 +08:00
luojiyin 366e7b5403 fix: use execFileSync for google curl requests 2026-03-08 20:34:39 +08:00
luojiyin 709e026be1 fix: use spawnSync for autocorrect command 2026-03-08 20:34:35 +08:00
42 changed files with 976 additions and 419 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
}, },
"metadata": { "metadata": {
"description": "Skills shared by Baoyu for improving daily work efficiency", "description": "Skills shared by Baoyu for improving daily work efficiency",
"version": "1.55.0" "version": "1.58.0"
}, },
"plugins": [ "plugins": [
{ {
+3
View File
@@ -161,3 +161,6 @@ posts/
*.ipr *.ipr
.claude/skills/baoyu-skill-evolution .claude/skills/baoyu-skill-evolution
# ClawHub local state (current and legacy directory names from the official CLI)
.clawhub/
.clawdhub/
+40
View File
@@ -2,6 +2,46 @@
English | [中文](./CHANGELOG.zh.md) English | [中文](./CHANGELOG.zh.md)
## 1.58.0 - 2026-03-08
### Features
- Add XDG config path support for EXTEND.md (by @liby)
### Fixes
- `baoyu-post-to-wechat`: surface agent-browser startup errors
- `baoyu-post-to-wechat`: harden agent-browser command and eval handling (by @luojiyin1987)
- `baoyu-image-gen`: use execFileSync for google curl requests (by @luojiyin1987)
- `baoyu-format-markdown`: use spawnSync for autocorrect command (by @luojiyin1987)
### Documentation
- Fix CLAUDE dependency statement (by @luojiyin1987)
- Add markdown-to-html to README utility skills (by @luojiyin1987)
## 1.57.0 - 2026-03-08
### Features
- Add ClawHub/OpenClaw publishing support with sync script and README documentation
### Refactor
- Add openclaw metadata to all skill frontmatter for ClawHub registry compatibility
- Rename `SKILL_DIR` to `baseDir` across all skills for consistency
- `baoyu-danger-gemini-web`, `baoyu-danger-x-to-markdown`: dynamic script path in usage display
- `baoyu-comic`, `baoyu-xhs-images`: use skill interface instead of direct script invocation for image generation
## 1.56.1 - 2026-03-08
### Fixes
- `baoyu-post-to-weibo`: simplify article image insertion with Backspace-based placeholder deletion for ProseMirror compatibility
## 1.56.0 - 2026-03-08
### Features
- `baoyu-article-illustrator`: preset-first selection flow with categorized style presets by content type
- `baoyu-xhs-images`: streamline workflow from 6 to 4 steps with Smart Confirm (Quick/Customize/Detailed paths)
### Fixes
- `baoyu-post-to-wechat`: improve image upload reliability with file chooser interception and fallback
## 1.55.0 - 2026-03-08 ## 1.55.0 - 2026-03-08
### Features ### Features
+40
View File
@@ -2,6 +2,46 @@
[English](./CHANGELOG.md) | 中文 [English](./CHANGELOG.md) | 中文
## 1.58.0 - 2026-03-08
### 新功能
- 新增 EXTEND.md 的 XDG 配置路径支持 (by @liby)
### 修复
- `baoyu-post-to-wechat`:暴露 agent-browser 启动错误信息
- `baoyu-post-to-wechat`:加固 agent-browser 命令和 eval 处理 (by @luojiyin1987)
- `baoyu-image-gen`:使用 execFileSync 替代 shell 执行 Google curl 请求 (by @luojiyin1987)
- `baoyu-format-markdown`:使用 spawnSync 替代 shell 执行 autocorrect 命令 (by @luojiyin1987)
### 文档
- 修正 CLAUDE 依赖说明 (by @luojiyin1987)
- 将 markdown-to-html 添加到 README 工具技能列表 (by @luojiyin1987)
## 1.57.0 - 2026-03-08
### 新功能
- 新增 ClawHub/OpenClaw 发布支持,包含同步脚本和 README 文档
### 重构
- 为所有 skill 前言添加 openclaw 元数据,兼容 ClawHub 注册表
- 全部 skill 中将 `SKILL_DIR` 统一重命名为 `baseDir`
- `baoyu-danger-gemini-web``baoyu-danger-x-to-markdown`:使用动态脚本路径显示用法
- `baoyu-comic``baoyu-xhs-images`:通过 skill 接口调用图片生成,不再直接调用脚本
## 1.56.1 - 2026-03-08
### 修复
- `baoyu-post-to-weibo`:简化头条文章图片插入逻辑,使用 Backspace 按键替代复杂的 deleteContents 方案,兼容 ProseMirror 编辑器
## 1.56.0 - 2026-03-08
### 新功能
- `baoyu-article-illustrator`:预设优先选择流程,按内容类型分类的风格预设
- `baoyu-xhs-images`:精简工作流从 6 步到 4 步,新增智能确认(快速/自定义/详细三种路径)
### 修复
- `baoyu-post-to-wechat`:通过文件选择器拦截改进图片上传可靠性
## 1.55.0 - 2026-03-08 ## 1.55.0 - 2026-03-08
### 新功能 ### 新功能
+14 -8
View File
@@ -89,7 +89,7 @@ ${BUN_X} skills/baoyu-danger-gemini-web/scripts/main.ts --promptfiles system.md
- **Bun**: TypeScript runtime (native `bun` preferred, fallback `npx -y bun`) - **Bun**: TypeScript runtime (native `bun` preferred, fallback `npx -y bun`)
- **Chrome**: Required for `baoyu-danger-gemini-web` auth and `baoyu-post-to-x` automation - **Chrome**: Required for `baoyu-danger-gemini-web` auth and `baoyu-post-to-x` automation
- **No npm packages**: Self-contained TypeScript, no external dependencies - **npm packages (per skill)**: Some skill subprojects include `package.json`/lockfiles and require dependency installation in their own `scripts/` directories
## Chrome Profile (Unified) ## Chrome Profile (Unified)
@@ -472,22 +472,27 @@ Check EXTEND.md existence (priority order):
\`\`\`bash \`\`\`bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/<skill-name>/EXTEND.md && echo "project" test -f .baoyu-skills/<skill-name>/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/<skill-name>/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/<skill-name>/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/<skill-name>/EXTEND.md" && echo "user"
\`\`\` \`\`\`
\`\`\`powershell \`\`\`powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/<skill-name>/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/<skill-name>/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/<skill-name>/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/<skill-name>/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/<skill-name>/EXTEND.md") { "user" }
\`\`\` \`\`\`
┌───────────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────┬──────────────────────────┐
Path Location │ Path Location
├───────────────────────────────────────────────────────────────┤ ├────────────────────────────────────────────────────────┼──────────────────────────┤
│ .baoyu-skills/<skill-name>/EXTEND.md │ Project directory │ │ .baoyu-skills/<skill-name>/EXTEND.md │ Project directory
├───────────────────────────────────────────────────────────────┤ ├────────────────────────────────────────────────────────┼──────────────────────────┤
│ $HOME/.baoyu-skills/<skill-name>/EXTEND.md │ User home │ $XDG_CONFIG_HOME/baoyu-skills/<skill-name>/EXTEND.md │ XDG config (~/.config)
─────────────────────────────────────────────────────────────── ├────────────────────────────────────────────────────────┼──────────────────────────
│ $HOME/.baoyu-skills/<skill-name>/EXTEND.md │ User home (legacy) │
└────────────────────────────────────────────────────────┴──────────────────────────┘
┌───────────┬───────────────────────────────────────────────────────────────────────────┐ ┌───────────┬───────────────────────────────────────────────────────────────────────────┐
│ Result │ Action │ │ Result │ Action │
@@ -523,5 +528,6 @@ Custom configurations via EXTEND.md. See **Preferences** section for paths and s
**Notes**: **Notes**:
- Replace `<skill-name>` with actual skill name (e.g., `baoyu-cover-image`) - Replace `<skill-name>` with actual skill name (e.g., `baoyu-cover-image`)
- Use `$HOME` instead of `~` for cross-platform compatibility (macOS/Linux/WSL/PowerShell) - Use `$HOME` instead of `~` for cross-platform compatibility (macOS/Linux/WSL/PowerShell)
- `$XDG_CONFIG_HOME` defaults to `~/.config` when unset
- Use `test -f` (Bash) or `Test-Path` (PowerShell) for explicit file existence check - Use `test -f` (Bash) or `Test-Path` (PowerShell) for explicit file existence check
- ASCII tables for clear visual formatting - ASCII tables for clear visual formatting
+37 -1
View File
@@ -17,6 +17,27 @@ Skills shared by Baoyu for improving daily work efficiency with Claude Code.
npx skills add jimliu/baoyu-skills npx skills add jimliu/baoyu-skills
``` ```
### Publish to ClawHub / OpenClaw
This repository now supports publishing each `skills/baoyu-*` directory as an individual ClawHub skill.
```bash
# Preview what would be published
./scripts/sync-clawhub.sh --dry-run
# Publish all changed skills from ./skills
./scripts/sync-clawhub.sh --all
```
ClawHub installs skills individually, not as one marketplace bundle. After publishing, users can install specific skills such as:
```bash
clawhub install baoyu-image-gen
clawhub install baoyu-markdown-to-html
```
Publishing to ClawHub releases the published skill under `MIT-0`, per ClawHub's registry rules.
### Register as Plugin Marketplace ### Register as Plugin Marketplace
Run the following command in Claude Code: Run the following command in Claude Code:
@@ -55,7 +76,7 @@ Simply tell Claude Code:
|--------|-------------|--------| |--------|-------------|--------|
| **content-skills** | Content generation and publishing | [xhs-images](#baoyu-xhs-images), [infographic](#baoyu-infographic), [cover-image](#baoyu-cover-image), [slide-deck](#baoyu-slide-deck), [comic](#baoyu-comic), [article-illustrator](#baoyu-article-illustrator), [post-to-x](#baoyu-post-to-x), [post-to-wechat](#baoyu-post-to-wechat), [post-to-weibo](#baoyu-post-to-weibo) | | **content-skills** | Content generation and publishing | [xhs-images](#baoyu-xhs-images), [infographic](#baoyu-infographic), [cover-image](#baoyu-cover-image), [slide-deck](#baoyu-slide-deck), [comic](#baoyu-comic), [article-illustrator](#baoyu-article-illustrator), [post-to-x](#baoyu-post-to-x), [post-to-wechat](#baoyu-post-to-wechat), [post-to-weibo](#baoyu-post-to-weibo) |
| **ai-generation-skills** | AI-powered generation backends | [image-gen](#baoyu-image-gen), [danger-gemini-web](#baoyu-danger-gemini-web) | | **ai-generation-skills** | AI-powered generation backends | [image-gen](#baoyu-image-gen), [danger-gemini-web](#baoyu-danger-gemini-web) |
| **utility-skills** | Utility tools for content processing | [url-to-markdown](#baoyu-url-to-markdown), [danger-x-to-markdown](#baoyu-danger-x-to-markdown), [compress-image](#baoyu-compress-image), [format-markdown](#baoyu-format-markdown), [translate](#baoyu-translate) | | **utility-skills** | Utility tools for content processing | [url-to-markdown](#baoyu-url-to-markdown), [danger-x-to-markdown](#baoyu-danger-x-to-markdown), [compress-image](#baoyu-compress-image), [format-markdown](#baoyu-format-markdown), [markdown-to-html](#baoyu-markdown-to-html), [translate](#baoyu-translate) |
## Update Skills ## Update Skills
@@ -777,6 +798,21 @@ Format plain text or markdown files with proper frontmatter, titles, summaries,
| Code/commands | `` `inline` `` or ` ```block``` ` | | Code/commands | `` `inline` `` or ` ```block``` ` |
| Quotes | `>` blockquote | | Quotes | `>` blockquote |
#### baoyu-markdown-to-html
Convert markdown files into styled HTML with WeChat-compatible themes, syntax highlighting, and optional bottom citations for external links.
```bash
# Basic conversion
/baoyu-markdown-to-html article.md
# Theme + color
/baoyu-markdown-to-html article.md --theme grace --color red
# Convert ordinary external links to bottom citations
/baoyu-markdown-to-html article.md --cite
```
#### baoyu-translate #### baoyu-translate
Translate articles and documents between languages with three modes: quick (direct), normal (analysis-informed), and refined (full publication-quality workflow with review and polish). Translate articles and documents between languages with three modes: quick (direct), normal (analysis-informed), and refined (full publication-quality workflow with review and polish).
+37 -1
View File
@@ -17,6 +17,27 @@
npx skills add jimliu/baoyu-skills npx skills add jimliu/baoyu-skills
``` ```
### 发布到 ClawHub / OpenClaw
现在这个仓库支持把每个 `skills/baoyu-*` 目录作为独立 ClawHub skill 发布。
```bash
# 预览将要发布的变更
./scripts/sync-clawhub.sh --dry-run
# 发布 ./skills 下所有已变更的 skill
./scripts/sync-clawhub.sh --all
```
ClawHub 按“单个 skill”安装,不是把整个 marketplace 一次性装进去。发布后,用户可以按需安装:
```bash
clawhub install baoyu-image-gen
clawhub install baoyu-markdown-to-html
```
根据 ClawHub 的 registry 规则,发布到 ClawHub 的 skill 会以 `MIT-0` 许可分发。
### 注册插件市场 ### 注册插件市场
在 Claude Code 中运行: 在 Claude Code 中运行:
@@ -55,7 +76,7 @@ npx skills add jimliu/baoyu-skills
|------|------|----------| |------|------|----------|
| **content-skills** | 内容生成和发布 | [xhs-images](#baoyu-xhs-images), [infographic](#baoyu-infographic), [cover-image](#baoyu-cover-image), [slide-deck](#baoyu-slide-deck), [comic](#baoyu-comic), [article-illustrator](#baoyu-article-illustrator), [post-to-x](#baoyu-post-to-x), [post-to-wechat](#baoyu-post-to-wechat), [post-to-weibo](#baoyu-post-to-weibo) | | **content-skills** | 内容生成和发布 | [xhs-images](#baoyu-xhs-images), [infographic](#baoyu-infographic), [cover-image](#baoyu-cover-image), [slide-deck](#baoyu-slide-deck), [comic](#baoyu-comic), [article-illustrator](#baoyu-article-illustrator), [post-to-x](#baoyu-post-to-x), [post-to-wechat](#baoyu-post-to-wechat), [post-to-weibo](#baoyu-post-to-weibo) |
| **ai-generation-skills** | AI 生成后端 | [image-gen](#baoyu-image-gen), [danger-gemini-web](#baoyu-danger-gemini-web) | | **ai-generation-skills** | AI 生成后端 | [image-gen](#baoyu-image-gen), [danger-gemini-web](#baoyu-danger-gemini-web) |
| **utility-skills** | 内容处理工具 | [url-to-markdown](#baoyu-url-to-markdown), [danger-x-to-markdown](#baoyu-danger-x-to-markdown), [compress-image](#baoyu-compress-image), [format-markdown](#baoyu-format-markdown), [translate](#baoyu-translate) | | **utility-skills** | 内容处理工具 | [url-to-markdown](#baoyu-url-to-markdown), [danger-x-to-markdown](#baoyu-danger-x-to-markdown), [compress-image](#baoyu-compress-image), [format-markdown](#baoyu-format-markdown), [markdown-to-html](#baoyu-markdown-to-html), [translate](#baoyu-translate) |
## 更新技能 ## 更新技能
@@ -777,6 +798,21 @@ AI 驱动的生成后端。
| 代码/命令 | `` `行内` `` 或 ` ```代码块``` ` | | 代码/命令 | `` `行内` `` 或 ` ```代码块``` ` |
| 引用 | `>` 引用块 | | 引用 | `>` 引用块 |
#### baoyu-markdown-to-html
将 Markdown 文件转换为样式化 HTML,支持微信公众号兼容主题、代码高亮,以及可选的外链底部引用。
```bash
# 基础转换
/baoyu-markdown-to-html article.md
# 主题 + 颜色
/baoyu-markdown-to-html article.md --theme grace --color red
# 将普通外链转换为文末引用
/baoyu-markdown-to-html article.md --cite
```
#### baoyu-translate #### baoyu-translate
三模式翻译技能:快速(直接翻译)、标准(分析后翻译)、精翻(完整出版级工作流,含审校与润色)。 三模式翻译技能:快速(直接翻译)、标准(分析后翻译)、精翻(完整出版级工作流,含审校与润色)。
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SKILLS_DIR="${ROOT_DIR}/skills"
if command -v clawhub >/dev/null 2>&1; then
CLAWHUB_CMD=(clawhub)
elif command -v npx >/dev/null 2>&1; then
CLAWHUB_CMD=(npx -y clawhub)
else
echo "Error: neither clawhub nor npx is available."
echo "See https://docs.openclaw.ai/zh-CN/tools/clawhub"
exit 1
fi
if [ "$#" -eq 0 ]; then
set -- --all
fi
exec "${CLAWHUB_CMD[@]}" sync --root "${SKILLS_DIR}" "$@"
+10 -3
View File
@@ -1,6 +1,10 @@
--- ---
name: baoyu-article-illustrator name: baoyu-article-illustrator
description: Analyzes article structure, identifies positions requiring visual aids, generates illustrations with Type × Style two-dimension approach. Use when user asks to "illustrate article", "add images", "generate images for article", or "为文章配图". description: Analyzes article structure, identifies positions requiring visual aids, generates illustrations with Type × Style two-dimension approach. Use when user asks to "illustrate article", "add images", "generate images for article", or "为文章配图".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-article-illustrator
--- ---
# Article Illustrator # Article Illustrator
@@ -51,12 +55,15 @@ See [references/styles.md](references/styles.md) for Core Styles, full gallery,
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-article-illustrator/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-article-illustrator/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "user" }
``` ```
@@ -82,13 +89,13 @@ Full procedures: [references/workflow.md](references/workflow.md#step-2-setup--a
### Step 3: Confirm Settings ⚠️ ### Step 3: Confirm Settings ⚠️
**ONE AskUserQuestion, max 4 Qs. Q1-Q3 REQUIRED.** **ONE AskUserQuestion, max 4 Qs. Q1-Q2 REQUIRED. Q3 required unless preset chosen.**
| Q | Options | | Q | Options |
|---|---------| |---|---------|
| **Q1: Type** | [Recommended], infographic, scene, flowchart, comparison, framework, timeline, mixed | | **Q1: Preset or Type** | [Recommended preset], [alt preset], or manual: infographic, scene, flowchart, comparison, framework, timeline, mixed |
| **Q2: Density** | minimal (1-2), balanced (3-5), per-section (Recommended), rich (6+) | | **Q2: Density** | minimal (1-2), balanced (3-5), per-section (Recommended), rich (6+) |
| **Q3: Style** | [Recommended], minimal-flat, sci-fi, hand-drawn, editorial, scene, poster, Other | | **Q3: Style** | [Recommended], minimal-flat, sci-fi, hand-drawn, editorial, scene, poster, Other**skip if preset chosen** |
| Q4: Language | When article language ≠ EXTEND.md setting | | Q4: Language | When article language ≠ EXTEND.md setting |
Full procedures: [references/workflow.md](references/workflow.md#step-3-confirm-settings-) Full procedures: [references/workflow.md](references/workflow.md#step-3-confirm-settings-)
@@ -2,26 +2,67 @@
`--preset X` expands to a type + style combination. Users can override either dimension. `--preset X` expands to a type + style combination. Users can override either dimension.
| --preset | Type | Style | ## By Category
|----------|------|-------|
| `tech-explainer` | `infographic` | `blueprint` | ### Technical & Engineering
| `knowledge-base` | `infographic` | `vector-illustration` |
| `saas-guide` | `infographic` | `notion` | | --preset | Type | Style | Best For |
| `data-report` | `infographic` | `editorial` | |----------|------|-------|----------|
| `science-paper` | `infographic` | `scientific` | | `tech-explainer` | `infographic` | `blueprint` | API docs, system metrics, technical deep-dives |
| `tutorial` | `flowchart` | `vector-illustration` | | `system-design` | `framework` | `blueprint` | Architecture diagrams, system design |
| `process-flow` | `flowchart` | `notion` | | `architecture` | `framework` | `vector-illustration` | Component relationships, module structure |
| `system-design` | `framework` | `blueprint` | | `science-paper` | `infographic` | `scientific` | Research findings, lab results, academic |
| `architecture` | `framework` | `vector-illustration` |
| `versus` | `comparison` | `vector-illustration` | ### Knowledge & Education
| `business-compare` | `comparison` | `elegant` |
| `storytelling` | `scene` | `warm` | | --preset | Type | Style | Best For |
| `lifestyle` | `scene` | `watercolor` | |----------|------|-------|----------|
| `history` | `timeline` | `elegant` | | `knowledge-base` | `infographic` | `vector-illustration` | Concept explainers, tutorials, how-to |
| `evolution` | `timeline` | `warm` | | `saas-guide` | `infographic` | `notion` | Product guides, SaaS docs, tool walkthroughs |
| `opinion-piece` | `scene` | `screen-print` | | `tutorial` | `flowchart` | `vector-illustration` | Step-by-step tutorials, setup guides |
| `editorial-poster` | `comparison` | `screen-print` | | `process-flow` | `flowchart` | `notion` | Workflow documentation, onboarding flows |
| `cinematic` | `scene` | `screen-print` |
### Data & Analysis
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `data-report` | `infographic` | `editorial` | Data journalism, metrics reports, dashboards |
| `versus` | `comparison` | `vector-illustration` | Tech comparisons, framework shootouts |
| `business-compare` | `comparison` | `elegant` | Product evaluations, strategy options |
### Narrative & Creative
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `storytelling` | `scene` | `warm` | Personal essays, reflections, growth stories |
| `lifestyle` | `scene` | `watercolor` | Travel, wellness, lifestyle, creative |
| `history` | `timeline` | `elegant` | Historical overviews, milestones |
| `evolution` | `timeline` | `warm` | Progress narratives, growth journeys |
### Editorial & Opinion
| --preset | Type | Style | Best For |
|----------|------|-------|----------|
| `opinion-piece` | `scene` | `screen-print` | Op-eds, commentary, critical essays |
| `editorial-poster` | `comparison` | `screen-print` | Debate, contrasting viewpoints |
| `cinematic` | `scene` | `screen-print` | Dramatic narratives, cultural essays |
## Content Type → Preset Recommendations
Use this table during Step 3 to recommend presets based on Step 2 content analysis:
| Content Type (Step 2) | Primary Preset | Alternatives |
|------------------------|----------------|--------------|
| Technical | `tech-explainer` | `system-design`, `architecture` |
| Tutorial | `tutorial` | `process-flow`, `knowledge-base` |
| Methodology / Framework | `system-design` | `architecture`, `process-flow` |
| Data / Metrics | `data-report` | `versus`, `tech-explainer` |
| Comparison / Review | `versus` | `business-compare`, `editorial-poster` |
| Narrative / Personal | `storytelling` | `lifestyle`, `evolution` |
| Opinion / Editorial | `opinion-piece` | `cinematic`, `editorial-poster` |
| Historical / Timeline | `history` | `evolution` |
| Academic / Research | `science-paper` | `tech-explainer`, `data-report` |
| SaaS / Product | `saas-guide` | `knowledge-base`, `process-flow` |
## Override Examples ## Override Examples
@@ -88,12 +88,15 @@ Check preferences and existing state, then ask ALL needed questions in ONE AskUs
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-article-illustrator/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-article-illustrator/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "user" }
``` ```
@@ -165,9 +168,16 @@ For each reference image:
**Do NOT skip.** Use ONE AskUserQuestion call with max 4 questions. **Q1, Q2, Q3 are ALL REQUIRED.** **Do NOT skip.** Use ONE AskUserQuestion call with max 4 questions. **Q1, Q2, Q3 are ALL REQUIRED.**
### Q1: Illustration Type ⚠️ REQUIRED ### Q1: Preset or Type ⚠️ REQUIRED
- [Recommended based on analysis] (Recommended)
- infographic / scene / flowchart / comparison / framework / timeline / mixed Based on Step 2 content analysis, recommend a preset first (sets both type & style). Look up [style-presets.md](style-presets.md) "Content Type → Preset Recommendations" table.
- [Recommended preset] — [brief: type + style + why] (Recommended)
- [Alternative preset] — [brief]
- Or choose type manually: infographic / scene / flowchart / comparison / framework / timeline / mixed
**If user picks a preset → skip Q3** (type & style both resolved).
**If user picks a type → Q3 is REQUIRED.**
### Q2: Density ⚠️ REQUIRED - DO NOT SKIP ### Q2: Density ⚠️ REQUIRED - DO NOT SKIP
- minimal (1-2) - Core concepts only - minimal (1-2) - Core concepts only
@@ -175,7 +185,7 @@ For each reference image:
- per-section - At least 1 per section/chapter (Recommended) - per-section - At least 1 per section/chapter (Recommended)
- rich (6+) - Comprehensive coverage - rich (6+) - Comprehensive coverage
### Q3: Style ⚠️ REQUIRED (ALWAYS ask, even with preferred_style in EXTEND.md) ### Q3: Style ⚠️ REQUIRED (skip if preset chosen in Q1)
If EXTEND.md has `preferred_style`: If EXTEND.md has `preferred_style`:
- [Custom style name + brief description] (Recommended) - [Custom style name + brief description] (Recommended)
@@ -191,14 +201,14 @@ If no `preferred_style` (present Core Styles first):
**Core Styles** (simplified selection): **Core Styles** (simplified selection):
| Core Style | Best For | | Core Style | Maps To | Best For |
|------------|----------| |------------|---------|----------|
| `minimal-flat` | General, knowledge sharing, SaaS | | `minimal-flat` | notion | General, knowledge sharing, SaaS |
| `sci-fi` | AI, frontier tech, system design | | `sci-fi` | blueprint | AI, frontier tech, system design |
| `hand-drawn` | Relaxed, reflective, casual | | `hand-drawn` | sketch/warm | Relaxed, reflective, casual |
| `editorial` | Processes, data, journalism | | `editorial` | editorial | Processes, data, journalism |
| `scene` | Narratives, emotional, lifestyle | | `scene` | warm/watercolor | Narratives, emotional, lifestyle |
| `poster` | Opinion, editorial, cultural, cinematic | | `poster` | screen-print | Opinion, editorial, cultural, cinematic |
Style selection based on Type × Style compatibility matrix (styles.md). Style selection based on Type × Style compatibility matrix (styles.md).
Full specs: `styles/<style>.md` Full specs: `styles/<style>.md`
+21 -17
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-comic name: baoyu-comic
description: Knowledge comic creator supporting multiple art styles and tones. Creates original educational comics with detailed panel layouts and sequential image generation. Use when user asks to create "知识漫画", "教育漫画", "biography comic", "tutorial comic", or "Logicomix-style comic". description: Knowledge comic creator supporting multiple art styles and tones. Creates original educational comics with detailed panel layouts and sequential image generation. Use when user asks to create "知识漫画", "教育漫画", "biography comic", "tutorial comic", or "Logicomix-style comic".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-comic
requires:
anyBins:
- bun
- npx
--- ---
# Knowledge Comic Creator # Knowledge Comic Creator
@@ -104,9 +112,9 @@ Details: [references/auto-selection.md](references/auto-selection.md)
**Important**: All scripts are located in the `scripts/` subdirectory of this skill. **Important**: All scripts are located in the `scripts/` subdirectory of this skill.
**Agent Execution Instructions**: **Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `SKILL_DIR` 1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts` 2. Script path = `{baseDir}/scripts/<script-name>.ts`
3. Replace all `${SKILL_DIR}` in this document with the actual path 3. Replace all `{baseDir}` in this document with the actual path
4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
**Script Reference**: **Script Reference**:
@@ -208,12 +216,11 @@ Analyze → [Check Existing?] → [Confirm: Style + Reviews] → Storyboard →
**7.1 Generate character sheet first**: **7.1 Generate character sheet first**:
- **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png` - **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png`
```bash - Invoke an installed image generation skill such as `baoyu-image-gen`
# Use Reference Sheet Prompt from characters/characters.md - Read that skill's `SKILL.md` and follow its documented interface rather than calling its scripts directly
${BUN_X} ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \ - Use `characters/characters.md` as the prompt-file input
--promptfiles characters/characters.md \ - Save output to `characters/characters.png`
--image characters/characters.png --ar 4:3 - Use aspect ratio `4:3`
```
**Compress character sheet** (recommended): **Compress character sheet** (recommended):
Compress to reduce token usage when used as reference image: Compress to reduce token usage when used as reference image:
@@ -231,14 +238,11 @@ Compress to reduce token usage when used as reference image:
**Backup rules for page generation**: **Backup rules for page generation**:
- If prompt file exists: rename to `prompts/NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.md` - If prompt file exists: rename to `prompts/NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.md`
- If image file exists: rename to `NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.png` - If image file exists: rename to `NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.png`
- Invoke the installed image generation skill for each page
```bash - Use `prompts/01-page-xxx.md` as the prompt-file input
# Example: ALWAYS include --ref for consistency - Save output to `01-page-xxx.png`
${BUN_X} ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \ - Use aspect ratio `3:4`
--promptfiles prompts/01-page-xxx.md \ - If the chosen skill supports reference images, pass `characters/characters.png` as `--ref`
--image 01-page-xxx.png --ar 3:4 \
--ref characters/characters.png
```
**Full workflow details**: [references/workflow.md](references/workflow.md) **Full workflow details**: [references/workflow.md](references/workflow.md)
+10 -9
View File
@@ -39,12 +39,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-comic/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-comic/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-comic/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-comic/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-comic/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-comic/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-comic/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-comic/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-comic/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-comic/EXTEND.md") { "user" }
``` ```
@@ -433,14 +436,12 @@ With confirmed prompts from Step 5/6:
**Strategy A: Using `--ref` parameter** (e.g., baoyu-image-gen) **Strategy A: Using `--ref` parameter** (e.g., baoyu-image-gen)
```bash - Read the chosen image generation skill's `SKILL.md`
# Each page generation MUST include --ref - Invoke that installed skill via its documented interface, not by calling its scripts directly
${BUN_X} ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \ - For every page, use `prompts/01-page-xxx.md` as the prompt-file input
--promptfiles prompts/01-page-xxx.md \ - Save output to `01-page-xxx.png`
--image 01-page-xxx.png \ - Use aspect ratio `3:4`
--ar 3:4 \ - Pass `characters/characters.png` as `--ref` on every page generation
--ref characters/characters.png
```
**Strategy B: Embedding character descriptions in prompt** **Strategy B: Embedding character descriptions in prompt**
@@ -478,7 +479,7 @@ If image generation skill supports `--sessionId`:
After all images generated: After all images generated:
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/merge-to-pdf.ts <comic-dir> ${BUN_X} {baseDir}/scripts/merge-to-pdf.ts <comic-dir>
``` ```
Creates `{topic-slug}.pdf` with all pages as full-page images. Creates `{topic-slug}.pdf` with all pages as full-page images.
+17 -6
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-compress-image name: baoyu-compress-image
description: Compresses images to WebP (default) or PNG with automatic tool selection. Use when user asks to "compress image", "optimize image", "convert to webp", or reduce image file size. description: Compresses images to WebP (default) or PNG with automatic tool selection. Use when user asks to "compress image", "optimize image", "convert to webp", or reduce image file size.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-compress-image
requires:
anyBins:
- bun
- npx
--- ---
# Image Compressor # Image Compressor
@@ -9,7 +17,7 @@ Compresses images using best available tool (sips → cwebp → ImageMagick →
## Script Directory ## Script Directory
Scripts in `scripts/` subdirectory. `${SKILL_DIR}` = this SKILL.md's directory path. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `${SKILL_DIR}` and `${BUN_X}` with actual values. Scripts in `scripts/` subdirectory. `{baseDir}` = this SKILL.md's directory path. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `{baseDir}` and `${BUN_X}` with actual values.
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
@@ -22,12 +30,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-compress-image/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-compress-image/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-compress-image/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-compress-image/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-compress-image/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-compress-image/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md") { "user" }
``` ```
@@ -52,7 +63,7 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md") { "user" }
## Usage ## Usage
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/main.ts <input> [options] ${BUN_X} {baseDir}/scripts/main.ts <input> [options]
``` ```
## Options ## Options
@@ -71,16 +82,16 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <input> [options]
```bash ```bash
# Single file → WebP (replaces original) # Single file → WebP (replaces original)
${BUN_X} ${SKILL_DIR}/scripts/main.ts image.png ${BUN_X} {baseDir}/scripts/main.ts image.png
# Keep PNG format # Keep PNG format
${BUN_X} ${SKILL_DIR}/scripts/main.ts image.png -f png --keep ${BUN_X} {baseDir}/scripts/main.ts image.png -f png --keep
# Directory recursive # Directory recursive
${BUN_X} ${SKILL_DIR}/scripts/main.ts ./images/ -r -q 75 ${BUN_X} {baseDir}/scripts/main.ts ./images/ -r -q 75
# JSON output # JSON output
${BUN_X} ${SKILL_DIR}/scripts/main.ts image.png --json ${BUN_X} {baseDir}/scripts/main.ts image.png --json
``` ```
**Output**: **Output**:
+7
View File
@@ -1,6 +1,10 @@
--- ---
name: baoyu-cover-image name: baoyu-cover-image
description: Generates article cover images with 5 dimensions (type, palette, rendering, text, mood) combining 10 color palettes and 7 rendering styles. Supports cinematic (2.35:1), widescreen (16:9), and square (1:1) aspects. Use when user asks to "generate cover image", "create article cover", or "make cover". description: Generates article cover images with 5 dimensions (type, palette, rendering, text, mood) combining 10 color palettes and 7 rendering styles. Supports cinematic (2.35:1), widescreen (16:9), and square (1:1) aspects. Use when user asks to "generate cover image", "create article cover", or "make cover".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-cover-image
--- ---
# Cover Image Generator # Cover Image Generator
@@ -130,12 +134,15 @@ Check EXTEND.md existence (priority: project → user):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-cover-image/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-cover-image/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-cover-image/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-cover-image/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-cover-image/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-cover-image/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md") { "user" }
``` ```
+23 -12
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-danger-gemini-web name: baoyu-danger-gemini-web
description: Generates images and text via reverse-engineered Gemini Web API. Supports text generation, image generation from prompts, reference images for vision input, and multi-turn conversations. Use when other skills need image generation backend, or when user requests "generate image with Gemini", "Gemini text generation", or needs vision-capable AI generation. description: Generates images and text via reverse-engineered Gemini Web API. Supports text generation, image generation from prompts, reference images for vision input, and multi-turn conversations. Use when other skills need image generation backend, or when user requests "generate image with Gemini", "Gemini text generation", or needs vision-capable AI generation.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-danger-gemini-web
requires:
anyBins:
- bun
- npx
--- ---
# Gemini Web Client # Gemini Web Client
@@ -12,10 +20,10 @@ Text/image generation via Gemini Web API. Supports reference images and multi-tu
**Important**: All scripts are located in the `scripts/` subdirectory of this skill. **Important**: All scripts are located in the `scripts/` subdirectory of this skill.
**Agent Execution Instructions**: **Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `SKILL_DIR` 1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts` 2. Script path = `{baseDir}/scripts/<script-name>.ts`
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
4. Replace all `${SKILL_DIR}` and `${BUN_X}` in this document with actual values 4. Replace all `{baseDir}` and `${BUN_X}` in this document with actual values
**Script Reference**: **Script Reference**:
| Script | Purpose | | Script | Purpose |
@@ -49,12 +57,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-danger-gemini-web/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-danger-gemini-web/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-danger-gemini-web/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-danger-gemini-web/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-danger-gemini-web/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-danger-gemini-web/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md") { "user" }
``` ```
@@ -80,23 +91,23 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md") { "user"
```bash ```bash
# Text generation # Text generation
${BUN_X} ${SKILL_DIR}/scripts/main.ts "Your prompt" ${BUN_X} {baseDir}/scripts/main.ts "Your prompt"
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Your prompt" --model gemini-3-flash ${BUN_X} {baseDir}/scripts/main.ts --prompt "Your prompt" --model gemini-3-flash
# Image generation # Image generation
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cute cat" --image cat.png ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cute cat" --image cat.png
${BUN_X} ${SKILL_DIR}/scripts/main.ts --promptfiles system.md content.md --image out.png ${BUN_X} {baseDir}/scripts/main.ts --promptfiles system.md content.md --image out.png
# Vision input (reference images) # Vision input (reference images)
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Describe this" --reference image.png ${BUN_X} {baseDir}/scripts/main.ts --prompt "Describe this" --reference image.png
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Create variation" --reference a.png --image out.png ${BUN_X} {baseDir}/scripts/main.ts --prompt "Create variation" --reference a.png --image out.png
# Multi-turn conversation # Multi-turn conversation
${BUN_X} ${SKILL_DIR}/scripts/main.ts "Remember: 42" --sessionId session-abc ${BUN_X} {baseDir}/scripts/main.ts "Remember: 42" --sessionId session-abc
${BUN_X} ${SKILL_DIR}/scripts/main.ts "What number?" --sessionId session-abc ${BUN_X} {baseDir}/scripts/main.ts "What number?" --sessionId session-abc
# JSON output # JSON output
${BUN_X} ${SKILL_DIR}/scripts/main.ts "Hello" --json ${BUN_X} {baseDir}/scripts/main.ts "Hello" --json
``` ```
## Options ## Options
+21 -6
View File
@@ -59,16 +59,31 @@ function normalizeSessionMetadata(input: unknown): Array<string | null> {
return [null, null, null]; return [null, null, null];
} }
function formatScriptCommand(fallback: string): string {
const raw = process.argv[1];
const displayPath = raw
? (() => {
const relative = path.relative(process.cwd(), raw);
return relative && !relative.startsWith("..") ? relative : raw;
})()
: fallback;
const quotedPath = displayPath.includes(" ")
? `"${displayPath.replace(/"/g, '\\"')}"`
: displayPath;
return `npx -y bun ${quotedPath}`;
}
function printUsage(cookiePath: string, profileDir: string): void { function printUsage(cookiePath: string, profileDir: string): void {
const cmd = formatScriptCommand("scripts/main.ts");
console.log(`Usage: console.log(`Usage:
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts --prompt "Hello" ${cmd} --prompt "Hello"
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts "Hello" ${cmd} "Hello"
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts --prompt "A cute cat" --image generated.png ${cmd} --prompt "A cute cat" --image generated.png
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts --promptfiles system.md content.md --image out.png ${cmd} --promptfiles system.md content.md --image out.png
Multi-turn conversation (agent generates unique sessionId): Multi-turn conversation (agent generates unique sessionId):
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts "Remember 42" --sessionId abc123 ${cmd} "Remember 42" --sessionId abc123
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts "What number?" --sessionId abc123 ${cmd} "What number?" --sessionId abc123
Options: Options:
-p, --prompt <text> Prompt text -p, --prompt <text> Prompt text
+17 -6
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-danger-x-to-markdown name: baoyu-danger-x-to-markdown
description: Converts X (Twitter) tweets and articles to markdown with YAML front matter. Uses reverse-engineered API requiring user consent. Use when user mentions "X to markdown", "tweet to markdown", "save tweet", or provides x.com/twitter.com URLs for conversion. description: Converts X (Twitter) tweets and articles to markdown with YAML front matter. Uses reverse-engineered API requiring user consent. Use when user mentions "X to markdown", "tweet to markdown", "save tweet", or provides x.com/twitter.com URLs for conversion.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-danger-x-to-markdown
requires:
anyBins:
- bun
- npx
--- ---
# X to Markdown # X to Markdown
@@ -14,8 +22,8 @@ Converts X content to markdown:
Scripts located in `scripts/` subdirectory. Scripts located in `scripts/` subdirectory.
**Path Resolution**: **Path Resolution**:
1. `SKILL_DIR` = this SKILL.md's directory 1. `{baseDir}` = this SKILL.md's directory
2. Script path = `${SKILL_DIR}/scripts/main.ts` 2. Script path = `{baseDir}/scripts/main.ts`
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
## Consent Requirement ## Consent Requirement
@@ -75,12 +83,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md") { "user" }
``` ```
@@ -140,10 +151,10 @@ Full reference: [references/config/first-time-setup.md](references/config/first-
## Usage ## Usage
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> ${BUN_X} {baseDir}/scripts/main.ts <url>
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> -o output.md ${BUN_X} {baseDir}/scripts/main.ts <url> -o output.md
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --download-media ${BUN_X} {baseDir}/scripts/main.ts <url> --download-media
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --json ${BUN_X} {baseDir}/scripts/main.ts <url> --json
``` ```
## Options ## Options
@@ -30,8 +30,22 @@ type ConsentRecord = {
const DISCLAIMER_VERSION = "1.0"; const DISCLAIMER_VERSION = "1.0";
function formatScriptCommand(fallback: string): string {
const raw = process.argv[1];
const displayPath = raw
? (() => {
const relative = path.relative(process.cwd(), raw);
return relative && !relative.startsWith("..") ? relative : raw;
})()
: fallback;
const quotedPath = displayPath.includes(" ")
? `"${displayPath.replace(/"/g, '\\"')}"`
: displayPath;
return `npx -y bun ${quotedPath}`;
}
function printUsage(exitCode: number): never { function printUsage(exitCode: number): never {
const cmd = "npx -y bun skills/baoyu-danger-x-to-markdown/scripts/main.ts"; const cmd = formatScriptCommand("scripts/main.ts");
console.log(`X (Twitter) to Markdown console.log(`X (Twitter) to Markdown
Usage: Usage:
@@ -36,6 +36,20 @@ function normalizeInputUrl(input: string): string {
} }
} }
function formatScriptCommand(fallback: string): string {
const raw = process.argv[1];
const displayPath = raw
? (() => {
const relative = path.relative(process.cwd(), raw);
return relative && !relative.startsWith("..") ? relative : raw;
})()
: fallback;
const quotedPath = displayPath.includes(" ")
? `"${displayPath.replace(/"/g, '\\"')}"`
: displayPath;
return `npx -y bun ${quotedPath}`;
}
function parseTweetId(input: string): string | null { function parseTweetId(input: string): string | null {
const trimmed = input.trim(); const trimmed = input.trim();
if (!trimmed) return null; if (!trimmed) return null;
@@ -179,7 +193,7 @@ async function main() {
const { url } = parseArgs(); const { url } = parseArgs();
if (!url) { if (!url) {
console.error("Usage:"); console.error("Usage:");
console.error(" npx -y bun skills/baoyu-danger-x-to-markdown/scripts/tweet-to-markdown.ts <tweet url>"); console.error(` ${formatScriptCommand("scripts/tweet-to-markdown.ts")} <tweet url>`);
process.exit(1); process.exit(1);
} }
+16 -5
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-format-markdown name: baoyu-format-markdown
description: Formats plain text or markdown files with frontmatter, titles, summaries, headings, bold, lists, and code blocks. Use when user asks to "format markdown", "beautify article", "add formatting", or improve article layout. Outputs to {filename}-formatted.md. description: Formats plain text or markdown files with frontmatter, titles, summaries, headings, bold, lists, and code blocks. Use when user asks to "format markdown", "beautify article", "add formatting", or improve article layout. Outputs to {filename}-formatted.md.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-format-markdown
requires:
anyBins:
- bun
- npx
--- ---
# Markdown Formatter # Markdown Formatter
@@ -11,7 +19,7 @@ Transforms plain text or markdown into well-structured, reader-friendly markdown
## Script Directory ## Script Directory
Scripts in `scripts/` subdirectory. `${SKILL_DIR}` = this SKILL.md's directory path. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `${SKILL_DIR}` and `${BUN_X}` with actual values. Scripts in `scripts/` subdirectory. `{baseDir}` = this SKILL.md's directory path. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `{baseDir}` and `${BUN_X}` with actual values.
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
@@ -26,12 +34,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-format-markdown/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-format-markdown/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-format-markdown/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-format-markdown/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-format-markdown/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-format-markdown/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-format-markdown/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-format-markdown/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-format-markdown/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-format-markdown/EXTEND.md") { "user" }
``` ```
@@ -296,7 +307,7 @@ fi
Run the formatting script on the output file: Run the formatting script on the output file:
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/main.ts {output-file-path} [options] ${BUN_X} {baseDir}/scripts/main.ts {output-file-path} [options]
``` ```
**Script Options:** **Script Options:**
@@ -314,13 +325,13 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts {output-file-path} [options]
```bash ```bash
# Default: spacing + emphasis enabled, quotes disabled # Default: spacing + emphasis enabled, quotes disabled
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md ${BUN_X} {baseDir}/scripts/main.ts article.md
# Enable all features including quote replacement # Enable all features including quote replacement
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --quotes ${BUN_X} {baseDir}/scripts/main.ts article.md --quotes
# Only fix emphasis issues, skip spacing # Only fix emphasis issues, skip spacing
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --no-spacing ${BUN_X} {baseDir}/scripts/main.ts article.md --no-spacing
``` ```
**Script performs (based on options):** **Script performs (based on options):**
@@ -1,10 +1,10 @@
import { execSync } from "child_process"; import { spawnSync } from "node:child_process";
import process from "node:process";
export function applyAutocorrect(filePath: string): boolean { export function applyAutocorrect(filePath: string): boolean {
try { const npxCmd = process.platform === "win32" ? "npx.cmd" : "npx";
execSync(`npx autocorrect-node --fix "${filePath}"`, { stdio: "inherit" }); const result = spawnSync(npxCmd, ["autocorrect-node", "--fix", filePath], {
return true; stdio: "inherit",
} catch { });
return false; return result.status === 0;
}
} }
+25 -14
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-image-gen name: baoyu-image-gen
description: AI image generation with OpenAI, Google, DashScope and Replicate APIs. Supports text-to-image, reference images, aspect ratios. Sequential by default; parallel generation available on request. Use when user asks to generate, create, or draw images. description: AI image generation with OpenAI, Google, DashScope and Replicate APIs. Supports text-to-image, reference images, aspect ratios. Sequential by default; parallel generation available on request. Use when user asks to generate, create, or draw images.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-image-gen
requires:
anyBins:
- bun
- npx
--- ---
# Image Generation (AI SDK) # Image Generation (AI SDK)
@@ -10,8 +18,8 @@ Official API-based image generation. Supports OpenAI, Google, DashScope (阿里
## Script Directory ## Script Directory
**Agent Execution**: **Agent Execution**:
1. `SKILL_DIR` = this SKILL.md file's directory 1. `{baseDir}` = this SKILL.md file's directory
2. Script path = `${SKILL_DIR}/scripts/main.ts` 2. Script path = `{baseDir}/scripts/main.ts`
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
## Step 0: Load Preferences ⛔ BLOCKING ## Step 0: Load Preferences ⛔ BLOCKING
@@ -23,12 +31,15 @@ Check EXTEND.md existence (priority: project → user):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-image-gen/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-image-gen/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-image-gen/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-image-gen/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-image-gen/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-image-gen/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-image-gen/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-image-gen/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-image-gen/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-image-gen/EXTEND.md") { "user" }
``` ```
@@ -52,34 +63,34 @@ Schema: `references/config/preferences-schema.md`
```bash ```bash
# Basic # Basic
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image cat.png ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image cat.png
# With aspect ratio # With aspect ratio
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A landscape" --image out.png --ar 16:9 ${BUN_X} {baseDir}/scripts/main.ts --prompt "A landscape" --image out.png --ar 16:9
# High quality # High quality
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --quality 2k ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --quality 2k
# From prompt files # From prompt files
${BUN_X} ${SKILL_DIR}/scripts/main.ts --promptfiles system.md content.md --image out.png ${BUN_X} {baseDir}/scripts/main.ts --promptfiles system.md content.md --image out.png
# With reference images (Google multimodal or OpenAI edits) # With reference images (Google multimodal or OpenAI edits)
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Make blue" --image out.png --ref source.png ${BUN_X} {baseDir}/scripts/main.ts --prompt "Make blue" --image out.png --ref source.png
# With reference images (explicit provider/model) # With reference images (explicit provider/model)
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Make blue" --image out.png --provider google --model gemini-3-pro-image-preview --ref source.png ${BUN_X} {baseDir}/scripts/main.ts --prompt "Make blue" --image out.png --provider google --model gemini-3-pro-image-preview --ref source.png
# Specific provider # Specific provider
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider openai ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --provider openai
# DashScope (阿里通义万象) # DashScope (阿里通义万象)
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "一只可爱的猫" --image out.png --provider dashscope ${BUN_X} {baseDir}/scripts/main.ts --prompt "一只可爱的猫" --image out.png --provider dashscope
# Replicate (google/nano-banana-pro) # Replicate (google/nano-banana-pro)
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate
# Replicate with specific model # Replicate with specific model
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana
``` ```
## Options ## Options
@@ -144,10 +155,10 @@ Examples:
```bash ```bash
# Use Replicate default model # Use Replicate default model
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate
# Override model explicitly # Override model explicitly
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana ${BUN_X} {baseDir}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana
``` ```
## Provider Selection ## Provider Selection
@@ -1,6 +1,6 @@
import path from "node:path"; import path from "node:path";
import { readFile } from "node:fs/promises"; import { readFile } from "node:fs/promises";
import { execSync } from "node:child_process"; import { execFileSync } from "node:child_process";
import type { CliArgs } from "../types"; import type { CliArgs } from "../types";
const GOOGLE_MULTIMODAL_MODELS = [ const GOOGLE_MULTIMODAL_MODELS = [
@@ -76,14 +76,43 @@ async function postGoogleJsonViaCurl<T>(
): Promise<T> { ): Promise<T> {
const proxy = getHttpProxy(); const proxy = getHttpProxy();
const bodyStr = JSON.stringify(body); const bodyStr = JSON.stringify(body);
const proxyArgs = proxy ? `-x "${proxy}"` : ""; const args = [
"-s",
"--connect-timeout",
"30",
"--max-time",
"300",
...(proxy ? ["-x", proxy] : []),
url,
"-H",
"Content-Type: application/json",
"-H",
`x-goog-api-key: ${apiKey}`,
"-d",
"@-",
];
const result = execSync( let result = "";
`curl -s --connect-timeout 30 --max-time 300 ${proxyArgs} "${url}" -H "Content-Type: application/json" -H "x-goog-api-key: ${apiKey}" -d @-`, try {
{ input: bodyStr, maxBuffer: 100 * 1024 * 1024, timeout: 310000 }, result = execFileSync("curl", args, {
); input: bodyStr,
encoding: "utf8",
maxBuffer: 100 * 1024 * 1024,
timeout: 310000,
});
} catch (error) {
const e = error as { message?: string; stderr?: string | Buffer };
const stderrText =
typeof e.stderr === "string"
? e.stderr
: e.stderr
? e.stderr.toString("utf8")
: "";
const details = stderrText.trim() || e.message || "curl request failed";
throw new Error(`Google API request failed via curl: ${details}`);
}
const parsed = JSON.parse(result.toString()) as any; const parsed = JSON.parse(result) as any;
if (parsed.error) { if (parsed.error) {
throw new Error( throw new Error(
`Google API error (${parsed.error.code}): ${parsed.error.message}`, `Google API error (${parsed.error.code}): ${parsed.error.message}`,
+7
View File
@@ -1,6 +1,10 @@
--- ---
name: baoyu-infographic name: baoyu-infographic
description: Generates professional infographics with 21 layout types and 20 visual styles. Analyzes content, recommends layout×style combinations, and generates publication-ready infographics. Use when user asks to create "infographic", "信息图", "visual summary", "可视化", or "高密度信息大图". description: Generates professional infographics with 21 layout types and 20 visual styles. Analyzes content, recommends layout×style combinations, and generates publication-ready infographics. Use when user asks to create "infographic", "信息图", "visual summary", "可视化", or "高密度信息大图".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-infographic
--- ---
# Infographic Generator # Infographic Generator
@@ -143,12 +147,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-infographic/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-infographic/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-infographic/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-infographic/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-infographic/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-infographic/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-infographic/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-infographic/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-infographic/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-infographic/EXTEND.md") { "user" }
``` ```
+20 -9
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-markdown-to-html name: baoyu-markdown-to-html
description: Converts Markdown to styled HTML with WeChat-compatible themes. Supports code highlighting, math, PlantUML, footnotes, alerts, infographics, and optional bottom citations for external links. Use when user asks for "markdown to html", "convert md to html", "md转html", "微信外链转底部引用", or needs styled HTML output from markdown. description: Converts Markdown to styled HTML with WeChat-compatible themes. Supports code highlighting, math, PlantUML, footnotes, alerts, infographics, and optional bottom citations for external links. Use when user asks for "markdown to html", "convert md to html", "md转html", "微信外链转底部引用", or needs styled HTML output from markdown.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-markdown-to-html
requires:
anyBins:
- bun
- npx
--- ---
# Markdown to HTML Converter # Markdown to HTML Converter
@@ -9,7 +17,7 @@ Converts Markdown files to beautifully styled HTML with inline CSS, optimized fo
## Script Directory ## Script Directory
**Agent Execution**: Determine this SKILL.md directory as `SKILL_DIR`. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `${SKILL_DIR}` and `${BUN_X}` with actual values. **Agent Execution**: Determine this SKILL.md directory as `{baseDir}`. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `{baseDir}` and `${BUN_X}` with actual values.
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
@@ -22,12 +30,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-markdown-to-html/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-markdown-to-html/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-markdown-to-html/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-markdown-to-html/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-markdown-to-html/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-markdown-to-html/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-markdown-to-html/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-markdown-to-html/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-markdown-to-html/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-markdown-to-html/EXTEND.md") { "user" }
``` ```
@@ -117,7 +128,7 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { Select-Str
### Step 2: Convert ### Step 2: Convert
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme> [--cite] ${BUN_X} {baseDir}/scripts/main.ts <markdown_file> --theme <theme> [--cite]
``` ```
### Step 3: Report Result ### Step 3: Report Result
@@ -127,7 +138,7 @@ Display the output path from JSON result. If backup was created, mention it.
## Usage ## Usage
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options] ${BUN_X} {baseDir}/scripts/main.ts <markdown_file> [options]
``` ```
**Options:** **Options:**
@@ -165,22 +176,22 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
```bash ```bash
# Basic conversion (uses default theme, removes first heading) # Basic conversion (uses default theme, removes first heading)
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md ${BUN_X} {baseDir}/scripts/main.ts article.md
# With specific theme # With specific theme
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme grace ${BUN_X} {baseDir}/scripts/main.ts article.md --theme grace
# Theme with custom color # Theme with custom color
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme modern --color red ${BUN_X} {baseDir}/scripts/main.ts article.md --theme modern --color red
# Enable bottom citations for ordinary external links # Enable bottom citations for ordinary external links
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --cite ${BUN_X} {baseDir}/scripts/main.ts article.md --cite
# Keep the first heading in content # Keep the first heading in content
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --keep-title ${BUN_X} {baseDir}/scripts/main.ts article.md --keep-title
# Override title # Override title
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --title "My Article" ${BUN_X} {baseDir}/scripts/main.ts article.md --title "My Article"
``` ```
## Output ## Output
@@ -37,6 +37,10 @@ function parseExtendYaml(yaml: string): Partial<ExtendConfig> {
export function loadExtendConfig(): Partial<ExtendConfig> { export function loadExtendConfig(): Partial<ExtendConfig> {
const paths = [ const paths = [
path.join(process.cwd(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"), path.join(process.cwd(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"),
path.join(
process.env.XDG_CONFIG_HOME || path.join(homedir(), ".config"),
"baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"
),
path.join(homedir(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"), path.join(homedir(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"),
]; ];
for (const p of paths) { for (const p of paths) {
+18 -7
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-post-to-wechat name: baoyu-post-to-wechat
description: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions "发布公众号", "post to wechat", "微信公众号", or "贴图/图文/文章". description: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions "发布公众号", "post to wechat", "微信公众号", or "贴图/图文/文章".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat
requires:
anyBins:
- bun
- npx
--- ---
# Post to WeChat Official Account # Post to WeChat Official Account
@@ -11,7 +19,7 @@ description: Posts content to WeChat Official Account (微信公众号) via API
## Script Directory ## Script Directory
**Agent Execution**: Determine this SKILL.md directory as `SKILL_DIR`, then use `${SKILL_DIR}/scripts/<name>.ts`. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. **Agent Execution**: Determine this SKILL.md directory as `{baseDir}`, then use `{baseDir}/scripts/<name>.ts`. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun.
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
@@ -28,12 +36,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-post-to-wechat/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-post-to-wechat/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-post-to-wechat/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-post-to-wechat/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { "user" }
``` ```
@@ -92,7 +103,7 @@ chrome_profile_path: /path/to/chrome/profile
Before first use, suggest running the environment check. User can skip if they prefer. Before first use, suggest running the environment check. User can skip if they prefer.
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/check-permissions.ts ${BUN_X} {baseDir}/scripts/check-permissions.ts
``` ```
Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts. Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts.
@@ -115,8 +126,8 @@ Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystrok
For short posts with multiple images (up to 9): For short posts with multiple images (up to 9):
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/wechat-browser.ts --markdown article.md --images ./images/ ${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown article.md --images ./images/
${BUN_X} ${SKILL_DIR}/scripts/wechat-browser.ts --title "标题" --content "内容" --image img.png --submit ${BUN_X} {baseDir}/scripts/wechat-browser.ts --title "标题" --content "内容" --image img.png --submit
``` ```
See [references/image-text-posting.md](references/image-text-posting.md) for details. See [references/image-text-posting.md](references/image-text-posting.md) for details.
@@ -260,7 +271,7 @@ WECHAT_APP_SECRET=<user_input>
**API method** (accepts `.md` or `.html`): **API method** (accepts `.md` or `.html`):
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--no-cite] ${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--no-cite]
``` ```
**CRITICAL**: Always include `--theme` parameter. Never omit it, even if using `default`. Only include `--color` if explicitly set by user or EXTEND.md. **CRITICAL**: Always include `--theme` parameter. Never omit it, even if using `default`. Only include `--color` if explicitly set by user or EXTEND.md.
@@ -279,8 +290,8 @@ If script parameters do not expose the two comment fields, still ensure final AP
**Browser method** (accepts `--markdown` or `--html`): **Browser method** (accepts `--markdown` or `--html`):
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite] ${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite]
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --html <html_file> ${BUN_X} {baseDir}/scripts/wechat-article.ts --html <html_file>
``` ```
### Step 5: Completion Report ### Step 5: Completion Report
@@ -37,6 +37,10 @@ function parseExtendYaml(yaml: string): Partial<ExtendConfig> {
export function loadExtendConfig(): Partial<ExtendConfig> { export function loadExtendConfig(): Partial<ExtendConfig> {
const paths = [ const paths = [
path.join(process.cwd(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"), path.join(process.cwd(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"),
path.join(
process.env.XDG_CONFIG_HOME || path.join(homedir(), ".config"),
"baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"
),
path.join(homedir(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"), path.join(homedir(), ".baoyu-skills", "baoyu-markdown-to-html", "EXTEND.md"),
]; ];
for (const p of paths) { for (const p of paths) {
@@ -1,4 +1,4 @@
import { execSync, spawnSync } from 'node:child_process'; import { spawnSync } from 'node:child_process';
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import process from 'node:process'; import process from 'node:process';
@@ -10,30 +10,51 @@ function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
function ab(cmd: string, json = false): string { function quoteForLog(arg: string): string {
const fullCmd = `agent-browser --session ${SESSION} ${cmd}${json ? ' --json' : ''}`; return /[\s"'\\]/.test(arg) ? JSON.stringify(arg) : arg;
console.log(`[ab] ${fullCmd}`);
try {
const result = execSync(fullCmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
return result.trim();
} catch (e: unknown) {
const err = e as { stdout?: string; stderr?: string; message?: string };
console.error(`[ab] Error: ${err.stderr || err.message}`);
return err.stdout || '';
}
} }
function abRaw(args: string[]): { success: boolean; output: string } { function toSafeJsStringLiteral(value: string): string {
return JSON.stringify(value)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
}
function runAgentBrowser(args: string[]): {
success: boolean;
output: string;
spawnError?: string;
} {
const result = spawnSync('agent-browser', ['--session', SESSION, ...args], { const result = spawnSync('agent-browser', ['--session', SESSION, ...args], {
encoding: 'utf8', encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe'] stdio: ['pipe', 'pipe', 'pipe']
}); });
const spawnError = result.error?.message?.trim();
const output = result.stdout || result.stderr || '';
return { return {
success: result.status === 0, success: result.status === 0,
output: result.stdout || result.stderr || '' output: output || spawnError || '',
spawnError
}; };
} }
function ab(args: string[], json = false): string {
const fullArgs = json ? [...args, '--json'] : args;
console.log(`[ab] agent-browser --session ${SESSION} ${fullArgs.map(quoteForLog).join(' ')}`);
const result = runAgentBrowser(fullArgs);
if (result.spawnError) {
throw new Error(`agent-browser failed to start: ${result.spawnError}`);
}
if (!result.success) {
console.error(`[ab] Error: ${result.output.trim()}`);
}
return result.output.trim();
}
function abRaw(args: string[]): { success: boolean; output: string } {
return runAgentBrowser(args);
}
interface SnapshotElement { interface SnapshotElement {
ref: string; ref: string;
role: string; role: string;
@@ -99,17 +120,17 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
} }
console.log('[wechat] Opening WeChat Official Account...'); console.log('[wechat] Opening WeChat Official Account...');
ab(`open ${WECHAT_URL} --headed`); ab(['open', WECHAT_URL, '--headed']);
await sleep(5000); await sleep(5000);
console.log('[wechat] Checking login status...'); console.log('[wechat] Checking login status...');
let url = ab('get url'); let url = ab(['get', 'url']);
console.log(`[wechat] Current URL: ${url}`); console.log(`[wechat] Current URL: ${url}`);
const waitForLogin = async (timeoutMs = 120_000): Promise<boolean> => { const waitForLogin = async (timeoutMs = 120_000): Promise<boolean> => {
const start = Date.now(); const start = Date.now();
while (Date.now() - start < timeoutMs) { while (Date.now() - start < timeoutMs) {
url = ab('get url'); url = ab(['get', 'url']);
if (url.includes('/cgi-bin/home')) return true; if (url.includes('/cgi-bin/home')) return true;
console.log('[wechat] Waiting for login...'); console.log('[wechat] Waiting for login...');
await sleep(3000); await sleep(3000);
@@ -126,7 +147,7 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
await sleep(2000); await sleep(2000);
console.log('[wechat] Getting page snapshot...'); console.log('[wechat] Getting page snapshot...');
let snapshot = ab('snapshot'); let snapshot = ab(['snapshot']);
console.log(snapshot); console.log(snapshot);
console.log('[wechat] Looking for "图文" menu...'); console.log('[wechat] Looking for "图文" menu...');
@@ -134,16 +155,16 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
if (!tuWenRef) { if (!tuWenRef) {
console.log('[wechat] Using eval to find and click menu...'); console.log('[wechat] Using eval to find and click menu...');
ab(`eval "document.querySelectorAll('.new-creation__menu .new-creation__menu-item')[2].click()"`); ab(['eval', "document.querySelectorAll('.new-creation__menu .new-creation__menu-item')[2].click()"]);
} else { } else {
console.log(`[wechat] Clicking menu ref: ${tuWenRef}`); console.log(`[wechat] Clicking menu ref: ${tuWenRef}`);
ab(`click ${tuWenRef}`); ab(['click', tuWenRef]);
} }
await sleep(4000); await sleep(4000);
console.log('[wechat] Checking for new tab...'); console.log('[wechat] Checking for new tab...');
const tabsOutput = ab('tab'); const tabsOutput = ab(['tab']);
console.log(`[wechat] Tabs: ${tabsOutput}`); console.log(`[wechat] Tabs: ${tabsOutput}`);
const tabLines = tabsOutput.split('\n'); const tabLines = tabsOutput.split('\n');
@@ -153,14 +174,14 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
const tabMatch = tabsOutput.match(/\[(\d+)\].*(?:appmsg|edit)/i); const tabMatch = tabsOutput.match(/\[(\d+)\].*(?:appmsg|edit)/i);
if (tabMatch) { if (tabMatch) {
console.log(`[wechat] Switching to editor tab ${tabMatch[1]}...`); console.log(`[wechat] Switching to editor tab ${tabMatch[1]}...`);
ab(`tab ${tabMatch[1]}`); ab(['tab', tabMatch[1]]);
} else { } else {
const lastTabMatch = tabsOutput.match(/\[(\d+)\]/g); const lastTabMatch = tabsOutput.match(/\[(\d+)\]/g);
if (lastTabMatch && lastTabMatch.length > 1) { if (lastTabMatch && lastTabMatch.length > 1) {
const lastTab = lastTabMatch[lastTabMatch.length - 1].match(/\d+/)?.[0]; const lastTab = lastTabMatch[lastTabMatch.length - 1].match(/\d+/)?.[0];
if (lastTab) { if (lastTab) {
console.log(`[wechat] Switching to last tab ${lastTab}...`); console.log(`[wechat] Switching to last tab ${lastTab}...`);
ab(`tab ${lastTab}`); ab(['tab', lastTab]);
} }
} }
} }
@@ -168,38 +189,44 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
await sleep(3000); await sleep(3000);
url = ab('get url'); url = ab(['get', 'url']);
console.log(`[wechat] Editor URL: ${url}`); console.log(`[wechat] Editor URL: ${url}`);
console.log('[wechat] Getting editor snapshot...'); console.log('[wechat] Getting editor snapshot...');
snapshot = ab('snapshot'); snapshot = ab(['snapshot']);
console.log(snapshot.substring(0, 2000)); console.log(snapshot.substring(0, 2000));
console.log('[wechat] Uploading images...'); console.log('[wechat] Uploading images...');
const fileInputSelector = '.js_upload_btn_container input[type=file]'; const fileInputSelector = '.js_upload_btn_container input[type=file]';
const fileInputSelectorJs = toSafeJsStringLiteral(fileInputSelector);
ab(`eval "document.querySelector('${fileInputSelector}').style.display = 'block'"`); ab(['eval', `{
const input = document.querySelector(${fileInputSelectorJs});
if (input) input.style.display = 'block';
}`]);
await sleep(500); await sleep(500);
const uploadResult = abRaw(['upload', `"${fileInputSelector}"`, ...absoluteImages]); const uploadResult = abRaw(['upload', fileInputSelector, ...absoluteImages]);
console.log(`[wechat] Upload result: ${uploadResult.output}`); console.log(`[wechat] Upload result: ${uploadResult.output}`);
if (!uploadResult.success) { if (!uploadResult.success) {
console.log('[wechat] Using alternative upload method...'); console.log('[wechat] Using alternative upload method...');
for (const img of absoluteImages) { for (const img of absoluteImages) {
console.log(`[wechat] Uploading: ${img}`); console.log(`[wechat] Uploading: ${img}`);
ab(`eval " const imgUrlJs = toSafeJsStringLiteral(`file://${img}`);
const input = document.querySelector('${fileInputSelector}'); const imgFileNameJs = toSafeJsStringLiteral(path.basename(img));
ab(['eval', `
const input = document.querySelector(${fileInputSelectorJs});
if (input) { if (input) {
const dt = new DataTransfer(); const dt = new DataTransfer();
fetch('file://${img}').then(r => r.blob()).then(b => { fetch(${imgUrlJs}).then(r => r.blob()).then(b => {
const file = new File([b], '${path.basename(img)}', { type: 'image/png' }); const file = new File([b], ${imgFileNameJs}, { type: 'image/png' });
dt.items.add(file); dt.items.add(file);
input.files = dt.files; input.files = dt.files;
input.dispatchEvent(new Event('change', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true }));
}); });
} }
"`); `]);
await sleep(2000); await sleep(2000);
} }
} }
@@ -208,13 +235,14 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
await sleep(10000); await sleep(10000);
console.log('[wechat] Filling title...'); console.log('[wechat] Filling title...');
snapshot = ab('snapshot -i'); snapshot = ab(['snapshot', '-i']);
const titleRef = findElementByText(snapshot, 'title') || findElementByText(snapshot, '标题'); const titleRef = findElementByText(snapshot, 'title') || findElementByText(snapshot, '标题');
if (titleRef) { if (titleRef) {
ab(`fill ${titleRef} "${title.replace(/"/g, '\\"')}"`); ab(['fill', titleRef, title]);
} else { } else {
ab(`eval "const t = document.querySelector('#title'); if(t) { t.value = '${title.replace(/'/g, "\\'")}'; t.dispatchEvent(new Event('input', {bubbles: true})); }"`); const titleJs = toSafeJsStringLiteral(title);
ab(['eval', `const t = document.querySelector('#title'); if(t) { t.value = ${titleJs}; t.dispatchEvent(new Event('input', {bubbles: true})); }`]);
} }
await sleep(500); await sleep(500);
@@ -222,9 +250,9 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
const editorRef = findElementByText(snapshot, 'js_pmEditorArea') || findElementByText(snapshot, 'textbox'); const editorRef = findElementByText(snapshot, 'js_pmEditorArea') || findElementByText(snapshot, 'textbox');
if (editorRef) { if (editorRef) {
ab(`click ${editorRef}`); ab(['click', editorRef]);
} else { } else {
ab(`eval "document.querySelector('.js_pmEditorArea')?.click()"`); ab(['eval', "document.querySelector('.js_pmEditorArea')?.click()"]);
} }
await sleep(500); await sleep(500);
@@ -233,11 +261,11 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
if (line.length > 0) { if (line.length > 0) {
const escapedLine = line.replace(/"/g, '\\"').replace(/'/g, "\\'"); const lineJs = toSafeJsStringLiteral(line);
ab(`eval "document.execCommand('insertText', false, '${escapedLine}')"`); ab(['eval', `document.execCommand('insertText', false, ${lineJs})`]);
} }
if (i < lines.length - 1) { if (i < lines.length - 1) {
ab('press Enter'); ab(['press', 'Enter']);
} }
await sleep(100); await sleep(100);
} }
@@ -249,9 +277,9 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
console.log('[wechat] Saving as draft...'); console.log('[wechat] Saving as draft...');
const submitRef = findElementByText(snapshot, 'js_submit') || findElementByText(snapshot, '保存'); const submitRef = findElementByText(snapshot, 'js_submit') || findElementByText(snapshot, '保存');
if (submitRef) { if (submitRef) {
ab(`click ${submitRef}`); ab(['click', submitRef]);
} else { } else {
ab(`eval "document.querySelector('#js_submit')?.click()"`); ab(['eval', "document.querySelector('#js_submit')?.click()"]);
} }
await sleep(3000); await sleep(3000);
console.log('[wechat] Draft saved!'); console.log('[wechat] Draft saved!');
@@ -261,7 +289,7 @@ async function postToWeChat(options: WeChatOptions): Promise<void> {
if (!keepOpen) { if (!keepOpen) {
console.log('[wechat] Closing browser...'); console.log('[wechat] Closing browser...');
ab('close'); ab(['close']);
} else { } else {
console.log('[wechat] Done. Browser window left open.'); console.log('[wechat] Done. Browser window left open.');
} }
@@ -551,37 +551,126 @@ export async function postToWeChat(options: WeChatBrowserOptions): Promise<void>
const absolutePaths = images.map(p => path.isAbsolute(p) ? p : path.resolve(process.cwd(), p)); const absolutePaths = images.map(p => path.isAbsolute(p) ? p : path.resolve(process.cwd(), p));
console.log(`[wechat-browser] Images: ${absolutePaths.join(', ')}`); console.log(`[wechat-browser] Images: ${absolutePaths.join(', ')}`);
const { root } = await cdp.send<{ root: { nodeId: number } }>('DOM.getDocument', {}, { sessionId }); // --- PRIMARY approach: intercept file chooser dialog ---
let uploadSuccess = false;
try {
console.log('[wechat-browser] [primary] Enabling file chooser interception...');
await cdp.send('Page.setInterceptFileChooserDialog', { enabled: true }, { sessionId });
// Try primary selector, then fallback to any multi-file image input // Set up listener for file chooser opened event BEFORE clicking
let { nodeId } = await cdp.send<{ nodeId: number }>('DOM.querySelector', { const fileChooserPromise = new Promise<{ backendNodeId: number; mode: string }>((resolve, reject) => {
nodeId: root.nodeId, const timeout = setTimeout(() => reject(new Error('File chooser dialog not opened within 10s')), 10_000);
selector: '.js_upload_btn_container input[type=file]', cdp!.on('Page.fileChooserOpened', (params: unknown) => {
}, { sessionId }); clearTimeout(timeout);
const p = params as { backendNodeId: number; mode: string };
console.log(`[wechat-browser] [primary] File chooser opened: backendNodeId=${p.backendNodeId}, mode=${p.mode}`);
resolve(p);
});
});
if (!nodeId) { // Trigger file chooser by calling .click() on the file input with userGesture
console.log('[wechat-browser] Primary file input not found, trying fallback selector...'); const fileInputSelectors = [
const fallback = await cdp.send<{ nodeId: number }>('DOM.querySelector', { '.js_upload_btn_container input[type=file]',
nodeId: root.nodeId, 'input[type=file][multiple][accept*="image"]',
selector: 'input[type=file][multiple][accept*="image"]', 'input[type=file][accept*="image"]',
'input[type=file][multiple]',
'input[type=file]',
];
console.log('[wechat-browser] [primary] Clicking file input via JS .click() with userGesture...');
const clickResult = await cdp.send<{ result: { value: string } }>('Runtime.evaluate', {
expression: `
(function() {
const selectors = ${JSON.stringify(fileInputSelectors)};
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el) {
el.click();
return JSON.stringify({ clicked: sel });
}
}
const debug = [];
document.querySelectorAll('input[type=file]').forEach((inp, i) => {
debug.push({ i, accept: inp.accept, multiple: inp.multiple, parentClass: inp.parentElement?.className?.slice(0, 60) });
});
return JSON.stringify({ error: 'no file input found', fileInputs: debug });
})()
`,
returnByValue: true,
userGesture: true,
}, { sessionId }); }, { sessionId });
nodeId = fallback.nodeId; console.log(`[wechat-browser] [primary] Click result: ${clickResult.result.value}`);
const clickStatus = JSON.parse(clickResult.result.value);
if (clickStatus.error) {
throw new Error(`File input not found: ${clickStatus.error}`);
}
// Wait for the file chooser event
console.log('[wechat-browser] [primary] Waiting for file chooser dialog...');
const chooser = await fileChooserPromise;
console.log(`[wechat-browser] [primary] Setting files via backendNodeId=${chooser.backendNodeId}...`);
await cdp.send('DOM.setFileInputFiles', {
files: absolutePaths,
backendNodeId: chooser.backendNodeId,
}, { sessionId });
console.log('[wechat-browser] [primary] Files set successfully via file chooser interception');
uploadSuccess = true;
} catch (primaryErr) {
console.log(`[wechat-browser] [primary] File chooser approach failed: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`);
// Disable interception before falling back
try { await cdp.send('Page.setInterceptFileChooserDialog', { enabled: false }, { sessionId }); } catch {}
} }
if (!nodeId) throw new Error('File input not found'); // --- FALLBACK approach: direct DOM.setFileInputFiles on nodeId ---
if (!uploadSuccess) {
console.log('[wechat-browser] [fallback] Trying direct DOM.setFileInputFiles...');
const { root } = await cdp.send<{ root: { nodeId: number } }>('DOM.getDocument', {}, { sessionId });
await cdp.send('DOM.setFileInputFiles', { const fileInputSelectors = [
nodeId, '.js_upload_btn_container input[type=file]',
files: absolutePaths, 'input[type=file][multiple][accept*="image"]',
}, { sessionId }); 'input[type=file][accept*="image"]',
'input[type=file][multiple]',
'input[type=file]',
];
// Dispatch change event to trigger the upload let nodeId = 0;
await cdp.send('Runtime.evaluate', { for (const sel of fileInputSelectors) {
expression: ` const result = await cdp.send<{ nodeId: number }>('DOM.querySelector', { nodeId: root.nodeId, selector: sel }, { sessionId });
const fileInput = document.querySelector('.js_upload_btn_container input[type=file]') || document.querySelector('input[type=file][multiple][accept*="image"]'); if (result.nodeId) {
if (fileInput) fileInput.dispatchEvent(new Event('change', { bubbles: true })); console.log(`[wechat-browser] [fallback] Found file input with selector: ${sel}`);
`, nodeId = result.nodeId;
}, { sessionId }); break;
}
}
if (!nodeId) throw new Error('File input not found with any selector');
await cdp.send('DOM.setFileInputFiles', { nodeId, files: absolutePaths }, { sessionId });
console.log('[wechat-browser] [fallback] Files set via nodeId');
// Dispatch change event
await cdp.send('Runtime.evaluate', {
expression: `
(function() {
const selectors = ${JSON.stringify(fileInputSelectors)};
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el) {
el.dispatchEvent(new Event('change', { bubbles: true }));
el.dispatchEvent(new Event('input', { bubbles: true }));
return 'dispatched on ' + sel;
}
}
return 'no input found for event dispatch';
})()
`,
returnByValue: true,
}, { sessionId });
console.log('[wechat-browser] [fallback] Change event dispatched');
}
// Wait for images to upload // Wait for images to upload
console.log('[wechat-browser] Waiting for images to upload...'); console.log('[wechat-browser] Waiting for images to upload...');
@@ -589,11 +678,16 @@ export async function postToWeChat(options: WeChatBrowserOptions): Promise<void>
for (let i = 0; i < 30; i++) { for (let i = 0; i < 30; i++) {
await sleep(2000); await sleep(2000);
const uploadCheck = await cdp.send<{ result: { value: string } }>('Runtime.evaluate', { const uploadCheck = await cdp.send<{ result: { value: string } }>('Runtime.evaluate', {
expression: `JSON.stringify({ uploaded: document.querySelectorAll('.weui-desktop-upload__thumb, .pic_item, [class*=upload_thumb]').length })`, expression: `
JSON.stringify({
uploaded: document.querySelectorAll('.weui-desktop-upload__thumb, .pic_item, [class*=upload_thumb], [class*="pic_item"], [class*="upload__thumb"]').length,
loading: document.querySelectorAll('[class*="upload_loading"], [class*="uploading"], .weui-desktop-upload__loading').length
})
`,
returnByValue: true, returnByValue: true,
}, { sessionId }); }, { sessionId });
const status = JSON.parse(uploadCheck.result.value); const status = JSON.parse(uploadCheck.result.value);
console.log(`[wechat-browser] Upload progress: ${status.uploaded}/${targetCount}`); console.log(`[wechat-browser] Upload progress: ${status.uploaded}/${targetCount} (loading: ${status.loading})`);
if (status.uploaded >= targetCount) break; if (status.uploaded >= targetCount) break;
} }
+18 -7
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-post-to-weibo name: baoyu-post-to-weibo
description: Posts content to Weibo (微博). Supports regular posts with text, images, and videos, and headline articles (头条文章) with Markdown input via Chrome CDP. Use when user asks to "post to Weibo", "发微博", "发布微博", "publish to Weibo", "share on Weibo", "写微博", or "微博头条文章". description: Posts content to Weibo (微博). Supports regular posts with text, images, and videos, and headline articles (头条文章) with Markdown input via Chrome CDP. Use when user asks to "post to Weibo", "发微博", "发布微博", "publish to Weibo", "share on Weibo", "写微博", or "微博头条文章".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-weibo
requires:
anyBins:
- bun
- npx
--- ---
# Post to Weibo # Post to Weibo
@@ -12,9 +20,9 @@ Posts text, images, videos, and long-form articles to Weibo via real Chrome brow
**Important**: All scripts are located in the `scripts/` subdirectory of this skill. **Important**: All scripts are located in the `scripts/` subdirectory of this skill.
**Agent Execution Instructions**: **Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `SKILL_DIR` 1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts` 2. Script path = `{baseDir}/scripts/<script-name>.ts`
3. Replace all `${SKILL_DIR}` in this document with the actual path 3. Replace all `{baseDir}` in this document with the actual path
4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
**Script Reference**: **Script Reference**:
@@ -32,12 +40,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-post-to-weibo/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-post-to-weibo/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-weibo/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-post-to-weibo/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-post-to-weibo/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-post-to-weibo/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-post-to-weibo/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-post-to-weibo/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-weibo/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-weibo/EXTEND.md") { "user" }
``` ```
@@ -72,8 +83,8 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-weibo/EXTEND.md") { "user" }
Text + images/videos (max 18 files total). Posted on Weibo homepage. Text + images/videos (max 18 files total). Posted on Weibo homepage.
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/weibo-post.ts "Hello Weibo!" --image ./photo.png ${BUN_X} {baseDir}/scripts/weibo-post.ts "Hello Weibo!" --image ./photo.png
${BUN_X} ${SKILL_DIR}/scripts/weibo-post.ts "Watch this" --video ./clip.mp4 ${BUN_X} {baseDir}/scripts/weibo-post.ts "Watch this" --video ./clip.mp4
``` ```
**Parameters**: **Parameters**:
@@ -93,8 +104,8 @@ ${BUN_X} ${SKILL_DIR}/scripts/weibo-post.ts "Watch this" --video ./clip.mp4
Long-form Markdown articles published at `https://card.weibo.com/article/v3/editor`. Long-form Markdown articles published at `https://card.weibo.com/article/v3/editor`.
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/weibo-article.ts article.md ${BUN_X} {baseDir}/scripts/weibo-article.ts article.md
${BUN_X} ${SKILL_DIR}/scripts/weibo-article.ts article.md --cover ./cover.jpg ${BUN_X} {baseDir}/scripts/weibo-article.ts article.md --cover ./cover.jpg
``` ```
**Parameters**: **Parameters**:
@@ -459,7 +459,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
if (charAfter === undefined || !/\\d/.test(charAfter)) { if (charAfter === undefined || !/\\d/.test(charAfter)) {
const parentElement = node.parentElement; const parentElement = node.parentElement;
if (parentElement) { if (parentElement) {
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); parentElement.scrollIntoView({ behavior: 'instant', block: 'center' });
} }
const range = document.createRange(); const range = document.createRange();
@@ -500,112 +500,56 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
return false; return false;
}; };
// Step A: Copy image to clipboard first (slow due to Swift compilation)
console.log(`[weibo-article] Copying image to clipboard: ${path.basename(img.localPath)}`);
if (!copyImageToClipboard(img.localPath)) {
console.warn(`[weibo-article] Failed to copy image to clipboard`);
continue;
}
await sleep(500);
// Step B: Select placeholder text (paste will replace the selection)
const selected = await selectPlaceholder(3); const selected = await selectPlaceholder(3);
if (!selected) { if (!selected) {
console.warn(`[weibo-article] Skipping image - could not select placeholder: ${img.placeholder}`); console.warn(`[weibo-article] Skipping image - could not select placeholder: ${img.placeholder}`);
continue; continue;
} }
console.log(`[weibo-article] Copying image: ${path.basename(img.localPath)}`); // Step C: Delete selected placeholder via Backspace (ProseMirror-compatible)
console.log(`[weibo-article] Deleting placeholder via Backspace...`);
if (!copyImageToClipboard(img.localPath)) { await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
console.warn(`[weibo-article] Failed to copy image to clipboard`); await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
continue; await sleep(500);
}
await sleep(1000);
// Delete placeholder by replacing selection with empty text
console.log(`[weibo-article] Deleting placeholder...`);
await cdp.send('Runtime.evaluate', {
expression: `(() => {
const sel = window.getSelection();
if (!sel || sel.isCollapsed) return false;
const range = sel.getRangeAt(0);
range.deleteContents();
sel.collapseToStart();
return true;
})()`,
returnByValue: true,
}, { sessionId });
await sleep(300);
// Fallback: send Backspace key if placeholder still exists
const stillExists = await cdp!.send<{ result: { value: boolean } }>('Runtime.evaluate', {
expression: `(() => {
const editor = document.querySelector('div[contenteditable="true"]');
if (!editor) return false;
const placeholder = ${JSON.stringify(img.placeholder)};
const regex = new RegExp(placeholder + '(?!\\\\d)');
return regex.test(editor.innerText);
})()`,
returnByValue: true,
}, { sessionId });
if (stillExists.result.value) {
console.log('[weibo-article] Placeholder survived deleteContents, trying Input.insertText replacement...');
// Re-select and replace with empty via Input.insertText
await cdp!.send('Runtime.evaluate', {
expression: `(() => {
const editor = document.querySelector('div[contenteditable="true"]');
if (!editor) return false;
const placeholder = ${JSON.stringify(img.placeholder)};
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, null, false);
let node;
while ((node = walker.nextNode())) {
const text = node.textContent || '';
let searchStart = 0;
let idx;
while ((idx = text.indexOf(placeholder, searchStart)) !== -1) {
const afterIdx = idx + placeholder.length;
const charAfter = text[afterIdx];
if (charAfter === undefined || !/\\d/.test(charAfter)) {
const range = document.createRange();
range.setStart(node, idx);
range.setEnd(node, idx + placeholder.length);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
return true;
}
searchStart = afterIdx;
}
}
return false;
})()`,
}, { sessionId });
await sleep(200);
await cdp!.send('Input.insertText', { text: '' }, { sessionId });
await sleep(300);
}
await sleep(200);
// Verify placeholder was deleted // Verify placeholder was deleted
const afterDelete = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', { const placeholderGone = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
expression: `(() => { expression: `(() => {
const editor = document.querySelector('div[contenteditable="true"]'); const editor = document.querySelector('div[contenteditable="true"]');
if (!editor) return true; if (!editor) return true;
const text = editor.innerText;
const placeholder = ${JSON.stringify(img.placeholder)}; const placeholder = ${JSON.stringify(img.placeholder)};
const regex = new RegExp(placeholder + '(?!\\\\d)'); const regex = new RegExp(placeholder + '(?!\\\\d)');
return !regex.test(text); return !regex.test(editor.innerText);
})()`, })()`,
returnByValue: true, returnByValue: true,
}, { sessionId }); }, { sessionId });
if (afterDelete.result.value) { if (placeholderGone.result.value) {
console.log(`[weibo-article] Placeholder deleted`); console.log(`[weibo-article] Placeholder deleted`);
} else { } else {
console.warn(`[weibo-article] Placeholder may still exist after delete`); console.warn(`[weibo-article] Placeholder may still exist, trying execCommand delete...`);
// Re-select and delete via execCommand
await selectPlaceholder(1);
await cdp.send('Runtime.evaluate', {
expression: `document.execCommand('delete')`,
}, { sessionId });
await sleep(300);
} }
// Focus editor for paste // Step D: Focus editor and paste image
await cdp.send('Runtime.evaluate', { await cdp.send('Runtime.evaluate', {
expression: `document.querySelector('div[contenteditable="true"]')?.focus()`, expression: `document.querySelector('div[contenteditable="true"]')?.focus()`,
}, { sessionId }); }, { sessionId });
await sleep(300); await sleep(200);
// Count images before paste // Count images before paste
const imgCountBefore = await cdp.send<{ result: { value: number } }>('Runtime.evaluate', { const imgCountBefore = await cdp.send<{ result: { value: number } }>('Runtime.evaluate', {
@@ -613,7 +557,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
returnByValue: true, returnByValue: true,
}, { sessionId }); }, { sessionId });
// Paste image // Paste image at cursor position (where placeholder was)
console.log(`[weibo-article] Pasting image...`); console.log(`[weibo-article] Pasting image...`);
if (pasteFromClipboard('Google Chrome', 5, 1000)) { if (pasteFromClipboard('Google Chrome', 5, 1000)) {
console.log(`[weibo-article] Paste keystroke sent for: ${path.basename(img.localPath)}`); console.log(`[weibo-article] Paste keystroke sent for: ${path.basename(img.localPath)}`);
+20 -9
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-post-to-x name: baoyu-post-to-x
description: Posts content and articles to X (Twitter). Supports regular posts with images/videos and X Articles (long-form Markdown). Uses real Chrome with CDP to bypass anti-automation. Use when user asks to "post to X", "tweet", "publish to Twitter", or "share on X". description: Posts content and articles to X (Twitter). Supports regular posts with images/videos and X Articles (long-form Markdown). Uses real Chrome with CDP to bypass anti-automation. Use when user asks to "post to X", "tweet", "publish to Twitter", or "share on X".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-x
requires:
anyBins:
- bun
- npx
--- ---
# Post to X (Twitter) # Post to X (Twitter)
@@ -12,9 +20,9 @@ Posts text, images, videos, and long-form articles to X via real Chrome browser
**Important**: All scripts are located in the `scripts/` subdirectory of this skill. **Important**: All scripts are located in the `scripts/` subdirectory of this skill.
**Agent Execution Instructions**: **Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `SKILL_DIR` 1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts` 2. Script path = `{baseDir}/scripts/<script-name>.ts`
3. Replace all `${SKILL_DIR}` in this document with the actual path 3. Replace all `{baseDir}` in this document with the actual path
4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
**Script Reference**: **Script Reference**:
@@ -36,12 +44,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-post-to-x/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-post-to-x/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-x/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-post-to-x/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-post-to-x/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-post-to-x/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md") { "user" }
``` ```
@@ -74,7 +85,7 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md") { "user" }
Before first use, suggest running the environment check. User can skip if they prefer. Before first use, suggest running the environment check. User can skip if they prefer.
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/check-paste-permissions.ts ${BUN_X} {baseDir}/scripts/check-paste-permissions.ts
``` ```
Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, Chrome conflicts. Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, Chrome conflicts.
@@ -107,7 +118,7 @@ Unless the user explicitly specifies the post type:
## Regular Posts ## Regular Posts
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/x-browser.ts "Hello!" --image ./photo.png ${BUN_X} {baseDir}/scripts/x-browser.ts "Hello!" --image ./photo.png
``` ```
**Parameters**: **Parameters**:
@@ -126,7 +137,7 @@ ${BUN_X} ${SKILL_DIR}/scripts/x-browser.ts "Hello!" --image ./photo.png
Text + video file. Text + video file.
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/x-video.ts "Check this out!" --video ./clip.mp4 ${BUN_X} {baseDir}/scripts/x-video.ts "Check this out!" --video ./clip.mp4
``` ```
**Parameters**: **Parameters**:
@@ -147,7 +158,7 @@ ${BUN_X} ${SKILL_DIR}/scripts/x-video.ts "Check this out!" --video ./clip.mp4
Quote an existing tweet with comment. Quote an existing tweet with comment.
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/x-quote.ts https://x.com/user/status/123 "Great insight!" ${BUN_X} {baseDir}/scripts/x-quote.ts https://x.com/user/status/123 "Great insight!"
``` ```
**Parameters**: **Parameters**:
@@ -166,8 +177,8 @@ ${BUN_X} ${SKILL_DIR}/scripts/x-quote.ts https://x.com/user/status/123 "Great in
Long-form Markdown articles (requires X Premium). Long-form Markdown articles (requires X Premium).
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md ${BUN_X} {baseDir}/scripts/x-article.ts article.md
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg ${BUN_X} {baseDir}/scripts/x-article.ts article.md --cover ./cover.jpg
``` ```
**Parameters**: **Parameters**:
@@ -12,13 +12,13 @@ Publish Markdown articles to X Articles editor with rich text formatting and ima
```bash ```bash
# Publish markdown article (preview mode) # Publish markdown article (preview mode)
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md ${BUN_X} {baseDir}/scripts/x-article.ts article.md
# With custom cover image # With custom cover image
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg ${BUN_X} {baseDir}/scripts/x-article.ts article.md --cover ./cover.jpg
# Actually publish # Actually publish
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --submit ${BUN_X} {baseDir}/scripts/x-article.ts article.md --submit
``` ```
## Markdown Format ## Markdown Format
@@ -76,13 +76,13 @@ Convert markdown and inspect structure:
```bash ```bash
# Get JSON with all metadata # Get JSON with all metadata
${BUN_X} ${SKILL_DIR}/scripts/md-to-html.ts article.md ${BUN_X} {baseDir}/scripts/md-to-html.ts article.md
# Output HTML only # Output HTML only
${BUN_X} ${SKILL_DIR}/scripts/md-to-html.ts article.md --html-only ${BUN_X} {baseDir}/scripts/md-to-html.ts article.md --html-only
# Save HTML to file # Save HTML to file
${BUN_X} ${SKILL_DIR}/scripts/md-to-html.ts article.md --save-html /tmp/article.html ${BUN_X} {baseDir}/scripts/md-to-html.ts article.md --save-html /tmp/article.html
``` ```
JSON output: JSON output:
@@ -161,7 +161,7 @@ Claude:
- **No create button**: Ensure X Premium subscription is active - **No create button**: Ensure X Premium subscription is active
- **Cover upload fails**: Check file path and format (PNG, JPEG) - **Cover upload fails**: Check file path and format (PNG, JPEG)
- **Images not inserting**: Verify placeholders exist in pasted content - **Images not inserting**: Verify placeholders exist in pasted content
- **Content not pasting**: Check HTML clipboard: `${BUN_X} ${SKILL_DIR}/scripts/copy-to-clipboard.ts html --file /tmp/test.html` - **Content not pasting**: Check HTML clipboard: `${BUN_X} {baseDir}/scripts/copy-to-clipboard.ts html --file /tmp/test.html`
## How It Works ## How It Works
@@ -9,20 +9,20 @@ If you prefer step-by-step control:
### Step 1: Copy Image to Clipboard ### Step 1: Copy Image to Clipboard
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/copy-to-clipboard.ts image /path/to/image.png ${BUN_X} {baseDir}/scripts/copy-to-clipboard.ts image /path/to/image.png
``` ```
### Step 2: Paste from Clipboard ### Step 2: Paste from Clipboard
```bash ```bash
# Simple paste to frontmost app # Simple paste to frontmost app
${BUN_X} ${SKILL_DIR}/scripts/paste-from-clipboard.ts ${BUN_X} {baseDir}/scripts/paste-from-clipboard.ts
# Paste to Chrome with retries # Paste to Chrome with retries
${BUN_X} ${SKILL_DIR}/scripts/paste-from-clipboard.ts --app "Google Chrome" --retries 5 ${BUN_X} {baseDir}/scripts/paste-from-clipboard.ts --app "Google Chrome" --retries 5
# Quick paste with shorter delay # Quick paste with shorter delay
${BUN_X} ${SKILL_DIR}/scripts/paste-from-clipboard.ts --delay 200 ${BUN_X} {baseDir}/scripts/paste-from-clipboard.ts --delay 200
``` ```
### Step 3: Use Playwright MCP (if Chrome session available) ### Step 3: Use Playwright MCP (if Chrome session available)
@@ -59,7 +59,7 @@ mcp__playwright__browser_take_screenshot filename="preview.png"
User: /post-to-x "Hello from Claude!" --image ./screenshot.png User: /post-to-x "Hello from Claude!" --image ./screenshot.png
Claude: Claude:
1. Runs: ${BUN_X} ${SKILL_DIR}/scripts/x-browser.ts "Hello from Claude!" --image ./screenshot.png 1. Runs: ${BUN_X} {baseDir}/scripts/x-browser.ts "Hello from Claude!" --image ./screenshot.png
2. Chrome opens with X compose page 2. Chrome opens with X compose page
3. Text is typed into editor 3. Text is typed into editor
4. Image is copied to clipboard and pasted 4. Image is copied to clipboard and pasted
@@ -72,7 +72,7 @@ Claude:
- **Chrome not found**: Set `X_BROWSER_CHROME_PATH` environment variable - **Chrome not found**: Set `X_BROWSER_CHROME_PATH` environment variable
- **Not logged in**: First run opens Chrome - log in manually, cookies are saved - **Not logged in**: First run opens Chrome - log in manually, cookies are saved
- **Image paste fails**: - **Image paste fails**:
- Verify clipboard script: `${BUN_X} ${SKILL_DIR}/scripts/copy-to-clipboard.ts image <path>` - Verify clipboard script: `${BUN_X} {baseDir}/scripts/copy-to-clipboard.ts image <path>`
- On macOS, grant "Accessibility" permission to Terminal/iTerm in System Settings > Privacy & Security > Accessibility - On macOS, grant "Accessibility" permission to Terminal/iTerm in System Settings > Privacy & Security > Accessibility
- Keep Chrome window visible and in front during paste operations - Keep Chrome window visible and in front during paste operations
- **osascript permission denied**: Grant Terminal accessibility permissions in System Preferences - **osascript permission denied**: Grant Terminal accessibility permissions in System Preferences
+15 -4
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-slide-deck name: baoyu-slide-deck
description: Generates professional slide deck images from content. Creates outlines with style instructions, then generates individual slide images. Use when user asks to "create slides", "make a presentation", "generate deck", "slide deck", or "PPT". description: Generates professional slide deck images from content. Creates outlines with style instructions, then generates individual slide images. Use when user asks to "create slides", "make a presentation", "generate deck", "slide deck", or "PPT".
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-slide-deck
requires:
anyBins:
- bun
- npx
--- ---
# Slide Deck Generator # Slide Deck Generator
@@ -22,8 +30,8 @@ Transform content into professional slide deck images.
## Script Directory ## Script Directory
**Agent Execution Instructions**: **Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `SKILL_DIR` 1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts` 2. Script path = `{baseDir}/scripts/<script-name>.ts`
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
| Script | Purpose | | Script | Purpose |
@@ -195,12 +203,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-slide-deck/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-slide-deck/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-slide-deck/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-slide-deck/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-slide-deck/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-slide-deck/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-slide-deck/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-slide-deck/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-slide-deck/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-slide-deck/EXTEND.md") { "user" }
``` ```
@@ -555,8 +566,8 @@ options:
### Step 8: Merge to PPTX and PDF ### Step 8: Merge to PPTX and PDF
```bash ```bash
${BUN_X} ${SKILL_DIR}/scripts/merge-to-pptx.ts <slide-deck-dir> ${BUN_X} {baseDir}/scripts/merge-to-pptx.ts <slide-deck-dir>
${BUN_X} ${SKILL_DIR}/scripts/merge-to-pdf.ts <slide-deck-dir> ${BUN_X} {baseDir}/scripts/merge-to-pdf.ts <slide-deck-dir>
``` ```
### Step 9: Output Summary ### Step 9: Output Summary
+13 -2
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-translate name: baoyu-translate
description: Translates articles and documents between languages with three modes - quick (direct), normal (analyze then translate), and refined (analyze, translate, review, polish). Supports custom glossaries and terminology consistency via EXTEND.md. Use when user asks to "translate", "翻译", "精翻", "translate article", "translate to Chinese/English", "改成中文", "改成英文", "convert to Chinese", "localize", "本地化", or needs any document translation. Also triggers for "refined translation", "精细翻译", "proofread translation", "快速翻译", "快翻", "这篇文章翻译一下", or when a URL or file is provided with translation intent. description: Translates articles and documents between languages with three modes - quick (direct), normal (analyze then translate), and refined (analyze, translate, review, polish). Supports custom glossaries and terminology consistency via EXTEND.md. Use when user asks to "translate", "翻译", "精翻", "translate article", "translate to Chinese/English", "改成中文", "改成英文", "convert to Chinese", "localize", "本地化", or needs any document translation. Also triggers for "refined translation", "精细翻译", "proofread translation", "快速翻译", "快翻", "这篇文章翻译一下", or when a URL or file is provided with translation intent.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-translate
requires:
anyBins:
- bun
- npx
--- ---
# Translator # Translator
@@ -9,7 +17,7 @@ Three-mode translation skill: **quick** for direct translation, **normal** for a
## Script Directory ## Script Directory
Scripts in `scripts/` subdirectory. `${SKILL_DIR}` = this SKILL.md's directory path. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `${SKILL_DIR}` and `${BUN_X}` with actual values. Scripts in `scripts/` subdirectory. `{baseDir}` = this SKILL.md's directory path. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun. Replace `{baseDir}` and `${BUN_X}` with actual values.
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
@@ -22,12 +30,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-translate/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-translate/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-translate/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-translate/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-translate/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-translate/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md") { "user" }
``` ```
@@ -172,7 +183,7 @@ Before translating chunks:
1. **Extract terminology**: Scan entire document for proper nouns, technical terms, recurring phrases 1. **Extract terminology**: Scan entire document for proper nouns, technical terms, recurring phrases
2. **Build session glossary**: Merge extracted terms with loaded glossaries, establish consistent translations 2. **Build session glossary**: Merge extracted terms with loaded glossaries, establish consistent translations
3. **Split into chunks**: Use `${BUN_X} ${SKILL_DIR}/scripts/chunk.ts <file> [--max-words <chunk_max_words>] [--output-dir <output-dir>]` 3. **Split into chunks**: Use `${BUN_X} {baseDir}/scripts/chunk.ts <file> [--max-words <chunk_max_words>] [--output-dir <output-dir>]`
- Parses markdown AST (headings, paragraphs, lists, code blocks, tables, etc.) - Parses markdown AST (headings, paragraphs, lists, code blocks, tables, etc.)
- Splits at markdown block boundaries to preserve structure - Splits at markdown block boundaries to preserve structure
- If a single block exceeds the threshold, falls back to line splitting, then word splitting - If a single block exceeds the threshold, falls back to line splitting, then word splitting
+19 -8
View File
@@ -1,6 +1,14 @@
--- ---
name: baoyu-url-to-markdown name: baoyu-url-to-markdown
description: Fetch any URL and convert to markdown using Chrome CDP. Saves the rendered HTML snapshot alongside the markdown, and automatically falls back to the pre-Defuddle HTML-to-Markdown pipeline when Defuddle fails. Supports two modes - auto-capture on page load, or wait for user signal (for pages requiring login). Use when user wants to save a webpage as markdown. description: Fetch any URL and convert to markdown using Chrome CDP. Saves the rendered HTML snapshot alongside the markdown, and automatically falls back to the pre-Defuddle HTML-to-Markdown pipeline when Defuddle fails. Supports two modes - auto-capture on page load, or wait for user signal (for pages requiring login). Use when user wants to save a webpage as markdown.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-url-to-markdown
requires:
anyBins:
- bun
- npx
--- ---
# URL to Markdown # URL to Markdown
@@ -12,10 +20,10 @@ Fetches any URL via Chrome CDP, saves the rendered HTML snapshot, and converts i
**Important**: All scripts are located in the `scripts/` subdirectory of this skill. **Important**: All scripts are located in the `scripts/` subdirectory of this skill.
**Agent Execution Instructions**: **Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `SKILL_DIR` 1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts` 2. Script path = `{baseDir}/scripts/<script-name>.ts`
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
4. Replace all `${SKILL_DIR}` and `${BUN_X}` in this document with actual values 4. Replace all `{baseDir}` and `${BUN_X}` in this document with actual values
**Script Reference**: **Script Reference**:
| Script | Purpose | | Script | Purpose |
@@ -30,12 +38,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-url-to-markdown/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-url-to-markdown/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-url-to-markdown/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-url-to-markdown/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-url-to-markdown/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-url-to-markdown/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-url-to-markdown/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-url-to-markdown/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-url-to-markdown/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-url-to-markdown/EXTEND.md") { "user" }
``` ```
@@ -112,19 +123,19 @@ Full reference: [references/config/first-time-setup.md](references/config/first-
```bash ```bash
# Auto mode (default) - capture when page loads # Auto mode (default) - capture when page loads
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> ${BUN_X} {baseDir}/scripts/main.ts <url>
# Wait mode - wait for user signal before capture # Wait mode - wait for user signal before capture
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --wait ${BUN_X} {baseDir}/scripts/main.ts <url> --wait
# Save to specific file # Save to specific file
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> -o output.md ${BUN_X} {baseDir}/scripts/main.ts <url> -o output.md
# Save to a custom output directory (auto-generates filename) # Save to a custom output directory (auto-generates filename)
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --output-dir ./posts/ ${BUN_X} {baseDir}/scripts/main.ts <url> --output-dir ./posts/
# Download images and videos to local directories # Download images and videos to local directories
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --download-media ${BUN_X} {baseDir}/scripts/main.ts <url> --download-media
``` ```
## Options ## Options
+86 -62
View File
@@ -1,6 +1,10 @@
--- ---
name: baoyu-xhs-images name: baoyu-xhs-images
description: Generates Xiaohongshu (Little Red Book) infographic series with 11 visual styles and 8 layouts. Breaks content into 1-10 cartoon-style images optimized for XHS engagement. Use when user mentions "小红书图片", "XHS images", "RedNote infographics", "小红书种草", or wants social media infographics for Chinese platforms. description: Generates Xiaohongshu (Little Red Book) infographic series with 11 visual styles and 8 layouts. Breaks content into 1-10 cartoon-style images optimized for XHS engagement. Use when user mentions "小红书图片", "XHS images", "RedNote infographics", "小红书种草", or wants social media infographics for Chinese platforms.
version: 1.56.1
metadata:
openclaw:
homepage: https://github.com/JimLiu/baoyu-skills#baoyu-xhs-images
--- ---
# Xiaohongshu Infographic Series Generator # Xiaohongshu Infographic Series Generator
@@ -76,7 +80,7 @@ Detailed style definitions: `references/presets/<style>.md`
## Preset Gallery ## Preset Gallery
Quick-start presets by content scenario. Use `--preset <name>` or recommend during Step 4. Quick-start presets by content scenario. Use `--preset <name>` or recommend during Step 2.
**Knowledge & Learning**: **Knowledge & Learning**:
@@ -237,11 +241,12 @@ XHS Infographic Progress:
- [ ] Found → load preferences → continue - [ ] Found → load preferences → continue
- [ ] Not found → run first-time setup → MUST complete before Step 1 - [ ] Not found → run first-time setup → MUST complete before Step 1
- [ ] Step 1: Analyze content → analysis.md - [ ] Step 1: Analyze content → analysis.md
- [ ] Step 2: Confirmation 1 - Content understanding ⚠️ REQUIRED - [ ] Step 2: Smart Confirm ⚠️ REQUIRED
- [ ] Step 3: Generate 3 outline + style variants - [ ] Path A: Quick confirm → generate recommended outline
- [ ] Step 4: Confirmation 2 - Outline & style & elements selection ⚠️ REQUIRED - [ ] Path B: Customize → adjust then generate outline
- [ ] Step 5: Generate images (sequential) - [ ] Path C: Detailed → 3 outlines → second confirm → generate outline
- [ ] Step 6: Completion report - [ ] Step 3: Generate images (sequential)
- [ ] Step 4: Completion report
``` ```
### Flow ### Flow
@@ -255,7 +260,11 @@ Input → [Step 0: Preferences] ─┬─ Found → Continue
┌───────────────────────────────────────────────────────────────────────────┘ ┌───────────────────────────────────────────────────────────────────────────┘
Analyze → [Confirm 1] → 3 Outlines → [Confirm 2: Outline + Style + Elements] → Generate → Complete Analyze → [Smart Confirm] ─┬─ Quick: confirm recommended → outline.md → Generate → Complete
├─ Customize: adjust options → outline.md → Generate → Complete
└─ Detailed: 3 outlines → [Confirm 2] → outline.md → Generate → Complete
``` ```
### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING ### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING
@@ -269,12 +278,15 @@ Check EXTEND.md existence (priority order):
```bash ```bash
# macOS, Linux, WSL, Git Bash # macOS, Linux, WSL, Git Bash
test -f .baoyu-skills/baoyu-xhs-images/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-xhs-images/EXTEND.md && echo "project"
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-xhs-images/EXTEND.md" && echo "xdg"
test -f "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md" && echo "user" test -f "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md" && echo "user"
``` ```
```powershell ```powershell
# PowerShell (Windows) # PowerShell (Windows)
if (Test-Path .baoyu-skills/baoyu-xhs-images/EXTEND.md) { "project" } if (Test-Path .baoyu-skills/baoyu-xhs-images/EXTEND.md) { "project" }
$xdg = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { "$HOME/.config" }
if (Test-Path "$xdg/baoyu-skills/baoyu-xhs-images/EXTEND.md") { "xdg" }
if (Test-Path "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md") { "user" } if (Test-Path "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md") { "user" }
``` ```
@@ -323,18 +335,63 @@ Read source content, save it if needed, and perform deep analysis.
- Swipe flow design - Swipe flow design
4. Detect source language 4. Detect source language
5. Determine recommended image count (2-10) 5. Determine recommended image count (2-10)
6. **Generate clarifying questions** (see Step 2) 6. **Auto-recommend** best strategy + style + layout based on content signals
7. **Save to `analysis.md`** 7. **Save to `analysis.md`**
### Step 2: Confirmation 1 - Content Understanding ⚠️ ### Step 2: Smart Confirm ⚠️
**Purpose**: Validate understanding + collect missing info. **Do NOT skip.** **Purpose**: Present auto-recommended plan, let user confirm or adjust. **Do NOT skip.**
**Display summary**: **Auto-Recommendation Logic**:
- Content type + topic identified 1. Use Auto Selection table to match content signals → best strategy + style + layout
- Key points extracted 2. Infer optimal image count from content density
- Tone detected 3. Load style's default elements from preset
- Source images count
**Display** (analysis summary + recommended plan):
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 内容分析
主题:[topic] | 类型:[content_type]
要点:[key points summary]
受众:[target audience]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎨 推荐方案(自动匹配)
策略:[A/B/C] [strategy name][reason]
风格:[style] · 布局:[layout] · 预设:[preset]
图片:[N]张(封面+[N-2]内容+结尾)
元素:[background] / [decorations] / [emphasis]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
**Use AskUserQuestion** with single question:
| Option | Description |
|--------|-------------|
| 1. ✅ 确认,直接生成(推荐) | Trust auto-recommendation, proceed immediately |
| 2. 🎛️ 自定义调整 | Modify strategy/style/layout/count in one step |
| 3. 📋 详细模式 | Generate 3 outlines, then choose (two confirmations) |
#### Path A: Quick Confirm (Option 1)
Generate single outline using recommended strategy + style → save to `outline.md` → Step 3.
#### Path B: Customize (Option 2)
**Use AskUserQuestion** with adjustable options (leave blank = keep recommended):
1. **策略风格**: Current: [strategy + style]. Options: A Story-Driven(warm) | B Information-Dense(notion) | C Visual-First(screen-print). Or specify style directly: cute/fresh/warm/bold/minimal/retro/pop/notion/chalkboard/study-notes/screen-print. Or use preset: knowledge-card / checklist / tutorial / poster / cinematic / etc.
2. **布局**: Current: [layout]. Options: sparse | balanced | dense | list | comparison | flow | mindmap | quadrant
3. **图片数量**: Current: [N]. Range: 2-10
4. **补充说明**(可选): Selling point emphasis, audience adjustment, color preference, etc.
**After response**: Generate single outline with user's choices → save to `outline.md` → Step 3.
#### Path C: Detailed Mode (Option 3)
Full two-confirmation flow for maximum control:
**Step 2a: Content Understanding**
**Use AskUserQuestion** for: **Use AskUserQuestion** for:
1. Core selling point (multiSelect: true) 1. Core selling point (multiSelect: true)
@@ -342,13 +399,9 @@ Read source content, save it if needed, and perform deep analysis.
3. Style preference: Authentic sharing / Professional review / Aesthetic mood / Auto 3. Style preference: Authentic sharing / Professional review / Aesthetic mood / Auto
4. Additional context (optional) 4. Additional context (optional)
**After response**: Update `analysis.md` → Step 3 **After response**: Update `analysis.md`.
### Step 3: Generate 3 Outline + Style Variants **Step 2b: Generate 3 Outline Variants**
Based on analysis + user context, create three distinct strategy variants. Each variant includes both **outline structure** and **visual style recommendation**.
**For each strategy**:
| Strategy | Filename | Outline | Recommended Style | | Strategy | Filename | Outline | Recommended Style |
|----------|----------|---------|-------------------| |----------|----------|---------|-------------------|
@@ -363,7 +416,7 @@ strategy: a # a, b, or c
name: Story-Driven name: Story-Driven
style: warm # recommended style for this strategy style: warm # recommended style for this strategy
style_reason: "Warm tones enhance emotional storytelling and personal connection" style_reason: "Warm tones enhance emotional storytelling and personal connection"
elements: # from style preset, can be customized in Step 4 elements: # from style preset, can be customized
background: solid-pastel background: solid-pastel
decorations: [clouds, stars-sparkles] decorations: [clouds, stars-sparkles]
emphasis: star-burst emphasis: star-burst
@@ -391,50 +444,22 @@ image_count: 5
- Each strategy MUST have different outline structure AND different recommended style - Each strategy MUST have different outline structure AND different recommended style
- Adapt page count: A typically 4-6, B typically 3-5, C typically 3-4 - Adapt page count: A typically 4-6, B typically 3-5, C typically 3-4
- Include `style_reason` explaining why this style fits the strategy - Include `style_reason` explaining why this style fits the strategy
- Consider user's style preference from Step 2
Reference: `references/workflows/outline-template.md` Reference: `references/workflows/outline-template.md`
### Step 4: Confirmation 2 - Outline & Style & Elements Selection ⚠️ **Step 2c: Outline & Style Selection**
**Purpose**: User chooses outline strategy, confirms visual style, and customizes elements. **Do NOT skip.**
**Display each strategy**:
- Strategy name + page count + recommended style
- Page-by-page summary (P1 → P2 → P3...)
**Use AskUserQuestion** with three questions: **Use AskUserQuestion** with three questions:
**Question 1: Outline Strategy** **Q1: Outline Strategy**: A / B / C / Combine (specify pages from each)
- Strategy A (Recommended if "authentic sharing")
- Strategy B (Recommended if "professional review")
- Strategy C (Recommended if "aesthetic mood")
- Combine: specify pages from each
**Question 2: Visual Style** **Q2: Visual Style**: Use recommended | Select preset | Select style | Custom description
- Use strategy's recommended style (show which style)
- Or use a preset: knowledge-card / checklist / tutorial / poster / cinematic / etc. (see [Style Presets](references/style-presets.md))
- Or select from: cute / fresh / warm / bold / minimal / retro / pop / notion / chalkboard / screen-print
- Or type custom style description
**Question 3: Visual Elements** (show after style selection) **Q3: Visual Elements**: Use defaults (Recommended) | Adjust background | Adjust decorations | Custom
Display the selected style's default elements from preset, then ask:
- Use style defaults (Recommended) - show preview: background, decorations, emphasis
- Adjust background - options: solid-pastel / solid-saturated / gradient-linear / gradient-radial / paper-texture / grid
- Adjust decorations - options: hearts / stars-sparkles / flowers / clouds / leaves / confetti
- Type custom element preferences
**After response**: **After response**: Save selected/merged outline to `outline.md` with confirmed style and elements → Step 3.
- Single strategy → copy to `outline.md` with confirmed style
- Combination → merge specified pages with confirmed style
- Custom request → regenerate based on feedback
- Style defaults → use preset's Element Combination as-is
- Background adjustment → update elements.background with user choice
- Decorations adjustment → update elements.decorations with user choice
- Custom elements → parse user's preferences into elements fields
- Update `outline.md` frontmatter with final style and elements
### Step 5: Generate Images ### Step 3: Generate Images
With confirmed outline + style + layout: With confirmed outline + style + layout:
@@ -474,12 +499,13 @@ If image generation skill supports `--sessionId`:
2. Use same session ID for all images 2. Use same session ID for all images
3. Combined with reference image chain, ensures maximum visual consistency 3. Combined with reference image chain, ensures maximum visual consistency
### Step 6: Completion Report ### Step 4: Completion Report
``` ```
Xiaohongshu Infographic Series Complete! Xiaohongshu Infographic Series Complete!
Topic: [topic] Topic: [topic]
Mode: [Quick / Custom / Detailed]
Strategy: [A/B/C/Combined] Strategy: [A/B/C/Combined]
Style: [style name] Style: [style name]
Layout: [layout name or "varies"] Layout: [layout name or "varies"]
@@ -487,10 +513,8 @@ Location: [directory path]
Images: N total Images: N total
✓ analysis.md ✓ analysis.md
✓ outline-strategy-a.md ✓ outline.md
✓ outline-strategy-b.md ✓ outline-strategy-a/b/c.md (detailed mode only)
✓ outline-strategy-c.md
✓ outline.md (selected: [strategy])
Files: Files:
- 01-cover-[slug].png ✓ Cover (sparse) - 01-cover-[slug].png ✓ Cover (sparse)
@@ -559,7 +583,7 @@ Detailed templates in `references/` directory:
- Auto-retry once on failure | Cartoon alternatives for sensitive figures - Auto-retry once on failure | Cartoon alternatives for sensitive figures
- Use confirmed language preference | Maintain style consistency - Use confirmed language preference | Maintain style consistency
- **Two confirmation points required** (Steps 2 & 4) - do not skip - **Smart Confirm required** (Step 2) - do not skip; detailed mode uses two sub-confirmations
## Extension Support ## Extension Support
@@ -195,4 +195,4 @@ Before proceeding to outline generation:
- [ ] Have I identified save/share triggers? - [ ] Have I identified save/share triggers?
- [ ] Are there clear visual opportunities? - [ ] Are there clear visual opportunities?
- [ ] Is the swipe flow planned? - [ ] Is the swipe flow planned?
- [ ] Have I selected 3 style+layout combinations? - [ ] Have I identified the best style+layout recommendation?
@@ -211,13 +211,9 @@ If preferences include watermark:
When generating multiple images in a series: When generating multiple images in a series:
1. **Image 1 (cover)**: Generate without `--ref` — this establishes the visual anchor 1. **Image 1 (cover)**: Generate without `--ref` — this establishes the visual anchor
2. **Images 2+**: Always pass image 1 as `--ref` to the image generation skill: 2. **Images 2+**: Always pass image 1 as `--ref` to the installed image generation skill.
```bash Read that skill's `SKILL.md` and use its documented interface rather than calling its scripts directly.
${BUN_X} ${SKILL_DIR}/scripts/main.ts \ For each later image, use the assembled prompt file as input, set the output image path, keep aspect ratio `3:4`, use quality `2k`, and pass image 1 as the reference.
--promptfiles prompts/02-content-xxx.md \
--ref path/to/01-cover-xxx.png \
--image 02-content-xxx.png --ar 3:4 --quality 2k
```
This ensures the AI maintains the same character design, illustration style, and color rendering across the series. This ensures the AI maintains the same character design, illustration style, and color rendering across the series.
### Step 6: Combine ### Step 6: Combine