mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-10 21:21:30 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f76a96741 | |||
| 67e3e11cce | |||
| 5b4ba3ac3f | |||
| ce259e4547 | |||
| fff1a54b6b | |||
| 9437581c48 | |||
| bd4db203f8 | |||
| 51387498a5 | |||
| 6d1336d8bd | |||
| 42931d6294 |
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||
"version": "1.44.0"
|
||||
"version": "1.47.0"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
@@ -45,7 +45,8 @@
|
||||
"./skills/baoyu-compress-image",
|
||||
"./skills/baoyu-url-to-markdown",
|
||||
"./skills/baoyu-format-markdown",
|
||||
"./skills/baoyu-markdown-to-html"
|
||||
"./skills/baoyu-markdown-to-html",
|
||||
"./skills/baoyu-translate"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -152,6 +152,7 @@ slide-deck/
|
||||
infographic/
|
||||
illustrations/
|
||||
comic/
|
||||
translate/
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
|
||||
@@ -2,6 +2,29 @@
|
||||
|
||||
English | [中文](./CHANGELOG.zh.md)
|
||||
|
||||
## 1.47.0 - 2026-03-05
|
||||
|
||||
### Features
|
||||
- Add `baoyu-translate` skill — three-mode translation (quick/normal/refined) with custom glossaries, audience-aware translation, and parallel chunked translation for long documents
|
||||
- Add cross-platform PowerShell support for EXTEND.md preference checks across all skills
|
||||
|
||||
## 1.46.0 - 2026-03-05
|
||||
|
||||
### Features
|
||||
- Add `--output-dir` option to url-to-markdown for custom output directory with auto-generated filenames
|
||||
|
||||
## 1.45.1 - 2026-03-05
|
||||
|
||||
### Refactor
|
||||
- Replace hardcoded `npx -y bun` with `${BUN_X}` runtime variable across all skills — prefers native `bun`, falls back to `npx -y bun`
|
||||
- Add Runtime Detection section to CLAUDE.md and Script Directory instructions in all SKILL.md files
|
||||
|
||||
## 1.45.0 - 2026-03-05
|
||||
|
||||
### Features
|
||||
- `baoyu-post-to-x`: add post-composition verification for X Articles — automatically checks remaining placeholders and image count after all images are inserted
|
||||
- `baoyu-post-to-x`: increase CDP timeout to 60s and add 3s DOM stabilization delay between image insertions for long articles
|
||||
|
||||
## 1.44.0 - 2026-03-05
|
||||
|
||||
### Features
|
||||
|
||||
@@ -2,6 +2,29 @@
|
||||
|
||||
[English](./CHANGELOG.md) | 中文
|
||||
|
||||
## 1.47.0 - 2026-03-05
|
||||
|
||||
### 新功能
|
||||
- 新增 `baoyu-translate` 翻译技能——支持快速/标准/精翻三种模式,自定义术语表、面向受众翻译、长文档自动分块并行翻译
|
||||
- 为所有技能的 EXTEND.md 偏好检测添加 PowerShell 跨平台支持
|
||||
|
||||
## 1.46.0 - 2026-03-05
|
||||
|
||||
### 新功能
|
||||
- 为 url-to-markdown 新增 `--output-dir` 选项,支持自定义输出目录并自动生成文件名
|
||||
|
||||
## 1.45.1 - 2026-03-05
|
||||
|
||||
### 重构
|
||||
- 将所有技能中硬编码的 `npx -y bun` 替换为 `${BUN_X}` 运行时变量——优先使用原生 `bun`,回退到 `npx -y bun`
|
||||
- 在 CLAUDE.md 中新增运行时检测章节,在所有 SKILL.md 的脚本目录说明中添加运行时解析步骤
|
||||
|
||||
## 1.45.0 - 2026-03-05
|
||||
|
||||
### 新功能
|
||||
- `baoyu-post-to-x`:X 文章发布后自动验证——检查残留占位符和图片数量是否正确
|
||||
- `baoyu-post-to-x`:增加 CDP 超时至 60 秒,图片插入间隔增加 3 秒 DOM 稳定等待,改善长文章发布稳定性
|
||||
|
||||
## 1.44.0 - 2026-03-05
|
||||
|
||||
### 新功能
|
||||
|
||||
@@ -43,27 +43,51 @@ Each skill contains:
|
||||
|
||||
## Running Skills
|
||||
|
||||
All scripts run via Bun (no build step):
|
||||
All scripts are TypeScript, executed via Bun runtime (no build step).
|
||||
|
||||
### Runtime Detection (`${BUN_X}`)
|
||||
|
||||
Before running any script, the agent MUST detect the runtime **once per session** and set `${BUN_X}`:
|
||||
|
||||
```bash
|
||||
npx -y bun skills/<skill>/scripts/main.ts [options]
|
||||
# Detect runtime (run once, reuse result)
|
||||
if command -v bun &>/dev/null; then
|
||||
BUN_X="bun"
|
||||
elif command -v npx &>/dev/null; then
|
||||
BUN_X="npx -y bun"
|
||||
else
|
||||
echo "Error: Neither bun nor npx found. Install bun: curl -fsSL https://bun.sh/install | bash"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
| Priority | Condition | `${BUN_X}` value | Notes |
|
||||
|----------|-----------|-------------------|-------|
|
||||
| 1 | `bun` installed | `bun` | Fastest, native execution |
|
||||
| 2 | `npx` available | `npx -y bun` | Downloads bun on first run via npm |
|
||||
| 3 | Neither found | Error + install guide | Suggest: `curl -fsSL https://bun.sh/install \| bash` |
|
||||
|
||||
### Script Execution
|
||||
|
||||
```bash
|
||||
${BUN_X} skills/<skill>/scripts/main.ts [options]
|
||||
```
|
||||
|
||||
Examples:
|
||||
```bash
|
||||
# Text generation
|
||||
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts "Hello"
|
||||
${BUN_X} skills/baoyu-danger-gemini-web/scripts/main.ts "Hello"
|
||||
|
||||
# Image generation
|
||||
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts --prompt "A cat" --image cat.png
|
||||
${BUN_X} skills/baoyu-danger-gemini-web/scripts/main.ts --prompt "A cat" --image cat.png
|
||||
|
||||
# From prompt files
|
||||
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
${BUN_X} skills/baoyu-danger-gemini-web/scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
```
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
- **Bun**: TypeScript runtime (via `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
|
||||
- **No npm packages**: Self-contained TypeScript, no external dependencies
|
||||
|
||||
@@ -176,7 +200,8 @@ Every SKILL.md with scripts MUST include this section after Usage:
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
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
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
@@ -185,7 +210,7 @@ Every SKILL.md with scripts MUST include this section after Usage:
|
||||
| `scripts/other.ts` | Other functionality |
|
||||
```
|
||||
|
||||
When referencing scripts in workflow sections, use `${SKILL_DIR}/scripts/<name>.ts` so agents can resolve the correct path.
|
||||
When referencing scripts in workflow sections, use `${BUN_X} ${SKILL_DIR}/scripts/<name>.ts` so agents can resolve the correct runtime and path.
|
||||
|
||||
### Progressive Disclosure
|
||||
|
||||
@@ -320,13 +345,13 @@ When adding, updating, or deleting styles for `baoyu-comic`, follow this workflo
|
||||
- Add auto-selection entry if applicable
|
||||
3. **Generate showcase image**:
|
||||
```bash
|
||||
npx -y bun skills/baoyu-danger-gemini-web/scripts/main.ts \
|
||||
${BUN_X} skills/baoyu-danger-gemini-web/scripts/main.ts \
|
||||
--prompt "A single comic book page in <style-name> style showing [appropriate scene]. Features: [style characteristics from style definition]. 3:4 portrait aspect ratio comic page." \
|
||||
--image screenshots/comic-styles/<style-name>.png
|
||||
```
|
||||
4. **Compress to WebP**:
|
||||
```bash
|
||||
npx -y bun skills/baoyu-compress-image/scripts/main.ts screenshots/comic-styles/<style-name>.png
|
||||
${BUN_X} skills/baoyu-compress-image/scripts/main.ts screenshots/comic-styles/<style-name>.png
|
||||
```
|
||||
5. **Update both READMEs** (`README.md` and `README.zh.md`):
|
||||
- Add style to `--style` options
|
||||
@@ -374,16 +399,20 @@ For skills with workflows, add as Step 1.1. For utility skills, add as "Preferen
|
||||
```markdown
|
||||
**1.1 Load Preferences (EXTEND.md)**
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
\`\`\`bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/<skill-name>/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/<skill-name>/EXTEND.md" && echo "user"
|
||||
\`\`\`
|
||||
|
||||
\`\`\`powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/<skill-name>/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/<skill-name>/EXTEND.md") { "user" }
|
||||
\`\`\`
|
||||
|
||||
┌────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -425,6 +454,6 @@ Custom configurations via EXTEND.md. See **Preferences** section for paths and s
|
||||
|
||||
**Notes**:
|
||||
- Replace `<skill-name>` with actual skill name (e.g., `baoyu-cover-image`)
|
||||
- Use `$HOME` instead of `~` for cross-platform compatibility (macOS/Linux/WSL)
|
||||
- Use `test -f` Bash command for explicit file existence check
|
||||
- Use `$HOME` instead of `~` for cross-platform compatibility (macOS/Linux/WSL/PowerShell)
|
||||
- Use `test -f` (Bash) or `Test-Path` (PowerShell) for explicit file existence check
|
||||
- ASCII tables for clear visual formatting
|
||||
|
||||
@@ -55,7 +55,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) |
|
||||
| **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) |
|
||||
| **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) |
|
||||
|
||||
## Update Skills
|
||||
|
||||
@@ -739,6 +739,30 @@ Format plain text or markdown files with proper frontmatter, titles, summaries,
|
||||
| Code/commands | `` `inline` `` or ` ```block``` ` |
|
||||
| Quotes | `>` blockquote |
|
||||
|
||||
#### baoyu-translate
|
||||
|
||||
Translate articles and documents between languages with three modes: quick (direct), normal (analysis-informed), and refined (full publication-quality workflow).
|
||||
|
||||
```bash
|
||||
# Normal mode (default) - analyze then translate
|
||||
/translate article.md --to zh-CN
|
||||
|
||||
# Quick mode - direct translation
|
||||
/translate article.md --mode quick --to ja
|
||||
|
||||
# Refined mode - full workflow with review and polish
|
||||
/translate article.md --mode refined --to zh-CN
|
||||
```
|
||||
|
||||
**Modes**:
|
||||
| Mode | Steps | Use Case |
|
||||
|------|-------|----------|
|
||||
| Quick | Translate | Short texts, informal content |
|
||||
| Normal | Analyze → Translate | Articles, blog posts |
|
||||
| Refined | Analyze → Translate → Review → Polish | Publication-quality documents |
|
||||
|
||||
**Features**: Custom glossaries via EXTEND.md, audience-aware translation (general/technical/academic/business), automatic chunking for long documents with parallel subagent translation.
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
Some skills require API keys or custom configuration. Environment variables can be set in `.env` files:
|
||||
|
||||
+25
-1
@@ -55,7 +55,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) |
|
||||
| **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) |
|
||||
| **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) |
|
||||
|
||||
## 更新技能
|
||||
|
||||
@@ -739,6 +739,30 @@ AI 驱动的生成后端。
|
||||
| 代码/命令 | `` `行内` `` 或 ` ```代码块``` ` |
|
||||
| 引用 | `>` 引用块 |
|
||||
|
||||
#### baoyu-translate
|
||||
|
||||
三模式翻译技能:快速(直接翻译)、标准(分析后翻译)、精翻(完整出版级工作流,含审校与润色)。
|
||||
|
||||
```bash
|
||||
# 标准模式(默认)- 先分析再翻译
|
||||
/translate article.md --to zh-CN
|
||||
|
||||
# 快速模式 - 直接翻译
|
||||
/translate article.md --mode quick --to ja
|
||||
|
||||
# 精翻模式 - 完整工作流,含审校与润色
|
||||
/translate article.md --mode refined --to zh-CN
|
||||
```
|
||||
|
||||
**模式**:
|
||||
| 模式 | 步骤 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| 快速 | 翻译 | 短文本、非正式内容 |
|
||||
| 标准 | 分析 → 翻译 | 文章、博客 |
|
||||
| 精翻 | 分析 → 翻译 → 审校 → 润色 | 出版级文档 |
|
||||
|
||||
**特性**:通过 EXTEND.md 自定义术语表、面向受众的翻译(通用/技术/学术/商务)、长文档自动分块并行翻译。
|
||||
|
||||
## 环境配置
|
||||
|
||||
部分技能需要 API 密钥或自定义配置。环境变量可以在 `.env` 文件中设置:
|
||||
|
||||
@@ -47,10 +47,17 @@ See [references/styles.md](references/styles.md) for Core Styles, full gallery,
|
||||
**1.5 Load Preferences (EXTEND.md) ⛔ BLOCKING**
|
||||
|
||||
```bash
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project"
|
||||
test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-article-illustrator/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
| Result | Action |
|
||||
|--------|--------|
|
||||
| Found | Read, parse, display summary |
|
||||
|
||||
@@ -86,10 +86,17 @@ Check preferences and existing state, then ask ALL needed questions in ONE AskUs
|
||||
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to reference images, do NOT ask about content, do NOT ask about type/style — ONLY complete the preferences setup first.
|
||||
|
||||
```bash
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project"
|
||||
test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-article-illustrator/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
| Result | Action |
|
||||
|--------|--------|
|
||||
| Found | Read, parse, display summary → Continue |
|
||||
|
||||
@@ -107,6 +107,7 @@ Details: [references/auto-selection.md](references/auto-selection.md)
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` 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
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
@@ -209,7 +210,7 @@ Analyze → [Check Existing?] → [Confirm: Style + Reviews] → Storyboard →
|
||||
- **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png`
|
||||
```bash
|
||||
# Use Reference Sheet Prompt from characters/characters.md
|
||||
npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
|
||||
${BUN_X} ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
|
||||
--promptfiles characters/characters.md \
|
||||
--image characters/characters.png --ar 4:3
|
||||
```
|
||||
@@ -233,7 +234,7 @@ Compress to reduce token usage when used as reference image:
|
||||
|
||||
```bash
|
||||
# Example: ALWAYS include --ref for consistency
|
||||
npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
|
||||
${BUN_X} ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
|
||||
--promptfiles prompts/01-page-xxx.md \
|
||||
--image 01-page-xxx.png --ar 3:4 \
|
||||
--ref characters/characters.png
|
||||
|
||||
@@ -34,16 +34,20 @@ Input → Preferences → Analyze → [Check Existing?] → [Confirm 1: Style +
|
||||
|
||||
### 1.1 Load Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-comic/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-comic/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-comic/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-comic/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
| Path | Location |
|
||||
|------|----------|
|
||||
| `.baoyu-skills/baoyu-comic/EXTEND.md` | Project directory |
|
||||
@@ -431,7 +435,7 @@ With confirmed prompts from Step 5/6:
|
||||
|
||||
```bash
|
||||
# Each page generation MUST include --ref
|
||||
npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
|
||||
${BUN_X} ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
|
||||
--promptfiles prompts/01-page-xxx.md \
|
||||
--image 01-page-xxx.png \
|
||||
--ar 3:4 \
|
||||
@@ -474,7 +478,7 @@ If image generation skill supports `--sessionId`:
|
||||
After all images generated:
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/merge-to-pdf.ts <comic-dir>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/merge-to-pdf.ts <comic-dir>
|
||||
```
|
||||
|
||||
Creates `{topic-slug}.pdf` with all pages as full-page images.
|
||||
|
||||
@@ -9,7 +9,7 @@ Compresses images using best available tool (sips → cwebp → ImageMagick →
|
||||
|
||||
## Script Directory
|
||||
|
||||
Scripts in `scripts/` subdirectory. Replace `${SKILL_DIR}` with this SKILL.md's directory path.
|
||||
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.
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
@@ -17,16 +17,20 @@ Scripts in `scripts/` subdirectory. Replace `${SKILL_DIR}` with this SKILL.md's
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-compress-image/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-compress-image/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -48,7 +52,7 @@ test -f "$HOME/.baoyu-skills/baoyu-compress-image/EXTEND.md" && echo "user"
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <input> [options]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <input> [options]
|
||||
```
|
||||
|
||||
## Options
|
||||
@@ -67,16 +71,16 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts <input> [options]
|
||||
|
||||
```bash
|
||||
# Single file → WebP (replaces original)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts image.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts image.png
|
||||
|
||||
# Keep PNG format
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts image.png -f png --keep
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts image.png -f png --keep
|
||||
|
||||
# Directory recursive
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts ./images/ -r -q 75
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts ./images/ -r -q 75
|
||||
|
||||
# JSON output
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts image.png --json
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts image.png --json
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
@@ -128,10 +128,17 @@ Analyze + Save Refs → [Output Dir] → [Confirm: 6 Dimensions] → Prompt →
|
||||
|
||||
Check EXTEND.md existence (priority: project → user):
|
||||
```bash
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-cover-image/EXTEND.md && echo "project"
|
||||
test -f "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-cover-image/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
| Result | Action |
|
||||
|--------|--------|
|
||||
| Found | Load, display summary → Continue |
|
||||
|
||||
@@ -14,7 +14,8 @@ Text/image generation via Gemini Web API. Supports reference images and multi-tu
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
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
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
@@ -43,16 +44,20 @@ Before first use, verify user consent for reverse-engineered API usage.
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-danger-gemini-web/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-danger-gemini-web/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌──────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├──────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -75,23 +80,23 @@ test -f "$HOME/.baoyu-skills/baoyu-danger-gemini-web/EXTEND.md" && echo "user"
|
||||
|
||||
```bash
|
||||
# Text generation
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts "Your prompt"
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "Your prompt" --model gemini-3-flash
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts "Your prompt"
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Your prompt" --model gemini-3-flash
|
||||
|
||||
# Image generation
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cute cat" --image cat.png
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
${BUN_X} ${SKILL_DIR}/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
|
||||
|
||||
# Vision input (reference images)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "Describe this" --reference image.png
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "Create variation" --reference a.png --image out.png
|
||||
${BUN_X} ${SKILL_DIR}/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
|
||||
|
||||
# Multi-turn conversation
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts "Remember: 42" --sessionId session-abc
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts "What number?" --sessionId session-abc
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts "Remember: 42" --sessionId session-abc
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts "What number?" --sessionId session-abc
|
||||
|
||||
# JSON output
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts "Hello" --json
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts "Hello" --json
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
@@ -16,6 +16,7 @@ Scripts located in `scripts/` subdirectory.
|
||||
**Path Resolution**:
|
||||
1. `SKILL_DIR` = this SKILL.md's directory
|
||||
2. Script path = `${SKILL_DIR}/scripts/main.ts`
|
||||
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
|
||||
|
||||
## Consent Requirement
|
||||
|
||||
@@ -69,16 +70,20 @@ Use `AskUserQuestion` with options: "Yes, I accept" | "No, I decline"
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌────────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -135,10 +140,10 @@ Full reference: [references/config/first-time-setup.md](references/config/first-
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url>
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url> -o output.md
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url> --download-media
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url> --json
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> -o output.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --download-media
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --json
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
@@ -9,7 +9,7 @@ Transforms plain text or markdown files into well-structured markdown with prope
|
||||
|
||||
## Script Directory
|
||||
|
||||
Scripts in `scripts/` subdirectory. Replace `${SKILL_DIR}` with this SKILL.md's directory path.
|
||||
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.
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
@@ -19,16 +19,20 @@ Scripts in `scripts/` subdirectory. Replace `${SKILL_DIR}` with this SKILL.md's
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-format-markdown/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-format-markdown/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-format-markdown/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-format-markdown/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌──────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├──────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -210,7 +214,7 @@ Example:
|
||||
After saving, **must** run the formatting script:
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts {output-file-path} [options]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts {output-file-path} [options]
|
||||
```
|
||||
|
||||
**Script Options:**
|
||||
@@ -229,16 +233,16 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts {output-file-path} [options]
|
||||
|
||||
```bash
|
||||
# Default: spacing + emphasis enabled, quotes disabled
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md
|
||||
|
||||
# Enable all features including quote replacement
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --quotes
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --quotes
|
||||
|
||||
# Only fix emphasis issues, skip spacing
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --no-spacing
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --no-spacing
|
||||
|
||||
# Disable all processing except frontmatter formatting
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --no-spacing --no-emphasis
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --no-spacing --no-emphasis
|
||||
```
|
||||
|
||||
**Script performs (based on options):**
|
||||
|
||||
@@ -12,6 +12,7 @@ Official API-based image generation. Supports OpenAI, Google, DashScope (阿里
|
||||
**Agent Execution**:
|
||||
1. `SKILL_DIR` = this SKILL.md file's directory
|
||||
2. Script path = `${SKILL_DIR}/scripts/main.ts`
|
||||
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
|
||||
|
||||
## Step 0: Load Preferences ⛔ BLOCKING
|
||||
|
||||
@@ -20,10 +21,17 @@ Official API-based image generation. Supports OpenAI, Google, DashScope (阿里
|
||||
Check EXTEND.md existence (priority: project → user):
|
||||
|
||||
```bash
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-image-gen/EXTEND.md && echo "project"
|
||||
test -f "$HOME/.baoyu-skills/baoyu-image-gen/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-image-gen/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-image-gen/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
| Result | Action |
|
||||
|--------|--------|
|
||||
| Found | Load, parse, apply settings. If `default_model.[provider]` is null → ask model only (Flow 2) |
|
||||
@@ -44,34 +52,34 @@ Schema: `references/config/preferences-schema.md`
|
||||
|
||||
```bash
|
||||
# Basic
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image cat.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image cat.png
|
||||
|
||||
# With aspect ratio
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A landscape" --image out.png --ar 16:9
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A landscape" --image out.png --ar 16:9
|
||||
|
||||
# High quality
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --quality 2k
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --quality 2k
|
||||
|
||||
# From prompt files
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
|
||||
# With reference images (Google multimodal or OpenAI edits)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "Make blue" --image out.png --ref source.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Make blue" --image out.png --ref source.png
|
||||
|
||||
# With reference images (explicit provider/model)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "Make blue" --image out.png --provider google --model gemini-3-pro-image-preview --ref source.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "Make blue" --image out.png --provider google --model gemini-3-pro-image-preview --ref source.png
|
||||
|
||||
# Specific provider
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider openai
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider openai
|
||||
|
||||
# DashScope (阿里通义万象)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "一只可爱的猫" --image out.png --provider dashscope
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "一只可爱的猫" --image out.png --provider dashscope
|
||||
|
||||
# Replicate (google/nano-banana-pro)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate
|
||||
|
||||
# Replicate with specific model
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana
|
||||
```
|
||||
|
||||
## Options
|
||||
@@ -136,10 +144,10 @@ Examples:
|
||||
|
||||
```bash
|
||||
# Use Replicate default model
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate
|
||||
|
||||
# Override model explicitly
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts --prompt "A cat" --image out.png --provider replicate --model google/nano-banana
|
||||
```
|
||||
|
||||
## Provider Selection
|
||||
|
||||
@@ -138,16 +138,20 @@ Slug: 2-4 words kebab-case from topic. Conflict: append `-YYYYMMDD-HHMMSS`.
|
||||
|
||||
**1.1 Load Preferences (EXTEND.md)**
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-infographic/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-infographic/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-infographic/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-infographic/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────────────┼───────────────────┤
|
||||
|
||||
@@ -9,7 +9,7 @@ Converts Markdown files to beautifully styled HTML with inline CSS, optimized fo
|
||||
|
||||
## Script Directory
|
||||
|
||||
**Agent Execution**: Determine this SKILL.md directory as `SKILL_DIR`, then use `${SKILL_DIR}/scripts/<name>.ts`.
|
||||
**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.
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
@@ -17,16 +17,20 @@ Converts Markdown files to beautifully styled HTML with inline CSS, optimized fo
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-markdown-to-html/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-markdown-to-html/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-markdown-to-html/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-markdown-to-html/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌──────────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├──────────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -83,6 +87,11 @@ Use `AskUserQuestion` to ask whether to format first. Formatting can fix:
|
||||
test -f "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && grep -o 'default_theme:.*' "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { Select-String -Pattern 'default_theme:.*' -Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" | ForEach-Object { $_.Matches.Value } }
|
||||
```
|
||||
|
||||
**If theme is resolved from EXTEND.md**: Use it directly, do NOT ask the user.
|
||||
|
||||
**If no default found**: Use AskUserQuestion to confirm:
|
||||
@@ -97,7 +106,7 @@ test -f "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && grep -o 'default
|
||||
### Step 2: Convert
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme>
|
||||
```
|
||||
|
||||
### Step 3: Report Result
|
||||
@@ -107,7 +116,7 @@ Display the output path from JSON result. If backup was created, mention it.
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
||||
```
|
||||
|
||||
**Options:**
|
||||
@@ -144,19 +153,19 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
||||
|
||||
```bash
|
||||
# Basic conversion (uses default theme, removes first heading)
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md
|
||||
|
||||
# With specific theme
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --theme grace
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme grace
|
||||
|
||||
# Theme with custom color
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --theme modern --color red
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme modern --color red
|
||||
|
||||
# Keep the first heading in content
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --keep-title
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --keep-title
|
||||
|
||||
# Override title
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts article.md --title "My Article"
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --title "My Article"
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
@@ -11,7 +11,7 @@ description: Posts content to WeChat Official Account (微信公众号) via API
|
||||
|
||||
## Script Directory
|
||||
|
||||
**Agent Execution**: Determine this SKILL.md directory as `SKILL_DIR`, then use `${SKILL_DIR}/scripts/<name>.ts`.
|
||||
**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.
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
@@ -23,16 +23,20 @@ description: Posts content to WeChat Official Account (微信公众号) via API
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-post-to-wechat/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-post-to-wechat/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -88,7 +92,7 @@ chrome_profile_path: /path/to/chrome/profile
|
||||
Before first use, suggest running the environment check. User can skip if they prefer.
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/check-permissions.ts
|
||||
${BUN_X} ${SKILL_DIR}/scripts/check-permissions.ts
|
||||
```
|
||||
|
||||
Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts.
|
||||
@@ -111,8 +115,8 @@ Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystrok
|
||||
For short posts with multiple images (up to 9):
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/wechat-browser.ts --markdown article.md --images ./images/
|
||||
npx -y bun ${SKILL_DIR}/scripts/wechat-browser.ts --title "标题" --content "内容" --image img.png --submit
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-browser.ts --markdown article.md --images ./images/
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-browser.ts --title "标题" --content "内容" --image img.png --submit
|
||||
```
|
||||
|
||||
See [references/image-text-posting.md](references/image-text-posting.md) for details.
|
||||
@@ -180,13 +184,17 @@ mkdir -p "$(pwd)/post-to-wechat/$(date +%Y-%m-%d)"
|
||||
**If API Selected - Check Credentials**:
|
||||
|
||||
```bash
|
||||
# Check project-level
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/.env && grep -q "WECHAT_APP_ID" .baoyu-skills/.env && echo "project"
|
||||
|
||||
# Check user-level
|
||||
test -f "$HOME/.baoyu-skills/.env" && grep -q "WECHAT_APP_ID" "$HOME/.baoyu-skills/.env" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if ((Test-Path .baoyu-skills/.env) -and (Select-String -Quiet -Pattern "WECHAT_APP_ID" .baoyu-skills/.env)) { "project" }
|
||||
if ((Test-Path "$HOME/.baoyu-skills/.env") -and (Select-String -Quiet -Pattern "WECHAT_APP_ID" "$HOME/.baoyu-skills/.env")) { "user" }
|
||||
```
|
||||
|
||||
**If Credentials Missing - Guide Setup**:
|
||||
|
||||
```
|
||||
@@ -247,7 +255,7 @@ WECHAT_APP_SECRET=<user_input>
|
||||
**API method** (accepts `.md` or `.html`):
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>]
|
||||
```
|
||||
|
||||
**CRITICAL**: Always include `--theme` parameter. Never omit it, even if using `default`. Only include `--color` if explicitly set by user or EXTEND.md.
|
||||
@@ -266,8 +274,8 @@ If script parameters do not expose the two comment fields, still ensure final AP
|
||||
**Browser method** (accepts `--markdown` or `--html`):
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>]
|
||||
npx -y bun ${SKILL_DIR}/scripts/wechat-article.ts --html <html_file>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --html <html_file>
|
||||
```
|
||||
|
||||
### Step 5: Completion Report
|
||||
|
||||
@@ -6,13 +6,13 @@ Post markdown articles to WeChat Official Account with full formatting support.
|
||||
|
||||
```bash
|
||||
# Post markdown article
|
||||
npx -y bun ./scripts/wechat-article.ts --markdown article.md
|
||||
${BUN_X} ./scripts/wechat-article.ts --markdown article.md
|
||||
|
||||
# With theme
|
||||
npx -y bun ./scripts/wechat-article.ts --markdown article.md --theme grace
|
||||
${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace
|
||||
|
||||
# With explicit options
|
||||
npx -y bun ./scripts/wechat-article.ts --markdown article.md --author "作者名" --summary "摘要"
|
||||
${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author "作者名" --summary "摘要"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
@@ -8,13 +8,13 @@ Post image-text messages with multiple images to WeChat Official Account.
|
||||
|
||||
```bash
|
||||
# Post with images and markdown file (title/content extracted automatically)
|
||||
npx -y bun ./scripts/wechat-browser.ts --markdown source.md --images ./images/
|
||||
${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/
|
||||
|
||||
# Post with explicit title and content
|
||||
npx -y bun ./scripts/wechat-browser.ts --title "标题" --content "内容" --image img1.png --image img2.png
|
||||
${BUN_X} ./scripts/wechat-browser.ts --title "标题" --content "内容" --image img1.png --image img2.png
|
||||
|
||||
# Save as draft
|
||||
npx -y bun ./scripts/wechat-browser.ts --markdown source.md --images ./images/ --submit
|
||||
${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/ --submit
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
@@ -15,6 +15,7 @@ Posts text, images, videos, and long-form articles to X via real Chrome browser
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` 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
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
@@ -30,16 +31,20 @@ Posts text, images, videos, and long-form articles to X via real Chrome browser
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-post-to-x/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-post-to-x/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌──────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├──────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -69,7 +74,7 @@ test -f "$HOME/.baoyu-skills/baoyu-post-to-x/EXTEND.md" && echo "user"
|
||||
Before first use, suggest running the environment check. User can skip if they prefer.
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/check-paste-permissions.ts
|
||||
${BUN_X} ${SKILL_DIR}/scripts/check-paste-permissions.ts
|
||||
```
|
||||
|
||||
Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, Chrome conflicts.
|
||||
@@ -98,7 +103,7 @@ Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystrok
|
||||
Text + up to 4 images.
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-browser.ts "Hello!" --image ./photo.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-browser.ts "Hello!" --image ./photo.png
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
@@ -117,7 +122,7 @@ npx -y bun ${SKILL_DIR}/scripts/x-browser.ts "Hello!" --image ./photo.png
|
||||
Text + video file.
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-video.ts "Check this out!" --video ./clip.mp4
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-video.ts "Check this out!" --video ./clip.mp4
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
@@ -138,7 +143,7 @@ npx -y bun ${SKILL_DIR}/scripts/x-video.ts "Check this out!" --video ./clip.mp4
|
||||
Quote an existing tweet with comment.
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-quote.ts https://x.com/user/status/123 "Great insight!"
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-quote.ts https://x.com/user/status/123 "Great insight!"
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
@@ -157,8 +162,8 @@ npx -y bun ${SKILL_DIR}/scripts/x-quote.ts https://x.com/user/status/123 "Great
|
||||
Long-form Markdown articles (requires X Premium).
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-article.ts article.md
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
@@ -172,6 +177,12 @@ npx -y bun ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg
|
||||
|
||||
**Note**: Script opens browser with article filled in. User reviews and publishes manually.
|
||||
|
||||
**Post-Composition Check**: The script automatically verifies after all images are inserted:
|
||||
- Remaining `XIMGPH_` placeholders in editor content
|
||||
- Expected vs actual image count
|
||||
|
||||
If the check fails (warnings in output), alert the user with the specific issues before they publish.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -12,13 +12,13 @@ Publish Markdown articles to X Articles editor with rich text formatting and ima
|
||||
|
||||
```bash
|
||||
# Publish markdown article (preview mode)
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-article.ts article.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md
|
||||
|
||||
# With custom cover image
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg
|
||||
|
||||
# Actually publish
|
||||
npx -y bun ${SKILL_DIR}/scripts/x-article.ts article.md --submit
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --submit
|
||||
```
|
||||
|
||||
## Markdown Format
|
||||
@@ -76,13 +76,13 @@ Convert markdown and inspect structure:
|
||||
|
||||
```bash
|
||||
# Get JSON with all metadata
|
||||
npx -y bun ${SKILL_DIR}/scripts/md-to-html.ts article.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/md-to-html.ts article.md
|
||||
|
||||
# Output HTML only
|
||||
npx -y bun ${SKILL_DIR}/scripts/md-to-html.ts article.md --html-only
|
||||
${BUN_X} ${SKILL_DIR}/scripts/md-to-html.ts article.md --html-only
|
||||
|
||||
# Save HTML to file
|
||||
npx -y bun ${SKILL_DIR}/scripts/md-to-html.ts article.md --save-html /tmp/article.html
|
||||
${BUN_X} ${SKILL_DIR}/scripts/md-to-html.ts article.md --save-html /tmp/article.html
|
||||
```
|
||||
|
||||
JSON output:
|
||||
@@ -132,8 +132,12 @@ JSON output:
|
||||
- Select the placeholder
|
||||
- Copy image to clipboard
|
||||
- Paste to replace selection
|
||||
9. **Review**: Browser stays open for 60s preview
|
||||
10. **Publish**: Only with `--submit` flag
|
||||
9. **Post-Composition Check** (automatic):
|
||||
- Scan editor for remaining `XIMGPH_` placeholders
|
||||
- Compare expected vs actual image count
|
||||
- Warn if issues found
|
||||
10. **Review**: Browser stays open for 60s preview
|
||||
11. **Publish**: Only with `--submit` flag
|
||||
|
||||
## Example Session
|
||||
|
||||
@@ -157,7 +161,7 @@ Claude:
|
||||
- **No create button**: Ensure X Premium subscription is active
|
||||
- **Cover upload fails**: Check file path and format (PNG, JPEG)
|
||||
- **Images not inserting**: Verify placeholders exist in pasted content
|
||||
- **Content not pasting**: Check HTML clipboard: `npx -y bun ${SKILL_DIR}/scripts/copy-to-clipboard.ts html --file /tmp/test.html`
|
||||
- **Content not pasting**: Check HTML clipboard: `${BUN_X} ${SKILL_DIR}/scripts/copy-to-clipboard.ts html --file /tmp/test.html`
|
||||
|
||||
## How It Works
|
||||
|
||||
|
||||
@@ -9,20 +9,20 @@ If you prefer step-by-step control:
|
||||
### Step 1: Copy Image to Clipboard
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/copy-to-clipboard.ts image /path/to/image.png
|
||||
${BUN_X} ${SKILL_DIR}/scripts/copy-to-clipboard.ts image /path/to/image.png
|
||||
```
|
||||
|
||||
### Step 2: Paste from Clipboard
|
||||
|
||||
```bash
|
||||
# Simple paste to frontmost app
|
||||
npx -y bun ${SKILL_DIR}/scripts/paste-from-clipboard.ts
|
||||
${BUN_X} ${SKILL_DIR}/scripts/paste-from-clipboard.ts
|
||||
|
||||
# Paste to Chrome with retries
|
||||
npx -y bun ${SKILL_DIR}/scripts/paste-from-clipboard.ts --app "Google Chrome" --retries 5
|
||||
${BUN_X} ${SKILL_DIR}/scripts/paste-from-clipboard.ts --app "Google Chrome" --retries 5
|
||||
|
||||
# Quick paste with shorter delay
|
||||
npx -y bun ${SKILL_DIR}/scripts/paste-from-clipboard.ts --delay 200
|
||||
${BUN_X} ${SKILL_DIR}/scripts/paste-from-clipboard.ts --delay 200
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
Claude:
|
||||
1. Runs: npx -y bun ${SKILL_DIR}/scripts/x-browser.ts "Hello from Claude!" --image ./screenshot.png
|
||||
1. Runs: ${BUN_X} ${SKILL_DIR}/scripts/x-browser.ts "Hello from Claude!" --image ./screenshot.png
|
||||
2. Chrome opens with X compose page
|
||||
3. Text is typed into editor
|
||||
4. Image is copied to clipboard and pasted
|
||||
@@ -72,7 +72,7 @@ Claude:
|
||||
- **Chrome not found**: Set `X_BROWSER_CHROME_PATH` environment variable
|
||||
- **Not logged in**: First run opens Chrome - log in manually, cookies are saved
|
||||
- **Image paste fails**:
|
||||
- Verify clipboard script: `npx -y bun ${SKILL_DIR}/scripts/copy-to-clipboard.ts image <path>`
|
||||
- Verify clipboard script: `${BUN_X} ${SKILL_DIR}/scripts/copy-to-clipboard.ts image <path>`
|
||||
- On macOS, grant "Accessibility" permission to Terminal/iTerm in System Settings > Privacy & Security > Accessibility
|
||||
- Keep Chrome window visible and in front during paste operations
|
||||
- **osascript permission denied**: Grant Terminal accessibility permissions in System Preferences
|
||||
|
||||
@@ -130,7 +130,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||
|
||||
try {
|
||||
const wsUrl = await waitForChromeDebugPort(port, 30_000, { includeLastError: true });
|
||||
cdp = await CdpConnection.connect(wsUrl, 30_000, { defaultTimeoutMs: 30_000 });
|
||||
cdp = await CdpConnection.connect(wsUrl, 30_000, { defaultTimeoutMs: 60_000 });
|
||||
|
||||
// Get page target
|
||||
const targets = await cdp.send<{ targetInfos: Array<{ targetId: string; url: string; type: string }> }>('Target.getTargets');
|
||||
@@ -148,7 +148,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||
await cdp.send('DOM.enable', {}, { sessionId });
|
||||
|
||||
console.log('[x-article] Waiting for articles page...');
|
||||
await sleep(3000);
|
||||
await sleep(1000);
|
||||
|
||||
// Wait for and click "create" button
|
||||
const waitForElement = async (selector: string, timeoutMs = 60_000): Promise<boolean> => {
|
||||
@@ -644,6 +644,8 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||
|
||||
if (imgUploadOk) {
|
||||
console.log(`[x-article] Image upload verified (${expectedImgCount} image block(s))`);
|
||||
// Wait for DraftEditor DOM to stabilize after image insertion
|
||||
await sleep(3000);
|
||||
} else {
|
||||
console.warn(`[x-article] Image upload not detected after 15s`);
|
||||
if (i === 0) {
|
||||
@@ -653,6 +655,42 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||
}
|
||||
|
||||
console.log('[x-article] All images processed.');
|
||||
|
||||
// Final verification: check placeholder residue and image count
|
||||
console.log('[x-article] Running post-composition verification...');
|
||||
const finalEditorContent = await cdp.send<{ result: { value: string } }>('Runtime.evaluate', {
|
||||
expression: `document.querySelector('.DraftEditor-editorContainer [data-contents="true"]')?.innerText || ''`,
|
||||
returnByValue: true,
|
||||
}, { sessionId });
|
||||
|
||||
const remainingPlaceholders: string[] = [];
|
||||
for (const img of parsed.contentImages) {
|
||||
const regex = new RegExp(img.placeholder + '(?!\\d)');
|
||||
if (regex.test(finalEditorContent.result.value)) {
|
||||
remainingPlaceholders.push(img.placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
const finalImgCount = await cdp.send<{ result: { value: number } }>('Runtime.evaluate', {
|
||||
expression: `document.querySelectorAll('section[data-block="true"][contenteditable="false"] img[src^="blob:"]').length`,
|
||||
returnByValue: true,
|
||||
}, { sessionId });
|
||||
|
||||
const expectedCount = parsed.contentImages.length;
|
||||
const actualCount = finalImgCount.result.value;
|
||||
|
||||
if (remainingPlaceholders.length > 0 || actualCount < expectedCount) {
|
||||
console.warn('[x-article] ⚠ POST-COMPOSITION CHECK FAILED:');
|
||||
if (remainingPlaceholders.length > 0) {
|
||||
console.warn(`[x-article] Remaining placeholders: ${remainingPlaceholders.join(', ')}`);
|
||||
}
|
||||
if (actualCount < expectedCount) {
|
||||
console.warn(`[x-article] Image count: expected ${expectedCount}, found ${actualCount}`);
|
||||
}
|
||||
console.warn('[x-article] Please check the article before publishing.');
|
||||
} else {
|
||||
console.log(`[x-article] ✓ Verification passed: ${actualCount} image(s), no remaining placeholders.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Before preview: blur editor to trigger save
|
||||
|
||||
@@ -24,6 +24,7 @@ Transform content into professional slide deck images.
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
@@ -189,16 +190,20 @@ Input → Preferences → Analyze → [Check Existing?] → Confirm (1-2 rounds)
|
||||
|
||||
**1.1 Load Preferences (EXTEND.md)**
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-slide-deck/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-slide-deck/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-slide-deck/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-slide-deck/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌──────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├──────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -550,8 +555,8 @@ options:
|
||||
### Step 8: Merge to PPTX and PDF
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/merge-to-pptx.ts <slide-deck-dir>
|
||||
npx -y bun ${SKILL_DIR}/scripts/merge-to-pdf.ts <slide-deck-dir>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/merge-to-pptx.ts <slide-deck-dir>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/merge-to-pdf.ts <slide-deck-dir>
|
||||
```
|
||||
|
||||
### Step 9: Output Summary
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
---
|
||||
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", or needs any document translation. Also triggers for "refined translation", "精细翻译", "proofread translation", or "快速翻译".
|
||||
---
|
||||
|
||||
# Translator
|
||||
|
||||
Three-mode translation skill: **quick** for direct translation, **normal** for analysis-informed translation, **refined** for full publication-quality workflow with review and polish.
|
||||
|
||||
## 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.
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `scripts/chunk.ts` | Split markdown into chunks by AST blocks (sections, headings, paragraphs), with line/word fallback for oversized blocks |
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-translate/EXTEND.md && echo "project"
|
||||
test -f "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-translate/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
| Path | Location |
|
||||
|------|----------|
|
||||
| `.baoyu-skills/baoyu-translate/EXTEND.md` | Project directory |
|
||||
| `$HOME/.baoyu-skills/baoyu-translate/EXTEND.md` | User home |
|
||||
|
||||
| Result | Action |
|
||||
|--------|--------|
|
||||
| Found | Read, parse, apply settings. On first use in session, briefly remind: "Using preferences from [path]. You can edit EXTEND.md to customize glossary, audience, etc." |
|
||||
| Not found | **MUST** run first-time setup (see below) — do NOT silently use defaults |
|
||||
|
||||
**EXTEND.md Supports**: Default target language | Default mode | Target audience | Custom glossaries | Translation style | Chunk settings
|
||||
|
||||
Schema: [references/config/extend-schema.md](references/config/extend-schema.md)
|
||||
|
||||
### First-Time Setup (BLOCKING)
|
||||
|
||||
**CRITICAL**: When EXTEND.md is not found, you **MUST** run the first-time setup before ANY translation. This is a **BLOCKING** operation.
|
||||
|
||||
Full reference: [references/config/first-time-setup.md](references/config/first-time-setup.md)
|
||||
|
||||
Use `AskUserQuestion` with all questions (target language, mode, audience, style, save location) in ONE call. After user answers, create EXTEND.md at the chosen location, confirm "Preferences saved to [path]", then continue.
|
||||
|
||||
## Defaults
|
||||
|
||||
All configurable values in one place. EXTEND.md overrides these; CLI flags override EXTEND.md.
|
||||
|
||||
| Setting | Default | EXTEND.md key | CLI flag | Description |
|
||||
|---------|---------|---------------|----------|-------------|
|
||||
| Target language | `zh-CN` | `target_language` | `--to` | Translation target language |
|
||||
| Mode | `normal` | `default_mode` | `--mode` | Translation mode |
|
||||
| Audience | `general` | `audience` | `--audience` | Target reader profile |
|
||||
| Style | `storytelling` | `style` | — | Translation style preference |
|
||||
| Chunk threshold | `4000` | `chunk_threshold` | — | Word count to trigger chunked translation |
|
||||
| Chunk max words | `5000` | `chunk_max_words` | — | Max words per chunk |
|
||||
|
||||
## Modes
|
||||
|
||||
| Mode | Flag | Steps | When to Use |
|
||||
|------|------|-------|-------------|
|
||||
| Quick | `--mode quick` | Translate | Short texts, informal content, quick tasks |
|
||||
| Normal | `--mode normal` (default) | Analyze → Translate | Articles, blog posts, general content |
|
||||
| Refined | `--mode refined` | Analyze → Translate → Review → Polish | Publication-quality, important documents |
|
||||
|
||||
**Default mode**: Normal (can be overridden in EXTEND.md `default_mode` setting).
|
||||
|
||||
**Auto-detection**:
|
||||
- "快翻", "quick", "直接翻译" → quick mode
|
||||
- "精翻", "refined", "publication quality", "proofread" → refined mode
|
||||
- Otherwise → default mode (normal)
|
||||
|
||||
**Upgrade prompt**: After normal mode completes, display:
|
||||
> Translation saved. To further review and polish, reply "继续润色" or "refine".
|
||||
|
||||
If user responds, continue with review → polish steps (same as refined mode Steps 3-4) on the existing output.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/translate [--mode quick|normal|refined] [--from <lang>] [--to <lang>] [--audience <audience>] [--glossary <file>] <source>
|
||||
```
|
||||
|
||||
- `<source>`: File path, URL, or inline text
|
||||
- `--from`: Source language (auto-detect if omitted)
|
||||
- `--to`: Target language (from EXTEND.md or default `zh-CN`)
|
||||
- `--audience`: Target reader profile (from EXTEND.md or default `general`)
|
||||
- `--glossary`: Additional glossary file to merge with EXTEND.md glossary
|
||||
|
||||
**Audience presets**:
|
||||
|
||||
| Value | Description | Effect |
|
||||
|-------|-------------|--------|
|
||||
| `general` | General readers (default) | Plain language, more translator's notes for jargon |
|
||||
| `technical` | Developers / engineers | Less annotation on common tech terms |
|
||||
| `academic` | Researchers / scholars | Formal register, precise terminology |
|
||||
| `business` | Business professionals | Business-friendly tone, explain tech concepts |
|
||||
|
||||
Custom audience descriptions are also accepted, e.g., `--audience "AI感兴趣的普通读者"`.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Load Preferences
|
||||
|
||||
1.1 Check EXTEND.md (see Preferences section above)
|
||||
|
||||
1.2 Load built-in glossary for the language pair if available:
|
||||
- EN→ZH: [references/glossary-en-zh.md](references/glossary-en-zh.md)
|
||||
|
||||
1.3 Merge glossaries: EXTEND.md glossary + built-in glossary + `--glossary` file (CLI overrides all)
|
||||
|
||||
### Step 2: Materialize Source & Create Output Directory
|
||||
|
||||
If the input is not a file, save it as one first. Then create an output subdirectory next to the source file.
|
||||
|
||||
**2.1 Materialize source**
|
||||
|
||||
| Input Type | Action |
|
||||
|------------|--------|
|
||||
| File | Use as-is (no copy needed) |
|
||||
| Inline text | Save to `translate/{slug}.md` |
|
||||
| URL | Fetch content, save to `translate/{slug}.md` |
|
||||
|
||||
`{slug}`: 2-4 word kebab-case slug derived from content topic.
|
||||
|
||||
**2.2 Create output directory**
|
||||
|
||||
Create a subdirectory next to the source file: `{source-dir}/{source-basename}-{target-lang}/`
|
||||
|
||||
Examples:
|
||||
- `posts/article.md` → `posts/article-zh/`
|
||||
- `translate/ai-future.md` → `translate/ai-future-zh/`
|
||||
|
||||
**Conflict resolution**: If the output directory already exists, rename the existing one to `{name}.backup-YYYYMMDD-HHMMSS/` before creating the new one. Never overwrite existing results.
|
||||
|
||||
**2.3 Output directory contents**
|
||||
|
||||
All intermediate and final files go into this directory:
|
||||
|
||||
| File | Mode | Description |
|
||||
|------|------|-------------|
|
||||
| `translation.md` | All | Final translation (always this name) |
|
||||
| `01-analysis.md` | Normal, Refined | Content analysis (domain, tone, terminology) |
|
||||
| `02-prompt.md` | Normal, Refined | Assembled translation prompt (used by subagent or inline) |
|
||||
| `03-draft.md` | Refined | Initial draft before review |
|
||||
| `04-review.md` | Refined | Reviewed version with fixes |
|
||||
| `chunks/` | Chunked | Source chunks + translated chunks |
|
||||
| `chunks/chunk-01.md` | Chunked | Source chunk |
|
||||
| `chunks/chunk-01-draft.md` | Chunked | Translated chunk |
|
||||
|
||||
Detect source language if `--from` not specified.
|
||||
|
||||
### Step 3: Assess Content Length
|
||||
|
||||
Quick mode does not chunk — translate directly regardless of length. If content exceeds model context limits, suggest the user switch to normal or refined mode.
|
||||
|
||||
For normal and refined modes:
|
||||
|
||||
| Content | Action |
|
||||
|---------|--------|
|
||||
| < chunk threshold | Translate as single unit |
|
||||
| >= chunk threshold | Chunk translation (see Step 3.1) |
|
||||
|
||||
**3.1 Long Content Preparation** (normal/refined modes, >= chunk threshold only)
|
||||
|
||||
Before translating chunks:
|
||||
|
||||
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
|
||||
3. **Split into chunks**: Use `${BUN_X} ${SKILL_DIR}/scripts/chunk.ts <file> [--max-words <chunk_max_words>]`
|
||||
- Parses markdown AST (headings, paragraphs, lists, code blocks, tables, etc.)
|
||||
- Splits at markdown block boundaries to preserve structure
|
||||
- If a single block exceeds the threshold, falls back to line splitting, then word splitting
|
||||
4. **Assemble translation prompt**:
|
||||
- Main agent reads `01-analysis.md` (if exists) and assembles shared context using Part 1 of [references/subagent-prompt-template.md](references/subagent-prompt-template.md) — inlining content background, merged glossary, and comprehension challenges
|
||||
- Save as `02-prompt.md` in the output directory (shared context only, no task instructions)
|
||||
5. **Draft translation via subagents** (if Agent tool available):
|
||||
- Spawn one subagent **per chunk**, all in parallel (Part 2 of the template)
|
||||
- Each subagent reads `02-prompt.md` for shared context, translates its chunk, saves to `chunks/chunk-NN-draft.md`
|
||||
- Terminology consistency is guaranteed by the shared `02-prompt.md` (glossary + comprehension challenges from analysis)
|
||||
- If no chunks (content under threshold): spawn one subagent for the entire source file
|
||||
- If Agent tool is unavailable, translate chunks sequentially inline using `02-prompt.md`
|
||||
6. **Merge**: Once all subagents complete, combine translated chunks in order, prepend frontmatter if present → save as `03-draft.md` (refined) or `translation.md` (normal)
|
||||
7. All intermediate files (source chunks + translated chunks) are preserved in `chunks/`
|
||||
|
||||
**After chunked draft is merged**, return control to main agent for review and polish (Step 4).
|
||||
|
||||
### Step 4: Translate & Refine
|
||||
|
||||
**Translation principles** (apply to all modes):
|
||||
|
||||
- **Accuracy first**: Facts, data, and logic must match the original exactly
|
||||
- **Natural flow**: Use idiomatic target language word order; break long sentences into shorter ones
|
||||
- **Terminology**: Use standard translations; annotate with original term in parentheses on first occurrence
|
||||
- **Preserve format**: Keep all markdown formatting (headings, bold, italic, images, links, code blocks)
|
||||
- **Respect original**: Maintain original structure and meaning; do not add, remove, or editorialize
|
||||
- **Translator's notes**: For terms, concepts, or cultural references that target readers may not understand — due to jargon, cultural gaps, or domain-specific knowledge — add a concise explanatory note in parentheses immediately after the term. The note should explain *what it means* in plain language, not just provide the English original. Format: `译文(English original,通俗解释)`. Calibrate annotation depth to the target audience: general readers need more notes than technical readers. Only add notes where genuinely needed; do not over-annotate obvious terms.
|
||||
|
||||
#### Quick Mode
|
||||
|
||||
Translate directly → save to `translation.md`.
|
||||
|
||||
#### Normal Mode
|
||||
|
||||
1. **Analyze** → `01-analysis.md` (domain, tone, audience, terminology, reader comprehension challenges)
|
||||
2. **Assemble prompt** → `02-prompt.md` (translation instructions with inlined context)
|
||||
3. **Translate** (following `02-prompt.md`) → `translation.md`
|
||||
|
||||
After completion, prompt user: "Translation saved. To further review and polish, reply **继续润色** or **refine**."
|
||||
|
||||
If user continues, proceed with review → polish (same as refined mode Steps 3-4 below), saving `03-draft.md` (rename current `translation.md`), `04-review.md`, and updated `translation.md`.
|
||||
|
||||
#### Refined Mode
|
||||
|
||||
Full workflow for publication quality. See [references/refined-workflow.md](references/refined-workflow.md) for detailed guidelines per step.
|
||||
|
||||
The subagent (if used in Step 3.1) only handles the initial draft. All subsequent steps are handled by the main agent, which may delegate to subagents at its discretion.
|
||||
|
||||
Steps and saved files (all in output directory):
|
||||
1. **Analyze** → `01-analysis.md` (domain, tone, terminology, reader comprehension challenges)
|
||||
2. **Assemble prompt** → `02-prompt.md` (translation instructions with inlined context)
|
||||
3. **Draft** → `03-draft.md` (initial translation with translator's notes; from subagent if chunked)
|
||||
4. **Review** → `04-review.md` (accuracy, naturalness, terminology fixes)
|
||||
5. **Polish** → `translation.md` (final publication-quality translation)
|
||||
|
||||
Each step reads the previous step's file and builds on it.
|
||||
|
||||
### Step 5: Output
|
||||
|
||||
Final translation is always at `translation.md` in the output directory.
|
||||
|
||||
Display summary:
|
||||
```
|
||||
**Translation complete** ({mode} mode)
|
||||
|
||||
Source: {source-path}
|
||||
Languages: {from} → {to}
|
||||
Output dir: {output-dir}/
|
||||
Final: {output-dir}/translation.md
|
||||
Glossary terms applied: {count}
|
||||
```
|
||||
|
||||
## Extension Support
|
||||
|
||||
Custom configurations via EXTEND.md. See **Preferences** section for paths and supported options.
|
||||
@@ -0,0 +1,73 @@
|
||||
# EXTEND.md Schema for baoyu-translate
|
||||
|
||||
## Format
|
||||
|
||||
EXTEND.md uses YAML format:
|
||||
|
||||
```yaml
|
||||
# Default target language (ISO code or common name)
|
||||
target_language: zh-CN
|
||||
|
||||
# Default translation mode
|
||||
default_mode: normal # quick | normal | refined
|
||||
|
||||
# Target audience (affects annotation depth and register)
|
||||
audience: general # general | technical | academic | business | or custom string
|
||||
|
||||
# Translation style preference
|
||||
style: storytelling # storytelling | formal | technical | literal
|
||||
|
||||
# Word count threshold to trigger chunked translation
|
||||
chunk_threshold: 4000
|
||||
|
||||
# Max words per chunk
|
||||
chunk_max_words: 5000
|
||||
|
||||
# Custom glossary (merged with built-in glossary)
|
||||
# CLI --glossary flag overrides these
|
||||
glossary:
|
||||
- from: "Reinforcement Learning"
|
||||
to: "强化学习"
|
||||
- from: "Transformer"
|
||||
to: "Transformer"
|
||||
note: "Keep English"
|
||||
|
||||
# Language-pair specific glossaries
|
||||
glossaries:
|
||||
en-zh:
|
||||
- from: "AI Agent"
|
||||
to: "AI 智能体"
|
||||
ja-zh:
|
||||
- from: "人工知能"
|
||||
to: "人工智能"
|
||||
```
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `target_language` | string | `zh-CN` | Default target language code |
|
||||
| `default_mode` | string | `normal` | Default translation mode (`quick` / `normal` / `refined`) |
|
||||
| `audience` | string | `general` | Target reader profile (`general` / `technical` / `academic` / `business` / custom) |
|
||||
| `style` | string | `storytelling` | Translation style preference |
|
||||
| `chunk_threshold` | number | `4000` | Word count threshold to trigger chunked translation |
|
||||
| `chunk_max_words` | number | `5000` | Max words per chunk |
|
||||
| `glossary` | array | `[]` | Universal glossary entries |
|
||||
| `glossaries` | object | `{}` | Language-pair specific glossary entries |
|
||||
|
||||
## Glossary Entry
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `from` | yes | Source term |
|
||||
| `to` | yes | Target translation |
|
||||
| `note` | no | Usage note (e.g., "Keep English", "Only in tech context") |
|
||||
|
||||
## Priority
|
||||
|
||||
1. CLI `--glossary` file entries
|
||||
2. EXTEND.md `glossaries[pair]` entries
|
||||
3. EXTEND.md `glossary` entries
|
||||
4. Built-in glossary (e.g., `references/glossary-en-zh.md`)
|
||||
|
||||
Later entries override earlier ones for the same source term.
|
||||
@@ -0,0 +1,157 @@
|
||||
---
|
||||
name: first-time-setup
|
||||
description: First-time setup flow for baoyu-translate preferences
|
||||
---
|
||||
|
||||
# First-Time Setup
|
||||
|
||||
## Overview
|
||||
|
||||
When no EXTEND.md is found, guide user through preference setup.
|
||||
|
||||
**BLOCKING OPERATION**: This setup MUST complete before ANY translation. Do NOT:
|
||||
- Start translating content
|
||||
- Ask about files or output paths
|
||||
- Proceed to any workflow steps
|
||||
|
||||
ONLY ask the questions in this setup flow, save EXTEND.md, then continue.
|
||||
|
||||
## Setup Flow
|
||||
|
||||
```
|
||||
No EXTEND.md found
|
||||
|
|
||||
v
|
||||
+---------------------+
|
||||
| AskUserQuestion |
|
||||
| (all questions) |
|
||||
+---------------------+
|
||||
|
|
||||
v
|
||||
+---------------------+
|
||||
| Create EXTEND.md |
|
||||
+---------------------+
|
||||
|
|
||||
v
|
||||
Continue translation
|
||||
```
|
||||
|
||||
## Questions
|
||||
|
||||
**Language**: Use user's input language or saved language preference.
|
||||
|
||||
Use AskUserQuestion with ALL questions in ONE call:
|
||||
|
||||
### Question 1: Target Language
|
||||
|
||||
```yaml
|
||||
header: "Target Language"
|
||||
question: "Default target language?"
|
||||
options:
|
||||
- label: "简体中文 zh-CN (Recommended)"
|
||||
description: "Translate to Simplified Chinese"
|
||||
- label: "繁體中文 zh-TW"
|
||||
description: "Translate to Traditional Chinese"
|
||||
- label: "English en"
|
||||
description: "Translate to English"
|
||||
- label: "日本語 ja"
|
||||
description: "Translate to Japanese"
|
||||
```
|
||||
|
||||
Note: User may type a custom language code.
|
||||
|
||||
### Question 2: Translation Mode
|
||||
|
||||
```yaml
|
||||
header: "Mode"
|
||||
question: "Default translation mode?"
|
||||
options:
|
||||
- label: "Normal (Recommended)"
|
||||
description: "Analyze content first, then translate"
|
||||
- label: "Quick"
|
||||
description: "Direct translation, no analysis"
|
||||
- label: "Refined"
|
||||
description: "Full workflow: analyze → translate → review → polish"
|
||||
```
|
||||
|
||||
### Question 3: Target Audience
|
||||
|
||||
```yaml
|
||||
header: "Audience"
|
||||
question: "Default target audience?"
|
||||
options:
|
||||
- label: "General readers (Recommended)"
|
||||
description: "Plain language, more translator's notes for jargon"
|
||||
- label: "Technical"
|
||||
description: "Developers/engineers, less annotation on tech terms"
|
||||
- label: "Academic"
|
||||
description: "Formal register, precise terminology"
|
||||
- label: "Business"
|
||||
description: "Business-friendly tone, explain tech concepts"
|
||||
```
|
||||
|
||||
Note: User may type a custom audience description.
|
||||
|
||||
### Question 4: Translation Style
|
||||
|
||||
```yaml
|
||||
header: "Style"
|
||||
question: "Translation style?"
|
||||
options:
|
||||
- label: "Storytelling (Recommended)"
|
||||
description: "Engaging, narrative-like flow"
|
||||
- label: "Formal"
|
||||
description: "Professional, structured"
|
||||
- label: "Technical"
|
||||
description: "Precise, documentation-style"
|
||||
- label: "Literal"
|
||||
description: "Close to original structure"
|
||||
```
|
||||
|
||||
### Question 5: Save Location
|
||||
|
||||
```yaml
|
||||
header: "Save"
|
||||
question: "Where to save preferences?"
|
||||
options:
|
||||
- label: "User (Recommended)"
|
||||
description: "$HOME/.baoyu-skills/ (all projects)"
|
||||
- label: "Project"
|
||||
description: ".baoyu-skills/ (this project only)"
|
||||
```
|
||||
|
||||
## Save Locations
|
||||
|
||||
| Choice | Path | Scope |
|
||||
|--------|------|-------|
|
||||
| User | `$HOME/.baoyu-skills/baoyu-translate/EXTEND.md` | All projects |
|
||||
| Project | `.baoyu-skills/baoyu-translate/EXTEND.md` | Current project |
|
||||
|
||||
## After Setup
|
||||
|
||||
1. Create directory if needed
|
||||
2. Write EXTEND.md with selected values
|
||||
3. Confirm: "Preferences saved to [path]"
|
||||
4. Mention: "You can add custom glossary terms to EXTEND.md anytime. See the `glossary` section in the file for the format."
|
||||
5. Continue with translation using saved preferences
|
||||
|
||||
## EXTEND.md Template
|
||||
|
||||
```yaml
|
||||
target_language: [zh-CN/zh-TW/en/ja/...]
|
||||
default_mode: [quick/normal/refined]
|
||||
audience: [general/technical/academic/business/custom]
|
||||
style: [storytelling/formal/technical/literal]
|
||||
|
||||
# Custom glossary (optional) — add your own term translations here
|
||||
# glossary:
|
||||
# - from: "Term"
|
||||
# to: "翻译"
|
||||
# - from: "Another Term"
|
||||
# to: "另一个翻译"
|
||||
# note: "Usage context"
|
||||
```
|
||||
|
||||
## Modifying Preferences Later
|
||||
|
||||
Users can edit EXTEND.md directly or delete it to trigger setup again.
|
||||
@@ -0,0 +1,21 @@
|
||||
# English → Chinese Glossary
|
||||
|
||||
Terms where standard translation is non-obvious or easily mistranslated. Common terms with straightforward translations (e.g., Machine Learning → 机器学习) are omitted — the model already knows these.
|
||||
|
||||
| English | Chinese | Notes |
|
||||
|---------|---------|-------|
|
||||
| AI Agent | AI 智能体 | |
|
||||
| Vibe Coding | 凭感觉编程 | |
|
||||
| the Bitter Lesson | 苦涩的教训 | Rich Sutton's essay |
|
||||
| Context Engineering | 上下文工程 | |
|
||||
| AI Wrapper | AI 套壳 | |
|
||||
| RLHF | 基于人类反馈的强化学习 | |
|
||||
| Hallucination | 幻觉 | AI-specific meaning |
|
||||
| Alignment | 对齐 | AI safety context |
|
||||
| Guardrails | 护栏 | AI safety context |
|
||||
| Agentic | 智能体化的 | |
|
||||
| Grounding | 基础化/落地 | Context-dependent |
|
||||
| Embedding | 嵌入/向量化 | Context-dependent |
|
||||
| Moat | 护城河 | Business context |
|
||||
| Flywheel | 飞轮效应 | |
|
||||
| Boilerplate | 样板代码 | |
|
||||
@@ -0,0 +1,186 @@
|
||||
# Translation Workflow Details
|
||||
|
||||
This file provides detailed guidelines for each workflow step. Steps are shared across modes:
|
||||
|
||||
- **Quick**: Translate only (no steps from this file)
|
||||
- **Normal**: Step 1 (Analysis) → Translate
|
||||
- **Refined**: Step 1 (Analysis) → Step 2 (Draft) → Step 3 (Review) → Step 4 (Polish)
|
||||
- **Normal → Upgrade**: After normal mode, user can continue with Step 3 → Step 4
|
||||
|
||||
All intermediate results are saved as files in the output directory.
|
||||
|
||||
## Step 1: Content Analysis
|
||||
|
||||
Before translating, deeply analyze the source material. Save analysis to `01-analysis.md` in the output directory. Focus on dimensions that directly inform translation quality.
|
||||
|
||||
### 1.1 Quick Summary
|
||||
|
||||
3-5 sentences capturing:
|
||||
- What is this content about?
|
||||
- What is the core argument?
|
||||
- What is the most valuable point?
|
||||
|
||||
### 1.2 Core Content
|
||||
|
||||
- **Core argument**: One sentence summary
|
||||
- **Key concepts**: What key concepts does the author use? How are they defined?
|
||||
- **Structure**: How is the argument developed? How do sections connect?
|
||||
- **Evidence**: What specific examples, data, or authoritative citations are used?
|
||||
|
||||
### 1.3 Background Context
|
||||
|
||||
- **Author**: Who is the author? What is their background and stance?
|
||||
- **Writing context**: What phenomenon, trend, or debate is this responding to?
|
||||
- **Purpose**: What problem is the author trying to solve? Who are they trying to influence?
|
||||
- **Implicit assumptions**: What unstated premises underlie the argument?
|
||||
|
||||
### 1.4 Terminology Extraction
|
||||
|
||||
- List all technical terms, proper nouns, brand names, acronyms
|
||||
- Cross-reference with loaded glossaries
|
||||
- For terms not in glossary, research standard translations
|
||||
- Record decisions in a working terminology table
|
||||
|
||||
### 1.5 Tone & Style
|
||||
|
||||
- Is the original formal or conversational?
|
||||
- Does it use humor, metaphor, or cultural references?
|
||||
- What register is appropriate for the translation given the target audience?
|
||||
|
||||
### 1.6 Reader Comprehension Challenges
|
||||
|
||||
Identify points where target readers may struggle, calibrated to the target audience:
|
||||
|
||||
- **Domain jargon**: Technical terms that lack widely-known translations or are meaningless when translated literally
|
||||
- **Cultural references**: Idioms, historical events, pop culture, social norms specific to the source culture
|
||||
- **Implicit knowledge**: Background context the original author assumes but target readers may lack
|
||||
- **Wordplay & metaphors**: Figurative language that doesn't carry over across languages
|
||||
- **Named concepts**: Theories, effects, or phenomena with coined names (e.g., "comb-over effect", "Dunning-Kruger effect")
|
||||
- **Cognitive gaps**: Counterintuitive claims or expectations vs. reality that need framing for target readers
|
||||
|
||||
For each identified challenge, note:
|
||||
1. The original term/passage
|
||||
2. Why it may confuse target readers
|
||||
3. A concise plain-language explanation to use as a translator's note
|
||||
|
||||
### 1.7 Translation Challenges
|
||||
|
||||
- Structural challenges (wordplay, ambiguity, puns that don't translate)
|
||||
- Passages where literal translation would lose meaning
|
||||
- Content where the author's voice or humor requires creative adaptation
|
||||
|
||||
**Save `01-analysis.md`** with:
|
||||
```
|
||||
## Quick Summary
|
||||
[3-5 sentences]
|
||||
|
||||
## Core Content
|
||||
Core argument: [one sentence]
|
||||
Key concepts: [list]
|
||||
Structure: [outline]
|
||||
|
||||
## Background Context
|
||||
Author: [who, background, stance]
|
||||
Writing context: [what this responds to]
|
||||
Purpose: [goal and target audience]
|
||||
Implicit assumptions: [unstated premises]
|
||||
|
||||
## Terminology
|
||||
[term → translation, ...]
|
||||
|
||||
## Tone & Style
|
||||
[assessment]
|
||||
|
||||
## Comprehension Challenges
|
||||
- [term/passage] → [why confusing] → [proposed note]
|
||||
- ...
|
||||
|
||||
## Translation Challenges
|
||||
[structural issues, creative adaptation needs]
|
||||
```
|
||||
|
||||
## Step 2: Assemble Translation Prompt
|
||||
|
||||
Main agent reads `01-analysis.md` and assembles a complete translation prompt using [references/subagent-prompt-template.md](subagent-prompt-template.md). Inline content background, merged glossary, and comprehension challenges into the prompt. Save to `02-prompt.md`.
|
||||
|
||||
This prompt is used by the subagent (chunked) or by the main agent itself (non-chunked).
|
||||
|
||||
## Step 3: Initial Draft
|
||||
|
||||
Save to `03-draft.md` in the output directory.
|
||||
|
||||
For chunked content, the subagent produces this draft (merged from chunk translations). For non-chunked content, the main agent produces it directly.
|
||||
|
||||
Translate the full content following `02-prompt.md`:
|
||||
|
||||
- Use the terminology decisions from Step 1 consistently
|
||||
- Match the identified tone and register
|
||||
- Break complex sentences into natural target-language patterns
|
||||
- Preserve all formatting and structure
|
||||
- First occurrence of technical terms: translated term (original in parentheses)
|
||||
- Add translator's notes for comprehension challenges identified in Step 1: use parentheses with a plain-language explanation, e.g., `译文(English original,通俗解释)`
|
||||
- Only annotate where genuinely needed — do not over-explain obvious terms
|
||||
|
||||
## Step 4: Review
|
||||
|
||||
The main agent reviews the draft. Save reviewed version to `04-review.md`.
|
||||
|
||||
Systematically review against these criteria:
|
||||
|
||||
### Accuracy Check
|
||||
- Compare each paragraph against the original
|
||||
- Verify all facts, numbers, dates, and proper nouns
|
||||
- Ensure no content was accidentally added, removed, or altered
|
||||
- Check that technical terms match glossary consistently throughout
|
||||
|
||||
### Naturalness Check
|
||||
- Read the translation as if it were original content (not a translation)
|
||||
- Flag sentences that sound like "translationese" — awkward word order, calques, unnatural phrasing
|
||||
- Check paragraph transitions and logical flow
|
||||
- Verify sentence length feels natural for target language
|
||||
|
||||
### Terminology Consistency
|
||||
- Verify each glossary term is translated the same way throughout
|
||||
- Check proper nouns are handled consistently (transliterated vs. kept in original)
|
||||
- Verify annotations appear on first occurrence only
|
||||
|
||||
### Cultural Adaptation & Translator's Notes
|
||||
- Are cultural references explained where needed?
|
||||
- Do metaphors and idioms work in the target language?
|
||||
- Are any references potentially confusing or offensive in the target culture?
|
||||
- Check translator's notes: are they accurate, concise, and genuinely helpful?
|
||||
- Identify any missed comprehension challenges that should have notes
|
||||
- Remove over-annotations on terms that are obvious to the target audience
|
||||
|
||||
## Step 5: Polish
|
||||
|
||||
Save final version to `translation.md`.
|
||||
|
||||
Final pass addressing all issues from the review:
|
||||
|
||||
- Fix all accuracy issues found in review
|
||||
- Rewrite unnatural sentences for fluency
|
||||
- Improve transitions between paragraphs
|
||||
- Ensure the translation reads as engaging, native-quality content
|
||||
- Verify formatting is preserved correctly
|
||||
- For storytelling-style content: ensure the narrative flow draws readers in
|
||||
- Final consistency check on terminology
|
||||
|
||||
## Subagent Responsibility
|
||||
|
||||
Each subagent (one per chunk) is responsible **only** for producing the initial draft of its chunk (Step 3). The main agent assembles the shared prompt (Step 2), spawns all subagents in parallel, then takes over for review (Step 4) and polish (Step 5). The main agent may delegate review or polish to subagents at its own discretion.
|
||||
|
||||
## Chunked Refined Translation
|
||||
|
||||
When content exceeds the chunk threshold (see Defaults in SKILL.md) and uses refined mode:
|
||||
|
||||
1. Main agent runs analysis (Step 1) on the **entire** document first → `01-analysis.md`
|
||||
2. Main agent assembles translation prompt → `02-prompt.md`
|
||||
3. Split into chunks → `chunks/`
|
||||
4. Spawn one subagent per chunk in parallel (each reads `02-prompt.md` for shared context) → merge all results into `03-draft.md`
|
||||
5. Main agent reviews the merged draft → `04-review.md`
|
||||
6. Main agent polishes → `translation.md`
|
||||
7. Final cross-chunk consistency check:
|
||||
- Check terminology consistency across chunk boundaries
|
||||
- Verify narrative flow between chunks
|
||||
- Fix any transition issues at chunk boundaries
|
||||
@@ -0,0 +1,71 @@
|
||||
# Subagent Translation Prompt Template
|
||||
|
||||
Two parts:
|
||||
1. **`02-prompt.md`** — Shared context (saved to output directory). Contains background, glossary, challenges, and principles. No task-specific instructions.
|
||||
2. **Subagent spawn prompt** — Task instructions passed when spawning each subagent. One subagent per chunk (or per source file if non-chunked).
|
||||
|
||||
The main agent reads `01-analysis.md` (if exists), inlines all relevant context into `02-prompt.md`, then spawns subagents in parallel with task instructions referencing that file.
|
||||
|
||||
Replace `{placeholders}` with actual values. Omit sections marked "if analysis exists" for quick mode.
|
||||
|
||||
---
|
||||
|
||||
## Part 1: `02-prompt.md` (shared context, saved as file)
|
||||
|
||||
```markdown
|
||||
You are a professional translator. Your task is to translate markdown content from {source_lang} to {target_lang}.
|
||||
|
||||
## Target Audience
|
||||
|
||||
{audience description}
|
||||
|
||||
## Content Background
|
||||
|
||||
{Inlined from 01-analysis.md if analysis exists: quick summary, core argument, author background, writing context, tone assessment.}
|
||||
|
||||
## Glossary
|
||||
|
||||
Apply these term translations consistently throughout. First occurrence of each term: include the original in parentheses after the translation.
|
||||
|
||||
{Merged glossary — combine built-in glossary + EXTEND.md glossary + terms extracted in analysis. One per line: English → Translation}
|
||||
|
||||
## Comprehension Challenges
|
||||
|
||||
The following terms or references may confuse target readers. Add translator's notes in parentheses where they appear: `译文(English original,通俗解释)`
|
||||
|
||||
{Inlined from 01-analysis.md comprehension challenges section if analysis exists. Each entry: term → explanation to use as note.}
|
||||
|
||||
## Translation Principles
|
||||
|
||||
- **Accuracy first**: Facts, data, and logic must match the original exactly
|
||||
- **Natural flow**: Use idiomatic {target_lang} word order; break long sentences into shorter ones
|
||||
- **Terminology**: Use glossary translations consistently; annotate with original term in parentheses on first occurrence
|
||||
- **Preserve format**: Keep all markdown formatting (headings, bold, italic, images, links, code blocks)
|
||||
- **Respect original**: Maintain original structure and meaning; do not add, remove, or editorialize
|
||||
- **Translator's notes**: For terms or cultural references listed in Comprehension Challenges above, add a concise explanatory note in parentheses. Only annotate where genuinely needed for the target audience.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 2: Subagent spawn prompt (passed as Agent tool prompt)
|
||||
|
||||
### Chunked mode (one subagent per chunk, all spawned in parallel)
|
||||
|
||||
```
|
||||
Read the translation instructions from: {output_dir}/02-prompt.md
|
||||
|
||||
Translate this chunk:
|
||||
1. Read `{output_dir}/chunks/chunk-{NN}.md`
|
||||
2. Translate following the instructions in 02-prompt.md
|
||||
3. Save translation to `{output_dir}/chunks/chunk-{NN}-draft.md`
|
||||
```
|
||||
|
||||
### Non-chunked mode
|
||||
|
||||
```
|
||||
Read the translation instructions from: {output_dir}/02-prompt.md
|
||||
|
||||
Translate the source file and save the result:
|
||||
1. Read `{source_file_path}`
|
||||
2. Save translation to `{output_path}`
|
||||
```
|
||||
@@ -0,0 +1,161 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"unified": "^11.0.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
|
||||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||
|
||||
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
|
||||
|
||||
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
|
||||
|
||||
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
|
||||
|
||||
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
||||
|
||||
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||
|
||||
"fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="],
|
||||
|
||||
"format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="],
|
||||
|
||||
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
|
||||
|
||||
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
|
||||
|
||||
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
|
||||
|
||||
"mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="],
|
||||
|
||||
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="],
|
||||
|
||||
"mdast-util-frontmatter": ["mdast-util-frontmatter@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "escape-string-regexp": "^5.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-extension-frontmatter": "^2.0.0" } }, "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA=="],
|
||||
|
||||
"mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="],
|
||||
|
||||
"mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="],
|
||||
|
||||
"mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="],
|
||||
|
||||
"mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="],
|
||||
|
||||
"mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="],
|
||||
|
||||
"mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="],
|
||||
|
||||
"mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="],
|
||||
|
||||
"mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="],
|
||||
|
||||
"mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="],
|
||||
|
||||
"micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
|
||||
|
||||
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
|
||||
|
||||
"micromark-extension-frontmatter": ["micromark-extension-frontmatter@2.0.0", "", { "dependencies": { "fault": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg=="],
|
||||
|
||||
"micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="],
|
||||
|
||||
"micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="],
|
||||
|
||||
"micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="],
|
||||
|
||||
"micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="],
|
||||
|
||||
"micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="],
|
||||
|
||||
"micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="],
|
||||
|
||||
"micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="],
|
||||
|
||||
"micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="],
|
||||
|
||||
"micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="],
|
||||
|
||||
"micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="],
|
||||
|
||||
"micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="],
|
||||
|
||||
"micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="],
|
||||
|
||||
"micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
|
||||
|
||||
"micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="],
|
||||
|
||||
"micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="],
|
||||
|
||||
"micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="],
|
||||
|
||||
"micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="],
|
||||
|
||||
"micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="],
|
||||
|
||||
"micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="],
|
||||
|
||||
"micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="],
|
||||
|
||||
"micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="],
|
||||
|
||||
"micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="],
|
||||
|
||||
"micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="],
|
||||
|
||||
"micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="],
|
||||
|
||||
"micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
|
||||
|
||||
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"remark-frontmatter": ["remark-frontmatter@5.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-frontmatter": "^2.0.0", "micromark-extension-frontmatter": "^2.0.0", "unified": "^11.0.0" } }, "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ=="],
|
||||
|
||||
"remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="],
|
||||
|
||||
"remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="],
|
||||
|
||||
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
|
||||
|
||||
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
|
||||
|
||||
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
||||
|
||||
"unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
|
||||
|
||||
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
|
||||
|
||||
"unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
|
||||
|
||||
"unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
|
||||
|
||||
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
||||
|
||||
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { readFileSync, writeFileSync, mkdirSync } from "fs"
|
||||
import { basename, dirname, join } from "path"
|
||||
import { unified } from "unified"
|
||||
import remarkParse from "remark-parse"
|
||||
import remarkGfm from "remark-gfm"
|
||||
import remarkFrontmatter from "remark-frontmatter"
|
||||
import remarkStringify from "remark-stringify"
|
||||
import type { Root, Content } from "mdast"
|
||||
|
||||
const args = process.argv.slice(2)
|
||||
const file = args.find(a => !a.startsWith("--"))
|
||||
const maxWords = parseInt(args[args.indexOf("--max-words") + 1] || "5000")
|
||||
|
||||
if (!file) {
|
||||
console.error("Usage: chunk.ts <file> [--max-words 5000]")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const content = readFileSync(file, "utf-8")
|
||||
|
||||
const tree = unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
.use(remarkFrontmatter, ["yaml"])
|
||||
.parse(content)
|
||||
|
||||
const stringify = unified()
|
||||
.use(remarkStringify, { bullet: "-", emphasis: "*", strong: "*" })
|
||||
.use(remarkGfm)
|
||||
.use(remarkFrontmatter, ["yaml"])
|
||||
|
||||
function nodeToMd(node: Content): string {
|
||||
const root: Root = { type: "root", children: [node] }
|
||||
return stringify.stringify(root).trim()
|
||||
}
|
||||
|
||||
function countWords(text: string): number {
|
||||
const cleaned = text.replace(/[#*`\[\]()>|_~-]/g, " ")
|
||||
const cjk = cleaned.match(/[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/g)
|
||||
const latin = cleaned.match(/[a-zA-Z0-9]+/g)
|
||||
return (cjk?.length || 0) + (latin?.length || 0)
|
||||
}
|
||||
|
||||
interface Block {
|
||||
md: string
|
||||
words: number
|
||||
}
|
||||
|
||||
function splitNodeToBlocks(node: Content): Block[] {
|
||||
const md = nodeToMd(node)
|
||||
const words = countWords(md)
|
||||
|
||||
if (words <= maxWords) return [{ md, words }]
|
||||
|
||||
if (node.type === "heading" || node.type === "thematicBreak" || node.type === "html") {
|
||||
return [{ md, words }]
|
||||
}
|
||||
|
||||
if ("children" in node && Array.isArray(node.children)) {
|
||||
const blocks: Block[] = []
|
||||
for (const child of node.children as Content[]) {
|
||||
blocks.push(...splitNodeToBlocks(child))
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
const lines = md.split("\n")
|
||||
if (lines.length > 1) {
|
||||
const blocks: Block[] = []
|
||||
let buf: string[] = []
|
||||
let bufWords = 0
|
||||
for (const line of lines) {
|
||||
const lw = countWords(line)
|
||||
if (bufWords + lw > maxWords && buf.length > 0) {
|
||||
blocks.push({ md: buf.join("\n"), words: bufWords })
|
||||
buf = [line]
|
||||
bufWords = lw
|
||||
} else {
|
||||
buf.push(line)
|
||||
bufWords += lw
|
||||
}
|
||||
}
|
||||
if (buf.length > 0) blocks.push({ md: buf.join("\n"), words: bufWords })
|
||||
return blocks
|
||||
}
|
||||
|
||||
return [{ md, words }]
|
||||
}
|
||||
|
||||
let frontmatter = ""
|
||||
const blocks: Block[] = []
|
||||
|
||||
for (const node of tree.children) {
|
||||
if (node.type === "yaml") {
|
||||
frontmatter = `---\n${node.value}\n---`
|
||||
continue
|
||||
}
|
||||
blocks.push(...splitNodeToBlocks(node as Content))
|
||||
}
|
||||
|
||||
const chunks: { blocks: Block[]; words: number }[] = []
|
||||
let cur: Block[] = []
|
||||
let curWords = 0
|
||||
|
||||
for (const b of blocks) {
|
||||
if (curWords + b.words > maxWords && cur.length > 0) {
|
||||
chunks.push({ blocks: cur, words: curWords })
|
||||
cur = [b]
|
||||
curWords = b.words
|
||||
} else {
|
||||
cur.push(b)
|
||||
curWords += b.words
|
||||
}
|
||||
}
|
||||
if (cur.length > 0) chunks.push({ blocks: cur, words: curWords })
|
||||
|
||||
const dir = join(dirname(file), "chunks")
|
||||
mkdirSync(dir, { recursive: true })
|
||||
|
||||
chunks.forEach((chunk, i) => {
|
||||
const num = String(i + 1).padStart(2, "0")
|
||||
const out = join(dir, `chunk-${num}.md`)
|
||||
writeFileSync(out, chunk.blocks.map(b => b.md).join("\n\n"))
|
||||
})
|
||||
|
||||
console.log(JSON.stringify({
|
||||
source: file,
|
||||
chunks: chunks.length,
|
||||
output_dir: dir,
|
||||
frontmatter: !!frontmatter,
|
||||
words_per_chunk: chunks.map(c => c.words)
|
||||
}))
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"unified": "^11.0.5"
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ Fetches any URL via Chrome CDP and converts HTML to clean markdown.
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
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
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
@@ -23,16 +24,20 @@ Fetches any URL via Chrome CDP and converts HTML to clean markdown.
|
||||
|
||||
## Preferences (EXTEND.md)
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-url-to-markdown/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-url-to-markdown/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-url-to-markdown/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-url-to-markdown/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌────────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────────────────┼───────────────────┤
|
||||
@@ -81,8 +86,14 @@ Full reference: [references/config/first-time-setup.md](references/config/first-
|
||||
| `download_media` | `ask` | `ask` / `1` / `0` | `ask` = prompt each time, `1` = always download, `0` = never |
|
||||
| `default_output_dir` | empty | path or empty | Default output directory (empty = `./url-to-markdown/`) |
|
||||
|
||||
**EXTEND.md → CLI mapping**:
|
||||
| EXTEND.md key | CLI argument | Notes |
|
||||
|---------------|-------------|-------|
|
||||
| `download_media: 1` | `--download-media` | |
|
||||
| `default_output_dir: ./posts/` | `--output-dir ./posts/` | Directory path. Do NOT pass to `-o` (which expects a file path) |
|
||||
|
||||
**Value priority**:
|
||||
1. CLI arguments (`--download-media`, `-o`)
|
||||
1. CLI arguments (`--download-media`, `-o`, `--output-dir`)
|
||||
2. EXTEND.md
|
||||
3. Skill defaults
|
||||
|
||||
@@ -98,16 +109,19 @@ Full reference: [references/config/first-time-setup.md](references/config/first-
|
||||
|
||||
```bash
|
||||
# Auto mode (default) - capture when page loads
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url>
|
||||
|
||||
# Wait mode - wait for user signal before capture
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url> --wait
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --wait
|
||||
|
||||
# Save to specific file
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url> -o output.md
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> -o output.md
|
||||
|
||||
# Save to a custom output directory (auto-generates filename)
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --output-dir ./posts/
|
||||
|
||||
# Download images and videos to local directories
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts <url> --download-media
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --download-media
|
||||
```
|
||||
|
||||
## Options
|
||||
@@ -115,7 +129,8 @@ npx -y bun ${SKILL_DIR}/scripts/main.ts <url> --download-media
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `<url>` | URL to fetch |
|
||||
| `-o <path>` | Output file path (default: auto-generated) |
|
||||
| `-o <path>` | Output file path — must be a **file** path, not directory (default: auto-generated) |
|
||||
| `--output-dir <dir>` | Base output directory — auto-generates `{dir}/{domain}/{slug}.md` (default: `./url-to-markdown/`) |
|
||||
| `--wait` | Wait for user signal before capturing |
|
||||
| `--timeout <ms>` | Page load timeout (default: 30000) |
|
||||
| `--download-media` | Download image/video assets to local `imgs/` and `videos/`, and rewrite markdown links to local relative paths |
|
||||
@@ -138,9 +153,8 @@ YAML front matter with `url`, `title`, `description`, `author`, `published`, `ca
|
||||
|
||||
## Output Directory
|
||||
|
||||
```
|
||||
url-to-markdown/<domain>/<slug>.md
|
||||
```
|
||||
Default: `url-to-markdown/<domain>/<slug>.md`
|
||||
With `--output-dir ./posts/`: `./posts/<domain>/<slug>.md`
|
||||
|
||||
- `<slug>`: From page title or URL path (kebab-case, 2-6 words)
|
||||
- Conflict resolution: Append timestamp `<slug>-YYYYMMDD-HHMMSS.md`
|
||||
|
||||
@@ -25,6 +25,7 @@ async function fileExists(filePath: string): Promise<boolean> {
|
||||
interface Args {
|
||||
url: string;
|
||||
output?: string;
|
||||
outputDir?: string;
|
||||
wait: boolean;
|
||||
timeout: number;
|
||||
downloadMedia: boolean;
|
||||
@@ -40,6 +41,8 @@ function parseArgs(argv: string[]): Args {
|
||||
args.output = argv[++i];
|
||||
} else if (arg === "--timeout" || arg === "-t") {
|
||||
args.timeout = parseInt(argv[++i], 10) || DEFAULT_TIMEOUT_MS;
|
||||
} else if (arg === "--output-dir") {
|
||||
args.outputDir = argv[++i];
|
||||
} else if (arg === "--download-media") {
|
||||
args.downloadMedia = true;
|
||||
} else if (!arg.startsWith("-") && !args.url) {
|
||||
@@ -66,10 +69,10 @@ function formatTimestamp(): string {
|
||||
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
||||
}
|
||||
|
||||
async function generateOutputPath(url: string, title: string): Promise<string> {
|
||||
async function generateOutputPath(url: string, title: string, outputDir?: string): Promise<string> {
|
||||
const domain = new URL(url).hostname.replace(/^www\./, "");
|
||||
const slug = generateSlug(title, url);
|
||||
const dataDir = resolveUrlToMarkdownDataDir();
|
||||
const dataDir = outputDir ? path.resolve(outputDir) : resolveUrlToMarkdownDataDir();
|
||||
const basePath = path.join(dataDir, domain, `${slug}.md`);
|
||||
|
||||
if (!(await fileExists(basePath))) {
|
||||
@@ -149,11 +152,19 @@ async function main(): Promise<void> {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (args.output) {
|
||||
const stat = await import("node:fs").then(fs => fs.statSync(args.output!, { throwIfNoEntry: false }));
|
||||
if (stat?.isDirectory()) {
|
||||
console.error(`Error: -o path is a directory, not a file: ${args.output}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Fetching: ${args.url}`);
|
||||
console.log(`Mode: ${args.wait ? "wait" : "auto"}`);
|
||||
|
||||
const result = await captureUrl(args);
|
||||
const outputPath = args.output || await generateOutputPath(args.url, result.metadata.title);
|
||||
const outputPath = args.output || await generateOutputPath(args.url, result.metadata.title, args.outputDir);
|
||||
const outputDir = path.dirname(outputPath);
|
||||
await mkdir(outputDir, { recursive: true });
|
||||
|
||||
|
||||
@@ -199,16 +199,20 @@ Analyze → [Confirm 1] → 3 Outlines → [Confirm 2: Outline + Style + Element
|
||||
|
||||
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about style, do NOT ask about layout — ONLY complete the preferences setup first.
|
||||
|
||||
Use Bash to check EXTEND.md existence (priority order):
|
||||
Check EXTEND.md existence (priority order):
|
||||
|
||||
```bash
|
||||
# Check project-level first
|
||||
# macOS, Linux, WSL, Git Bash
|
||||
test -f .baoyu-skills/baoyu-xhs-images/EXTEND.md && echo "project"
|
||||
|
||||
# Then user-level (cross-platform: $HOME works on macOS/Linux/WSL)
|
||||
test -f "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md" && echo "user"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell (Windows)
|
||||
if (Test-Path .baoyu-skills/baoyu-xhs-images/EXTEND.md) { "project" }
|
||||
if (Test-Path "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md") { "user" }
|
||||
```
|
||||
|
||||
┌────────────────────────────────────────────────────┬───────────────────┐
|
||||
│ Path │ Location │
|
||||
├────────────────────────────────────────────────────┼───────────────────┤
|
||||
|
||||
@@ -167,7 +167,7 @@ When generating multiple images in a series:
|
||||
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:
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/main.ts \
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts \
|
||||
--promptfiles prompts/02-content-xxx.md \
|
||||
--ref path/to/01-cover-xxx.png \
|
||||
--image 02-content-xxx.png --ar 3:4 --quality 2k
|
||||
|
||||
Reference in New Issue
Block a user