Skill: runmanfm-bit/mermaid-workflow-skill (version 1.0.0)

# Mermaid Workflow Skill ## 描述 按照新的工作流程创建和处理Mermaid图表：先生成Mermaid格式的图表定义文件(.mmd)，然后调用终端命令运行mmdc (Mermaid CLI)将.mmd转换为PNG，最后将图片链接插入Markdown文件对应的位置。 ## 激活条件 当用户需要创建或处理以下类型的图表时激活此技能： - 技术路线图 - 系统架构图 - 流程图 - 序列图 - 类图 - 状态图 - 甘特图 - ER图 - 以及其他Mermaid支持的图表类型 ## 核心工作流程 1. **创建Mermaid定义文件** (.mmd) 2. **转换为PNG图片** (使用mmdc CLI) 3. **插入Markdown文件** (替换占位符或插入到指定位置) ## 文件结构 ``` mermaid-workflow-skill/ ├── SKILL.md (本文件) ├── scripts/ │ ├── create_mermaid.py (创建Mermaid图表) │ ├── convert_mermaid.py (转换Mermaid为PNG) │ └── insert_to_md.py (插入图片到Markdown) ├── templates/ │ ├── roadmap.mmd (技术路线图模板) │ ├── architecture.mmd (系统架构图模板) │ ├── flowchart.mmd (流程图模板) │ └── sequence.mmd (序列图模板) └── examples/ ├── example_roadmap.mmd (示例路线图) ├── example_architecture.mmd (示例架构图) └── example_output.md (示例输出) ``` ## 依赖要求 - **Mermaid CLI (mmdc)**: 必须安装并配置好 - **Python 3.8+**: 用于运行脚本 - **Puppeteer配置**: 用于解决mmdc沙箱问题 ## 安装和配置 ### 1. 安装Mermaid CLI ```bash # 全局安装 npm install -g @mermaid-js/mermaid-cli # 或者使用npx npx @mermaid-js/mermaid-cli ``` ### 2. 验证安装 ```bash mmdc --version # 应该显示版本号，如：11.12.0 ``` ### 3. 解决沙箱问题 创建Puppeteer配置文件： ```json { "args": ["--no-sandbox", "--disable-setuid-sandbox"] } ``` ## 使用方法 ### 基本使用流程 #### 1. 创建Mermaid图表定义文件 ```bash python scripts/create_mermaid.py --type roadmap --title "技术路线图" --output roadmap.mmd ``` #### 2. 转换为PNG图片 ```bash python scripts/convert_mermaid.py --input roadmap.mmd --output roadmap.png ``` #### 3. 插入到Markdown文件 ```bash python scripts/insert_to_md.py --md-file report.md --image roadmap.png --placeholder "[ROADMAP]" ``` ### 完整示例 #### 示例1: 创建技术路线图 ```bash # 1. 创建路线图定义 python scripts/create_mermaid.py \ --type roadmap \ --title "AI开发技术路线图" \ --phases "2024 Q1:基础研究,2024 Q2:原型开发,2024 Q3:测试验证,2024 Q4:产品发布" \ --output ai_roadmap.mmd # 2. 转换为PNG python scripts/convert_mermaid.py \ --input ai_roadmap.mmd \ --output ai_roadmap.png \ --width 1200 \ --height 800 # 3. 插入到Markdown python scripts/insert_to_md.py \ --md-file ai_report.md \ --image ai_roadmap.png \ --section "## 技术路线图" ``` #### 示例2: 创建系统架构图 ```bash # 1. 创建架构图定义 python scripts/create_mermaid.py \ --type architecture \ --title "微服务系统架构" \ --layers "前端:React,网关:API Gateway,服务:UserService,OrderService,数据:MySQL,Redis" \ --output architecture.mmd # 2. 转换为PNG python scripts/convert_mermaid.py --input architecture.mmd --output architecture.png # 3. 插入到Markdown python scripts/insert_to_md.py --md-file design.md --image architecture.png ``` ## 脚本详细说明 ### 1. create_mermaid.py 创建各种类型的Mermaid图表定义文件。 **参数:** - `--type`: 图表类型 (roadmap, architecture, flowchart, sequence, class, state, gantt, er) - `--title`: 图表标题 - `--output`: 输出文件路径 - 其他类型特定参数 **支持的图表类型:** 1. **roadmap**: 技术路线图 2. **architecture**: 系统架构图 3. **flowchart**: 流程图 4. **sequence**: 序列图 5. **class**: 类图 6. **state**: 状态图 7. **gantt**: 甘特图 8. **er**: ER图 ### 2. convert_mermaid.py 将.mmd文件转换为PNG图片。 **参数:** - `--input`: 输入.mmd文件 - `--output`: 输出.png文件 - `--width`: 图片宽度 (默认1200) - `--height`: 图片高度 (默认800) - `--theme`: 主题 (default, forest, dark, neutral) - `--background`: 背景颜色 (默认白色) ### 3. insert_to_md.py 将PNG图片插入到Markdown文件。 **参数:** - `--md-file`: Markdown文件路径 - `--image`: 图片文件路径 - `--placeholder`: 要替换的占位符 (可选) - `--section`: 要插入的章节标题 (可选) - `--caption`: 图片标题 (可选) - `--position`: 插入位置 (before, after, replace) ## 模板系统 ### 路线图模板 (roadmap.mmd) ```mermaid %%{init: {'theme': 'default', 'themeVariables': { 'primaryColor': '#007bff', 'primaryTextColor': '#fff', 'primaryBorderColor': '#0056b3', 'lineColor': '#333', 'tertiaryColor': '#f8f9fa'}}}%% gantt title {{TITLE}} dateFormat YYYY-MM axisFormat %Y年%m月 section 第一阶段 任务1 :a1, {{START_DATE}}, {{DURATION_1}} section 第二阶段 任务2 :after a1, {{DURATION_2}} section 第三阶段 任务3 :after a2, {{DURATION_3}} ``` ### 架构图模板 (architecture.mmd) ```mermaid graph TB subgraph "{{FRONTEND_TITLE}}" A[{{FRONTEND_COMPONENT}}] end subgraph "{{API_TITLE}}" B[{{API_COMPONENT}}] end subgraph "{{SERVICE_TITLE}}" C[{{SERVICE_1}}] D[{{SERVICE_2}}] end subgraph "{{DATA_TITLE}}" E[({{DATABASE}})] F[{{CACHE}}] end A --> B B --> C B --> D C --> E D --> E C --> F D --> F ``` ## 集成到OpenClaw工作流 ### 作为独立技能使用 ```python # 在OpenClaw会话中调用 exec("python /path/to/mermaid-workflow-skill/scripts/create_mermaid.py --type roadmap --output roadmap.mmd") ``` ### 作为其他技能的组件 ```python # 在其他技能中集成Mermaid图表生成 def generate_technical_report(): # 1. 创建路线图 create_mermaid_chart("roadmap", "项目路线图") # 2. 转换为图片 convert_to_png("roadmap.mmd", "roadmap.png") # 3. 插入到报告 insert_image_to_md("report.md", "roadmap.png", "## 项目路线图") ``` ## 故障排除 ### 常见问题 #### 1. mmdc命令找不到 ```bash # 检查是否安装 which mmdc # 如果使用npx npx @mermaid-js/mermaid-cli --version ``` #### 2. 沙箱错误 ``` Error: Failed to launch the browser process! No usable sandbox! ``` **解决方案:** 使用Puppeteer配置文件 ```bash mmdc -i input.mmd -o output.png -p puppeteer-config.json ``` #### 3. 中文显示问题 **解决方案:** 确保系统安装了中文字体 ```bash # Ubuntu/Debian sudo apt-get install fonts-wqy-zenhei # 或者在mmdc命令中指定字体 mmdc -i input.mmd -o output.png --fontFamily "WenQuanYi Zen Hei" ``` #### 4. 图片质量不佳 **解决方案:** 增加图片尺寸和DPI ```bash mmdc -i input.mmd -o output.png -w 2000 -H 1400 --scale 2 ``` ## 最佳实践 ### 1. 文件命名规范 - 使用有意义的文件名: `project_roadmap.mmd`, `system_architecture.png` - 包含版本信息: `v1.0_architecture.mmd` - 使用日期戳: `20240302_roadmap.mmd` ### 2. 版本控制 - 将.mmd文件纳入版本控制 - PNG图片可以忽略（可重新生成） - 在README中记录图表生成命令 ### 3. 文档化 - 为每个图表添加注释说明 - 在Markdown中提供图表说明文字 - 维护图表变更日志 ### 4. 自动化集成 - 在CI/CD中集成图表生成 - 使用Makefile或脚本自动化流程 - 设置图表生成触发器 ## 扩展功能 ### 批量处理 ```bash # 批量转换所有.mmd文件 for file in *.mmd; do python scripts/convert_mermaid.py --input "$file" --output "${file%.mmd}.png" done ``` ### 监控和日志 ```python # 添加日志记录 import logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') ``` ### 质量检查 ```python # 检查图表语法 def validate_mermaid_syntax(mmd_content): # 实现语法检查逻辑 pass ``` ## 示例项目 ### 完整工作流示例 ```bash # 创建项目目录 mkdir -p my_project/charts cd my_project # 1. 创建技术路线图 python ../mermaid-workflow-skill/scripts/create_mermaid.py \ --type roadmap \ --title "产品开发路线图" \ --output charts/product_roadmap.mmd # 2. 创建系统架构图 python ../mermaid-workflow-skill/scripts/create_mermaid.py \ --type architecture \ --title "系统架构" \ --output charts/system_architecture.mmd # 3. 转换为PNG for mmd in charts/*.mmd; do python ../mermaid-workflow-skill/scripts/convert_mermaid.py \ --input "$mmd" \ --output "${mmd%.mmd}.png" done # 4. 创建Markdown报告 cat > report.md << EOF # 项目报告 ## 技术路线图 ![产品开发路线图](charts/product_roadmap.png) ## 系统架构 ![系统架构图](charts/system_architecture.png) EOF # 5. 插入图片（如果需要自动化插入） python ../mermaid-workflow-skill/scripts/insert_to_md.py \ --md-file report.md \ --image charts/product_roadmap.png \ --section "## 技术路线图" ``` ## 更新日志 ### v1.0.0 (2026-03-02) - 初始版本发布 - 支持8种Mermaid图表类型 - 完整的创建-转换-插入工作流 - 模板系统和示例 ## 贡献指南 1. Fork项目 2. 创建功能分支 3. 提交更改 4. 创建Pull Request ## 许可证 MIT License

path: README.md
content: # Mermaid Workflow Skill

一个专门用于按照新工作流程创建和处理Mermaid图表的OpenClaw技能。

## 核心工作流程

1. **创建Mermaid定义文件** (.mmd)
2. **转换为PNG图片** (使用mmdc CLI)
3. **插入Markdown文件** (替换占位符或插入到指定位置)

## 快速开始

### 1. 安装依赖

```bash
# 安装Mermaid CLI
npm install -g @mermaid-js/mermaid-cli

# 或使用npx（无需安装）
npx @mermaid-js/mermaid-cli --version
```

### 2. 运行快速开始示例

```bash
cd /path/to/mermaid-workflow-skill
./quick_start.sh
```

### 3. 验证安装

```bash
# 检查mmdc
mmdc --version

# 检查Python脚本
python3 scripts/create_mermaid.py --help
```

## 使用方法

### 基本命令

#### 创建图表定义
```bash
python scripts/create_mermaid.py \
  --type roadmap \
  --title "技术路线图" \
  --output chart.mmd
```

#### 转换为PNG
```bash
python scripts/convert_mermaid.py \
  --input chart.mmd \
  --output chart.png
```

#### 插入到Markdown
```bash
python scripts/insert_to_md.py \
  --md-file report.md \
  --image chart.png \
  --placeholder "[CHART_PLACEHOLDER]"
```

### 支持的图表类型

- `roadmap`: 技术路线图（甘特图）
- `architecture`: 系统架构图
- `flowchart`: 流程图
- `sequence`: 序列图
- `class`: 类图
- `state`: 状态图
- `gantt`: 甘特图
- `er`: ER图

## 集成到OpenClaw

### 作为独立技能使用

在OpenClaw会话中直接调用：

```python
# 创建路线图
exec("python /path/to/mermaid-workflow-skill/scripts/create_mermaid.py --type roadmap --output roadmap.mmd")

# 转换为图片
exec("python /path/to/mermaid-workflow-skill/scripts/convert_mermaid.py --input roadmap.mmd --output roadmap.png")

# 插入到文档
exec("python /path/to/mermaid-workflow-skill/scripts/insert_to_md.py --md-file report.md --image roadmap.png --section '## 路线图'")
```

### 在技能中集成

在其他技能中调用Mermaid工作流：

```python
def generate_technical_document():
    # 创建图表
    create_mermaid_chart("roadmap", "项目路线图")
    
    # 转换为图片
    convert_to_png("roadmap.mmd", "roadmap.png")
    
    # 插入到文档
    insert_image_to_md("document.md", "roadmap.png", "## 项目路线图")
```

## 文件结构

```
mermaid-workflow-skill/
├── SKILL.md                    # 技能定义文件
├── README.md                   # 本文档
├── quick_start.sh              # 快速开始脚本
├── scripts/
│   ├── create_mermaid.py       # 创建Mermaid图表
│   ├── convert_mermaid.py      # 转换为PNG
│   └── insert_to_md.py         # 插入到Markdown
├── templates/                  # 图表模板
│   ├── roadmap.mmd
│   ├── architecture.mmd
│   └── flowchart.mmd
└── examples/                   # 示例文件
    └── example_workflow.md
```

## 配置

### Puppeteer配置文件

解决mmdc沙箱问题：

```json
{
  "args": ["--no-sandbox", "--disable-setuid-sandbox"]
}
```

使用配置文件：
```bash
python scripts/convert_mermaid.py --input chart.mmd --output chart.png --puppeteer-config puppeteer-config.json
```

### 环境变量

可以设置以下环境变量：

```bash
export MERMAID_THEME="forest"
export MERMAID_WIDTH="1600"
export MERMAID_HEIGHT="900"
```

## 故障排除

### 常见问题

1. **mmdc命令未找到**
   ```bash
   # 使用npx
   npx @mermaid-js/mermaid-cli --version
   
   # 或全局安装
   npm install -g @mermaid-js/mermaid-cli
   ```

2. **沙箱错误**
   ```
   Error: Failed to launch the browser process! No usable sandbox!
   ```
   创建Puppeteer配置文件并指定：
   ```bash
   python scripts/convert_mermaid.py --puppeteer-config puppeteer-config.json
   ```

3. **中文显示问题**
   ```bash
   # Ubuntu安装中文字体
   sudo apt-get install fonts-wqy-zenhei
   
   # 或在命令中指定字体
   mmdc --fontFamily "WenQuanYi Zen Hei"
   ```

4. **图片质量不佳**
   ```bash
   # 增加尺寸和DPI
   python scripts/convert_mermaid.py --width 2000 --height 1400
   ```

## 高级用法

### 批量处理

```bash
# 批量创建图表
for type in roadmap architecture flowchart; do
    python scripts/create_mermaid.py --type $type --output ${type}.mmd
done

# 批量转换
python scripts/convert_mermaid.py --input ./ --output ./png/ --batch

# 批量插入
python scripts/insert_to_md.py --md-file report.md --image-dir ./png/ --batch --placeholder-prefix "["
```

### 自定义模板

修改`templates/`目录中的模板文件：

```mermaid
%% templates/custom.mmd
graph TB
    A[自定义节点]
    B{自定义决策}
    C(自定义流程)
    
    A --> B
    B -->|是| C
    B -->|否| A
```

### 自动化工作流

创建自动化脚本：

```bash
#!/bin/bash
# automate_workflow.sh

# 1. 创建图表
python scripts/create_mermaid.py --type "$1" --title "$2" --output "$3.mmd"

# 2. 转换为图片
python scripts/convert_mermaid.py --input "$3.mmd" --output "$3.png"

# 3. 插入到文档
python scripts/insert_to_md.py --md-file "$4" --image "$3.png" --section "$5"

echo "✅ 工作流完成: $3"
```

## 示例

### 完整工作流示例

```bash
# 创建项目目录
mkdir -p my_project
cd my_project

# 1. 创建图表
python ../mermaid-workflow-skill/scripts/create_mermaid.py \
  --type roadmap \
  --title "产品开发路线图" \
  --output product_roadmap.mmd

# 2. 转换为图片
python ../mermaid-workflow-skill/scripts/convert_mermaid.py \
  --input product_roadmap.mmd \
  --output product_roadmap.png

# 3. 创建报告
cat > report.md << EOF
# 项目报告

## 技术路线图
![产品开发路线图](product_roadmap.png)
EOF

echo "✅ 工作流完成！"
```

## 许可证

MIT License

## 贡献

欢迎提交Issue和Pull Request！

1. Fork项目
2. 创建功能分支
3. 提交更改
4. 创建Pull Request

path: examples/example_workflow.md
content: # Mermaid工作流示例

本文档演示如何使用Mermaid工作流技能创建和插入图表。

## 技术路线图

[ROADMAP_PLACEHOLDER]

## 系统架构

[ARCHITECTURE_PLACEHOLDER]

## 处理流程

[FLOWCHART_PLACEHOLDER]

## 使用说明

### 1. 创建Mermaid图表定义

```bash
# 创建技术路线图
python scripts/create_mermaid.py \
  --type roadmap \
  --title "项目开发路线图" \
  --output examples/project_roadmap.mmd

# 创建系统架构图
python scripts/create_mermaid.py \
  --type architecture \
  --title "微服务架构" \
  --output examples/system_architecture.mmd

# 创建流程图
python scripts/create_mermaid.py \
  --type flowchart \
  --title "用户注册流程" \
  --output examples/user_flowchart.mmd
```

### 2. 转换为PNG图片

```bash
# 转换单个文件
python scripts/convert_mermaid.py \
  --input examples/project_roadmap.mmd \
  --output examples/project_roadmap.png

# 批量转换
python scripts/convert_mermaid.py \
  --input examples/ \
  --output examples/png/ \
  --batch
```

### 3. 插入到Markdown文件

```bash
# 替换占位符
python scripts/insert_to_md.py \
  --md-file examples/example_workflow.md \
  --image examples/project_roadmap.png \
  --placeholder "[ROADMAP_PLACEHOLDER]" \
  --caption "项目开发路线图"

# 插入到指定章节
python scripts/insert_to_md.py \
  --md-file examples/example_workflow.md \
  --image examples/system_architecture.png \
  --section "## 系统架构" \
  --caption "微服务系统架构"

# 批量插入
python scripts/insert_to_md.py \
  --md-file examples/example_workflow.md \
  --image-dir examples/png/ \
  --batch \
  --placeholder-prefix "["
```

### 4. 完整工作流脚本

```bash
#!/bin/bash
# 完整工作流示例

# 创建图表定义
python scripts/create_mermaid.py --type roadmap --title "示例路线图" --output chart1.mmd
python scripts/create_mermaid.py --type architecture --title "示例架构" --output chart2.mmd

# 转换为PNG
python scripts/convert_mermaid.py --input chart1.mmd --output chart1.png
python scripts/convert_mermaid.py --input chart2.mmd --output chart2.png

# 创建Markdown文件
cat > report.md << EOF
# 项目报告

## 路线图
[CHART_1]

## 架构图
[CHART_2]
EOF

# 插入图片
python scripts/insert_to_md.py --md-file report.md --image chart1.png --placeholder "[CHART_1]"
python scripts/insert_to_md.py --md-file report.md --image chart2.png --placeholder "[CHART_2]"

echo "✅ 工作流完成！"
```

## 注意事项

1. **文件路径**: 确保使用正确的相对路径或绝对路径
2. **占位符**: 在Markdown中使用唯一的占位符
3. **图片大小**: 根据需要调整图片尺寸
4. **版本控制**: 建议将.mmd文件纳入版本控制，PNG文件可以忽略

## 故障排除

### 问题1: mmdc命令未找到
```bash
# 检查安装
which mmdc

# 使用npx
npx @mermaid-js/mermaid-cli --version
```

### 问题2: 沙箱错误
创建`puppeteer-config.json`:
```json
{
  "args": ["--no-sandbox", "--disable-setuid-sandbox"]
}
```

### 问题3: 中文显示问题
```bash
# 安装中文字体（Ubuntu）
sudo apt-get install fonts-wqy-zenhei

# 或在mmdc命令中指定字体
mmdc --fontFamily "WenQuanYi Zen Hei"
```

## 扩展功能

### 自定义模板
可以修改`templates/`目录中的模板文件，添加自己的样式和布局。

### 自动化脚本
可以创建自动化脚本，将图表生成集成到CI/CD流程中。

### 质量检查
可以添加图表语法检查和验证功能。

path: quick_start.sh
content: #!/bin/bash
# Mermaid工作流技能快速开始脚本

echo "========================================"
echo "Mermaid工作流技能 - 快速开始"
echo "========================================"

# 检查Python
if ! command -v python3 &> /dev/null; then
    echo "❌ Python3未安装"
    exit 1
fi

echo "✅ Python3已安装: $(python3 --version)"

# 检查mmdc
if ! command -v mmdc &> /dev/null; then
    echo "⚠️ Mermaid CLI (mmdc) 未安装"
    echo "请安装: npm install -g @mermaid-js/mermaid-cli"
    echo "或使用npx: npx @mermaid-js/mermaid-cli"
    read -p "是否继续？(y/n): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 1
    fi
else
    echo "✅ Mermaid CLI已安装: $(mmdc --version)"
fi

# 创建示例目录
EXAMPLE_DIR="quick_start_example"
mkdir -p "$EXAMPLE_DIR"
cd "$EXAMPLE_DIR"

echo ""
echo "1. 创建Mermaid图表定义文件..."
python3 ../scripts/create_mermaid.py \
  --type roadmap \
  --title "快速开始示例路线图" \
  --output example_roadmap.mmd

python3 ../scripts/create_mermaid.py \
  --type architecture \
  --title "示例系统架构" \
  --output example_architecture.mmd

echo "✅ 图表定义文件已创建"

echo ""
echo "2. 转换为PNG图片..."
# 创建Puppeteer配置文件
cat > puppeteer-config.json << EOF
{
  "args": ["--no-sandbox", "--disable-setuid-sandbox"]
}
EOF

python3 ../scripts/convert_mermaid.py \
  --input example_roadmap.mmd \
  --output example_roadmap.png \
  --puppeteer-config puppeteer-config.json

python3 ../scripts/convert_mermaid.py \
  --input example_architecture.mmd \
  --output example_architecture.png \
  --puppeteer-config puppeteer-config.json

echo "✅ PNG图片已生成"

echo ""
echo "3. 创建Markdown报告..."
cat > example_report.md << 'EOF'
# 示例报告

## 项目路线图
[ROADMAP_IMAGE]

## 系统架构
[ARCHITECTURE_IMAGE]

## 说明
这是一个使用Mermaid工作流技能生成的示例报告。
EOF

echo "✅ Markdown报告已创建"

echo ""
echo "4. 插入图片到报告..."
python3 ../scripts/insert_to_md.py \
  --md-file example_report.md \
  --image example_roadmap.png \
  --placeholder "[ROADMAP_IMAGE]" \
  --caption "项目开发路线图"

python3 ../scripts/insert_to_md.py \
  --md-file example_report.md \
  --image example_architecture.png \
  --placeholder "[ARCHITECTURE_IMAGE]" \
  --caption "系统架构图"

echo "✅ 图片已插入到报告"

echo ""
echo "5. 查看生成的文件..."
echo "生成的文件:"
ls -la *.mmd *.png *.md

echo ""
echo "========================================"
echo "✅ 快速开始完成！"
echo "生成的文件在: $EXAMPLE_DIR/"
echo ""
echo "查看报告:"
echo "  cat $EXAMPLE_DIR/example_report.md"
echo ""
echo "清理示例:"
echo "  rm -rf $EXAMPLE_DIR"
echo "========================================"

path: quick_start_example/example_report.md
content: # 示例报告

## 项目路线图
[ROADMAP_IMAGE]

## 系统架构
[ARCHITECTURE_IMAGE]

## 说明
这是一个使用Mermaid工作流技能生成的示例报告。


path: quick_start_example/puppeteer-config.json
content: {
  "args": ["--no-sandbox", "--disable-setuid-sandbox"]
}


path: scripts/convert_mermaid.py
content: #!/usr/bin/env python3
"""
将Mermaid图表定义文件(.mmd)转换为PNG图片
使用mmdc (Mermaid CLI)进行转换
"""

import os
import sys
import argparse
import subprocess
from pathlib import Path
import tempfile
import json

def check_mmdc_installed():
    """检查mmdc是否安装"""
    try:
        result = subprocess.run(['mmdc', '--version'], 
                              capture_output=True, text=True)
        if result.returncode == 0:
            version = result.stdout.strip()
            print(f"✅ Mermaid CLI已安装: {version}")
            return True
        else:
            print("❌ Mermaid CLI未正确安装")
            return False
    except FileNotFoundError:
        print("❌ Mermaid CLI未安装")
        print("请安装: npm install -g @mermaid-js/mermaid-cli")
        return False

def create_puppeteer_config(config_path):
    """创建Puppeteer配置文件解决沙箱问题"""
    config = {
        "args": ["--no-sandbox", "--disable-setuid-sandbox"]
    }
    
    with open(config_path, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2)
    
    print(f"✅ Puppeteer配置文件已创建: {config_path}")
    return config_path

def convert_mermaid_to_png(input_file, output_file, width=1200, height=800, 
                          theme='default', background='white', puppeteer_config=None):
    """
    将Mermaid文件转换为PNG图片
    """
    if not Path(input_file).exists():
        print(f"❌ 输入文件不存在: {input_file}")
        return False
    
    # 确保输出目录存在
    output_path = Path(output_file)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    
    # 构建mmdc命令
    cmd = [
        'mmdc',
        '-i', str(input_file),
        '-o', str(output_file),
        '-w', str(width),
        '-H', str(height),
        '-b', background
    ]
    
    # 添加主题
    if theme != 'default':
        cmd.extend(['-t', theme])
    
    # 添加Puppeteer配置
    if puppeteer_config:
        cmd.extend(['-p', str(puppeteer_config)])
    
    print(f"执行命令: {' '.join(cmd)}")
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        
        if result.returncode == 0:
            print(f"✅ Mermaid图表已转换为PNG: {output_file}")
            
            # 检查文件大小
            if output_path.exists():
                file_size = output_path.stat().st_size / 1024  # KB
                print(f"   文件大小: {file_size:.1f} KB")
                print(f"   尺寸: {width}×{height} 像素")
                return True
            else:
                print("❌ 转换成功但输出文件未创建")
                return False
        else:
            print(f"❌ Mermaid转换失败 (退出码: {result.returncode})")
            print(f"错误输出: {result.stderr}")
            
            # 尝试使用npx
            print("尝试使用npx...")
            cmd[0] = 'npx'
            cmd.insert(1, '@mermaid-js/mermaid-cli')
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            if result.returncode == 0:
                print(f"✅ 使用npx转换成功: {output_file}")
                return True
            else:
                print(f"❌ npx转换也失败: {result.stderr}")
                return False
                
    except subprocess.TimeoutExpired:
        print("❌ 转换超时 (30秒)")
        return False
    except Exception as e:
        print(f"❌ 转换过程中发生错误: {e}")
        return False

def batch_convert_mermaid_files(input_dir, output_dir, **kwargs):
    """
    批量转换Mermaid文件
    """
    input_dir = Path(input_dir)
    output_dir = Path(output_dir)
    
    if not input_dir.exists():
        print(f"❌ 输入目录不存在: {input_dir}")
        return False
    
    # 确保输出目录存在
    output_dir.mkdir(parents=True, exist_ok=True)
    
    # 查找所有.mmd文件
    mmd_files = list(input_dir.glob("*.mmd"))
    
    if not mmd_files:
        print(f"❌ 在 {input_dir} 中没有找到.mmd文件")
        return False
    
    print(f"找到 {len(mmd_files)} 个Mermaid文件")
    print("=" * 60)
    
    success_count = 0
    
    for mmd_file in mmd_files:
        output_file = output_dir / f"{mmd_file.stem}.png"
        
        print(f"正在转换: {mmd_file.name}")
        
        if convert_mermaid_to_png(mmd_file, output_file, **kwargs):
            success_count += 1
        
        print("-" * 40)
    
    print(f"\n转换完成: {success_count}/{len(mmd_files)} 个文件转换成功")
    return success_count > 0

def main():
    parser = argparse.ArgumentParser(description='将Mermaid图表转换为PNG图片')
    parser.add_argument('--input', required=True, help='输入.mmd文件或目录')
    parser.add_argument('--output', help='输出.png文件（批量模式时为目录）')
    parser.add_argument('--width', type=int, default=1200, help='图片宽度（默认1200）')
    parser.add_argument('--height', type=int, default=800, help='图片高度（默认800）')
    parser.add_argument('--theme', default='default', 
                       choices=['default', 'forest', 'dark', 'neutral'],
                       help='图表主题（默认default）')
    parser.add_argument('--background', default='white', help='背景颜色（默认白色）')
    parser.add_argument('--puppeteer-config', help='Puppeteer配置文件路径')
    parser.add_argument('--batch', action='store_true', help='批量模式（转换目录中的所有.mmd文件）')
    parser.add_argument('--create-config', action='store_true', help='创建Puppeteer配置文件')
    
    args = parser.parse_args()
    
    print("=" * 60)
    print("Mermaid图表转换工具")
    print("=" * 60)
    
    # 检查mmdc是否安装
    if not check_mmdc_installed():
        sys.exit(1)
    
    # 创建Puppeteer配置文件（如果需要）
    puppeteer_config = args.puppeteer_config
    if args.create_config and not puppeteer_config:
        config_path = Path.home() / '.mermaid-puppeteer-config.json'
        puppeteer_config = create_puppeteer_config(config_path)
    
    # 批量模式
    if args.batch:
        input_path = Path(args.input)
        
        if input_path.is_file():
            print("❌ 批量模式需要目录作为输入")
            sys.exit(1)
        
        output_dir = args.output if args.output else input_path / "png_output"
        
        success = batch_convert_mermaid_files(
            input_path, output_dir,
            width=args.width,
            height=args.height,
            theme=args.theme,
            background=args.background,
            puppeteer_config=puppeteer_config
        )
        
        if success:
            print(f"\n✅ 批量转换完成！")
            print(f"输出目录: {output_dir}")
        else:
            print("\n❌ 批量转换失败")
            sys.exit(1)
    
    # 单文件模式
    else:
        input_path = Path(args.input)
        
        if not input_path.exists():
            print(f"❌ 输入文件不存在: {input_path}")
            sys.exit(1)
        
        if input_path.is_dir():
            print("❌ 单文件模式需要文件作为输入，使用 --batch 进行批量转换")
            sys.exit(1)
        
        # 确定输出文件路径
        if args.output:
            output_path = Path(args.output)
        else:
            output_path = input_path.with_suffix('.png')
        
        success = convert_mermaid_to_png(
            input_path, output_path,
            width=args.width,
            height=args.height,
            theme=args.theme,
            background=args.background,
            puppeteer_config=puppeteer_config
        )
        
        if success:
            print(f"\n✅ 转换完成！")
            print(f"输出文件: {output_path}")
        else:
            print("\n❌ 转换失败")
            sys.exit(1)

if __name__ == "__main__":
    main()

path: scripts/create_mermaid.py
content: #!/usr/bin/env python3
"""
创建Mermaid图表定义文件(.mmd)
支持多种图表类型：roadmap, architecture, flowchart, sequence, class, state, gantt, er
"""

import os
import sys
import argparse
from pathlib import Path
import json
from datetime import datetime

# 添加脚本目录到路径
sys.path.insert(0, str(Path(__file__).parent.parent))

def create_roadmap_chart(title, phases, milestones, output_path):
    """
    创建技术路线图
    """
    template = """%%{init: {'theme': 'default', 'themeVariables': { 'primaryColor': '#007bff', 'primaryTextColor': '#fff', 'primaryBorderColor': '#0056b3', 'lineColor': '#333', 'tertiaryColor': '#f8f9fa'}}}%%
gantt
    title {title}
    dateFormat YYYY-MM-DD
    axisFormat %Y年%m月
    
    section 第一阶段
    {phase1_tasks}
    
    section 第二阶段
    {phase2_tasks}
    
    section 第三阶段
    {phase3_tasks}
    
    section 里程碑
    {milestone_tasks}
"""
    
    # 解析阶段和任务
    phase_tasks = {}
    for i, phase in enumerate(phases[:3], 1):
        phase_tasks[f'phase{i}_tasks'] = phase
    
    # 解析里程碑
    milestone_tasks = []
    for milestone in milestones:
        milestone_tasks.append(f"{milestone['name']} :milestone, {milestone['date']}, 1d")
    
    content = template.format(
        title=title,
        phase1_tasks=phase_tasks.get('phase1_tasks', '规划阶段 :2024-01-01, 30d'),
        phase2_tasks=phase_tasks.get('phase2_tasks', '开发阶段 :after phase1, 60d'),
        phase3_tasks=phase_tasks.get('phase3_tasks', '测试阶段 :after phase2, 30d'),
        milestone_tasks='\n    '.join(milestone_tasks) if milestone_tasks else '版本发布 :milestone, 2024-04-01, 1d'
    )
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def create_architecture_chart(title, layers, components, connections, output_path):
    """
    创建系统架构图
    """
    template = """graph TB
    subgraph "{frontend_title}"
        A[{frontend_component}]
    end
    
    subgraph "{api_title}"
        B[{api_component}]
    end
    
    subgraph "{service_title}"
        C[{service_1}]
        D[{service_2}]
    end
    
    subgraph "{data_title}"
        E[({database})]
        F[{cache}]
    end
    
    A --> B
    B --> C
    B --> D
    C --> E
    D --> E
    C --> F
    D --> F
    
    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style C fill:#e8f5e8
    style D fill:#e8f5e8
    style E fill:#fff3e0
    style F fill:#fff3e0
"""
    
    # 解析层和组件
    layer_map = {
        'frontend': {'title': '前端层', 'component': 'Web界面'},
        'api': {'title': 'API网关', 'component': 'API Gateway'},
        'service': {'title': '服务层', 'component': '微服务'},
        'data': {'title': '数据层', 'component': '数据库'}
    }
    
    # 更新用户提供的值
    for layer in layers:
        if layer['name'] in layer_map:
            layer_map[layer['name']]['title'] = layer.get('title', layer_map[layer['name']]['title'])
            layer_map[layer['name']]['component'] = layer.get('component', layer_map[layer['name']]['component'])
    
    content = template.format(
        frontend_title=layer_map['frontend']['title'],
        frontend_component=layer_map['frontend']['component'],
        api_title=layer_map['api']['title'],
        api_component=layer_map['api']['component'],
        service_title=layer_map['service']['title'],
        service_1=components.get('service1', '用户服务'),
        service_2=components.get('service2', '订单服务'),
        database=components.get('database', 'MySQL'),
        cache=components.get('cache', 'Redis')
    )
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def create_flowchart_chart(title, steps, decisions, output_path):
    """
    创建流程图
    """
    template = """flowchart TD
    Start(["{title}"])
    
    {steps_content}
    
    {decisions_content}
    
    End([结束])
    
    style Start fill:#4CAF50,color:white
    style End fill:#F44336,color:white
    style Process fill:#2196F3,color:white
    style Decision fill:#FF9800,color:white
"""
    
    # 生成步骤
    steps_content = []
    for i, step in enumerate(steps, 1):
        steps_content.append(f'    Step{i}[{step}]')
    
    # 生成决策
    decisions_content = []
    for i, decision in enumerate(decisions, 1):
        decisions_content.append(f'    Decision{i}{{{decision}}}')
    
    # 连接步骤和决策
    connections = []
    if steps_content:
        connections.append('    Start --> Step1')
        for i in range(1, len(steps_content)):
            connections.append(f'    Step{i} --> Step{i+1}')
        
        if decisions_content:
            connections.append(f'    Step{len(steps_content)} --> Decision1')
            for i in range(1, len(decisions_content)):
                connections.append(f'    Decision{i} --> Decision{i+1}')
            connections.append(f'    Decision{len(decisions_content)} --> End')
        else:
            connections.append(f'    Step{len(steps_content)} --> End')
    
    content = template.format(
        title=title,
        steps_content='\n'.join(steps_content) if steps_content else '    Process1[处理步骤]',
        decisions_content='\n'.join(decisions_content) if decisions_content else '    Decision1{决策点}',
        connections='\n'.join(connections) if connections else '    Start --> Process1\n    Process1 --> Decision1\n    Decision1 --> End'
    )
    
    # 添加连接
    content = content.replace('    End([结束])', f'    End([结束])\n\n{connections}')
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def create_sequence_chart(title, participants, messages, output_path):
    """
    创建序列图
    """
    template = """sequenceDiagram
    participant User as 用户
    participant Frontend as 前端
    participant Backend as 后端
    participant DB as 数据库
    
    {messages_content}
"""
    
    # 生成参与者
    participants_content = []
    for i, participant in enumerate(participants, 1):
        participants_content.append(f'    participant P{i} as {participant}')
    
    # 生成消息
    messages_content = []
    for message in messages:
        messages_content.append(f'    {message["from"]}->>{message["to"]}: {message["text"]}')
    
    content = template.format(
        messages_content='\n'.join(messages_content) if messages_content else '    User->>Frontend: 请求数据\n    Frontend->>Backend: API调用\n    Backend->>DB: 查询数据\n    DB-->>Backend: 返回结果\n    Backend-->>Frontend: 响应数据\n    Frontend-->>User: 显示结果'
    )
    
    # 添加参与者定义
    if participants_content:
        content = content.replace('    participant User as 用户', '\n'.join(participants_content))
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def create_class_chart(title, classes, relationships, output_path):
    """
    创建类图
    """
    template = """classDiagram
    {classes_content}
    
    {relationships_content}
"""
    
    # 生成类定义
    classes_content = []
    for cls in classes:
        class_def = f'    class {cls["name"]} {{\n'
        if 'attributes' in cls:
            for attr in cls['attributes']:
                class_def += f'        {attr}\n'
        if 'methods' in cls:
            for method in cls['methods']:
                class_def += f'        {method}\n'
        class_def += '    }'
        classes_content.append(class_def)
    
    # 生成关系
    relationships_content = []
    for rel in relationships:
        relationships_content.append(f'    {rel["from"]} {rel["type"]} {rel["to"]}')
    
    content = template.format(
        classes_content='\n'.join(classes_content) if classes_content else '''    class User {
        +id: int
        +name: string
        +email: string
        +create(): void
        +update(): void
    }
    
    class Order {
        +id: int
        +userId: int
        +total: float
        +create(): void
        +pay(): void
    }''',
        relationships_content='\n'.join(relationships_content) if relationships_content else '    User "1" --> "*" Order : 拥有'
    )
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def create_gantt_chart(title, tasks, dependencies, output_path):
    """
    创建甘特图
    """
    template = """gantt
    title {title}
    dateFormat YYYY-MM-DD
    
    section 项目阶段
    {tasks_content}
"""
    
    # 生成任务
    tasks_content = []
    for task in tasks:
        task_str = f'    {task["name"]} :{task.get("id", "task")}, {task["start"]}, {task["duration"]}'
        tasks_content.append(task_str)
    
    content = template.format(
        title=title,
        tasks_content='\n'.join(tasks_content) if tasks_content else '''    需求分析 :req, 2024-01-01, 10d
    设计阶段 :design, after req, 15d
    开发阶段 :dev, after design, 30d
    测试阶段 :test, after dev, 15d
    部署上线 :deploy, after test, 5d'''
    )
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def create_er_chart(title, entities, relationships, output_path):
    """
    创建ER图
    """
    template = """erDiagram
    {entities_content}
    
    {relationships_content}
"""
    
    # 生成实体
    entities_content = []
    for entity in entities:
        entity_def = f'    {entity["name"]} {{\n'
        for attr in entity['attributes']:
            entity_def += f'        {attr}\n'
        entity_def += '    }'
        entities_content.append(entity_def)
    
    # 生成关系
    relationships_content = []
    for rel in relationships:
        relationships_content.append(f'    {rel["from"]} {rel.get("cardinality", "||--||")} {rel["to"]} : "{rel.get("label", "关系")}"')
    
    content = template.format(
        entities_content='\n'.join(entities_content) if entities_content else '''    USER {
        int id PK
        string name
        string email
        datetime created_at
    }
    
    ORDER {
        int id PK
        int user_id FK
        decimal amount
        string status
        datetime created_at
    }''',
        relationships_content='\n'.join(relationships_content) if relationships_content else '    USER ||--o{ ORDER : "创建"'
    )
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return content

def main():
    parser = argparse.ArgumentParser(description='创建Mermaid图表定义文件')
    parser.add_argument('--type', required=True, choices=['roadmap', 'architecture', 'flowchart', 'sequence', 'class', 'state', 'gantt', 'er'],
                       help='图表类型')
    parser.add_argument('--title', default='图表标题', help='图表标题')
    parser.add_argument('--output', required=True, help='输出文件路径')
    parser.add_argument('--config', help='JSON配置文件路径')
    
    # 类型特定参数
    parser.add_argument('--phases', help='阶段定义（用于roadmap）')
    parser.add_argument('--milestones', help='里程碑定义（用于roadmap）')
    parser.add_argument('--layers', help='层定义（用于architecture）')
    parser.add_argument('--components', help='组件定义（用于architecture）')
    parser.add_argument('--steps', help='步骤定义（用于flowchart）')
    parser.add_argument('--decisions', help='决策点定义（用于flowchart）')
    parser.add_argument('--participants', help='参与者定义（用于sequence）')
    parser.add_argument('--messages', help='消息定义（用于sequence）')
    parser.add_argument('--classes', help='类定义（用于class）')
    parser.add_argument('--relationships', help='关系定义（用于class）')
    parser.add_argument('--tasks', help='任务定义（用于gantt）')
    parser.add_argument('--dependencies', help='依赖关系（用于gantt）')
    parser.add_argument('--entities', help='实体定义（用于er）')
    
    args = parser.parse_args()
    
    # 确保输出目录存在
    output_path = Path(args.output)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    
    # 从配置文件加载数据（如果提供）
    config_data = {}
    if args.config and Path(args.config).exists():
        with open(args.config, 'r', encoding='utf-8') as f:
            config_data = json.load(f)
    
    # 根据类型创建图表
    chart_type = args.type
    
    if chart_type == 'roadmap':
        # 解析阶段和里程碑
        phases = []
        if args.phases:
            phases = [p.strip() for p in args.phases.split(',')]
        elif 'phases' in config_data:
            phases = config_data['phases']
        
        milestones = []
        if args.milestones:
            milestones = [{'name': m.split(':')[0], 'date': m.split(':')[1]} 
                         for m in args.milestones.split(',')]
        elif 'milestones' in config_data:
            milestones = config_data['milestones']
        
        create_roadmap_chart(args.title, phases, milestones, output_path)
    
    elif chart_type == 'architecture':
        # 解析层和组件
        layers = []
        if args.layers:
            layers = [{'name': l.split(':')[0], 'title': l.split(':')[1]} 
                     for l in args.layers.split(',')]
        elif 'layers' in config_data:
            layers = config_data['layers']
        
        components = {}
        if args.components:
            components = dict(c.split(':') for c in args.components.split(','))
        elif 'components' in config_data:
            components = config_data['components']
        
        create_architecture_chart(args.title, layers, components, {}, output_path)
    
    elif chart_type == 'flowchart':
        # 解析步骤和决策
        steps = []
        if args.steps:
            steps = [s.strip() for s in args.steps.split(',')]
        elif 'steps' in config_data:
            steps = config_data['steps']
        
        decisions = []
        if args.decisions:
            decisions = [d.strip() for d in args.decisions.split(',')]
        elif 'decisions' in config_data:
            decisions = config_data['decisions']
        
        create_flowchart_chart(args.title, steps, decisions, output_path)
    
    elif chart_type == 'sequence':
        # 解析参与者和消息
        participants = []
        if args.participants:
            participants = [p.strip() for p in args.participants.split(',')]
        elif 'participants' in config_data:
            participants = config_data['participants']
        
        messages = []
        if args.messages:
            messages = [{'from': m.split('->')[0], 'to': m.split('->')[1].split(':')[0], 
                        'text': m.split(':')[1]} 
                       for m in args.messages.split(',')]
        elif 'messages' in config_data:
            messages = config_data['messages']
        
        create_sequence_chart(args.title, participants, messages, output_path)
    
    elif chart_type == 'class':
        # 解析类和关系
        classes = []
        if args.classes:
            # 简单解析：ClassName:attr1,attr2|method1,method2
            for cls_str in args.classes.split(';'):
                parts = cls_str.split(':')
                if len(parts) >= 2:
                    cls = {'name': parts[0]}
                    attr_methods = parts[1].split('|')
                    if len(attr_methods) >= 1:
                        cls['attributes'] = attr_methods[0].split(',')
                    if len(attr_methods) >= 2:
                        cls['methods'] = attr_methods[1].split(',')
                    classes.append(cls)
        elif 'classes' in config_data:
            classes = config_data['classes']
        
        relationships = []
        if args.relationships:
            relationships = [{'from': r.split('->')[0], 'to': r.split('->')[1].split(':')[0],
                             'type': r.split(':')[1]} 
                            for r in args.relationships.split(',')]
        elif 'relationships' in config_data:
            relationships = config_data['relationships']
        
        create_class_chart(args.title, classes, relationships, output_path)
    
    elif chart_type == 'gantt':
        # 解析任务和依赖
        tasks = []
        if args.tasks:
            for task_str in args.tasks.split(';'):
                parts = task_str.split(':')
                if len(parts) >= 3:
                    tasks.append({
                        'name': parts[0],
                        'start': parts[1],
                        'duration': parts[2],
                        'id': parts[3] if len(parts) > 3 else parts[0].lower().replace(' ', '_')
                    })
        elif 'tasks' in config_data:
            tasks = config_data['tasks']
        
        create_gantt_chart(args.title, tasks, [], output_path)
    
    elif chart_type == 'er':
        # 解析实体和关系
        entities = []
        if args.entities:
            for entity_str in args.entities.split(';'):
                parts = entity_str.split(':')
                if len(parts) >= 2:
                    entities.append({
                        'name': parts[0],
                        'attributes': parts[1].split(',')
                    })
        elif 'entities' in config_data:
            entities = config_data['entities']
        
        relationships = []
        if args.relationships:
            for rel_str in args.relationships.split(';'):
                parts = rel_str.split(':')
                if len(parts) >= 3:
                    relationships.append({
                        'from': parts[0],
                        'to': parts[1],
                        'cardinality': parts[2],
                        'label': parts[3] if len(parts) > 3 else '关系'
                    })
        elif 'relationships' in config_data:
            relationships = config_data['relationships']
        
        create_er_chart(args.title, entities, relationships, output_path)
    
    else:
        print(f"不支持的图表类型: {chart_type}")
        sys.exit(1)
    
    print(f"✅ Mermaid图表已创建: {output_path}")
    print(f"   类型: {chart_type}")
    print(f"   标题: {args.title}")
    print(f"   文件大小: {output_path.stat().st_size} 字节")

if __name__ == "__main__":
    main()

path: scripts/insert_to_md.py
content: #!/usr/bin/env python3
"""
将PNG图片插入到Markdown文件
支持替换占位符或在指定位置插入
"""

import os
import sys
import argparse
import re
from pathlib import Path
import shutil

def insert_image_to_markdown(md_file, image_file, placeholder=None, section=None, 
                           caption=None, position='after', relative_path=True):
    """
    将图片插入到Markdown文件
    """
    if not Path(md_file).exists():
        print(f"❌ Markdown文件不存在: {md_file}")
        return False
    
    if not Path(image_file).exists():
        print(f"❌ 图片文件不存在: {image_file}")
        return False
    
    # 读取Markdown内容
    with open(md_file, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # 计算相对路径
    if relative_path:
        md_path = Path(md_file).parent
        img_path = Path(image_file)
        
        try:
            # 计算相对路径
            rel_path = os.path.relpath(img_path, md_path)
            image_ref = rel_path
        except ValueError:
            # 如果无法计算相对路径，使用绝对路径
            image_ref = str(img_path)
            print(f"⚠️ 使用绝对路径: {image_ref}")
    else:
        image_ref = str(Path(image_file).name)
    
    # 构建图片Markdown语法
    if caption:
        image_markdown = f'![{caption}]({image_ref})'
    else:
        # 使用文件名作为默认标题
        caption_text = Path(image_file).stem.replace('_', ' ').replace('-', ' ')
        image_markdown = f'![{caption_text}]({image_ref})'
    
    # 添加图片说明
    if caption:
        image_markdown += f'\n\n*图: {caption}*'
    
    new_content = content
    
    # 情况1: 替换占位符
    if placeholder:
        if placeholder in content:
            new_content = content.replace(placeholder, image_markdown)
            print(f"✅ 已替换占位符: {placeholder}")
        else:
            print(f"⚠️ 占位符未找到: {placeholder}")
            print("将在文件末尾插入图片")
            new_content = content + f'\n\n{image_markdown}'
    
    # 情况2: 插入到指定章节
    elif section:
        # 查找章节
        lines = content.split('\n')
        section_index = -1
        
        for i, line in enumerate(lines):
            if line.strip().startswith(section):
                section_index = i
                break
        
        if section_index >= 0:
            if position == 'before':
                # 插入到章节前
                lines.insert(section_index, '')
                lines.insert(section_index, image_markdown)
                new_content = '\n'.join(lines)
                print(f"✅ 已插入图片到章节前: {section}")
            elif position == 'after':
                # 插入到章节后
                # 找到章节结束位置（下一个同级或更高级标题）
                insert_index = section_index + 1
                while insert_index < len(lines):
                    line = lines[insert_index]
                    if line.strip() and line.strip()[0] == '#':
                        # 找到下一个标题，停止
                        break
                    insert_index += 1
                
                lines.insert(insert_index, '')
                lines.insert(insert_index, image_markdown)
                new_content = '\n'.join(lines)
                print(f"✅ 已插入图片到章节后: {section}")
            else:  # replace
                # 替换章节内容
                # 找到章节内容范围
                start_index = section_index + 1
                end_index = start_index
                while end_index < len(lines):
                    line = lines[end_index]
                    if line.strip() and line.strip()[0] == '#':
                        # 找到下一个标题，停止
                        break
                    end_index += 1
                
                # 替换章节内容
                new_lines = lines[:start_index] + ['', image_markdown, ''] + lines[end_index:]
                new_content = '\n'.join(new_lines)
                print(f"✅ 已替换章节内容: {section}")
        else:
            print(f"⚠️ 章节未找到: {section}")
            print("将在文件末尾插入图片")
            new_content = content + f'\n\n{image_markdown}'
    
    # 情况3: 插入到文件末尾
    else:
        new_content = content + f'\n\n{image_markdown}'
        print("✅ 已插入图片到文件末尾")
    
    # 写入文件
    with open(md_file, 'w', encoding='utf-8') as f:
        f.write(new_content)
    
    print(f"✅ 图片已插入到: {md_file}")
    print(f"   图片引用: {image_ref}")
    if caption:
        print(f"   图片标题: {caption}")
    
    return True

def batch_insert_images(md_file, image_dir, pattern=None, placeholder_prefix='[IMAGE_'):
    """
    批量插入图片到Markdown文件
    """
    if not Path(md_file).exists():
        print(f"❌ Markdown文件不存在: {md_file}")
        return False
    
    if not Path(image_dir).exists():
        print(f"❌ 图片目录不存在: {image_dir}")
        return False
    
    # 查找图片文件
    if pattern:
        image_files = list(Path(image_dir).glob(pattern))
    else:
        image_files = list(Path(image_dir).glob("*.png")) + \
                     list(Path(image_dir).glob("*.jpg")) + \
                     list(Path(image_dir).glob("*.jpeg"))
    
    if not image_files:
        print(f"❌ 在 {image_dir} 中没有找到图片文件")
        return False
    
    print(f"找到 {len(image_files)} 个图片文件")
    
    # 读取Markdown内容
    with open(md_file, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # 查找所有占位符
    placeholders = re.findall(rf'{re.escape(placeholder_prefix)}[^\]]+\]', content)
    
    if not placeholders:
        print(f"❌ 未找到占位符（前缀: {placeholder_prefix}）")
        return False
    
    print(f"找到 {len(placeholders)} 个占位符")
    
    # 按数字排序占位符
    def extract_number(ph):
        match = re.search(r'(\d+)', ph)
        return int(match.group(1)) if match else 0
    
    sorted_placeholders = sorted(placeholders, key=extract_number)
    
    # 按数字排序图片文件
    def extract_image_number(img_path):
        match = re.search(r'(\d+)', img_path.stem)
        return int(match.group(1)) if match else 0
    
    sorted_images = sorted(image_files, key=extract_image_number)
    
    # 确保数量匹配
    if len(sorted_placeholders) != len(sorted_images):
        print(f"⚠️ 占位符数量({len(sorted_placeholders)})与图片数量({len(sorted_images)})不匹配")
        min_count = min(len(sorted_placeholders), len(sorted_images))
        sorted_placeholders = sorted_placeholders[:min_count]
        sorted_images = sorted_images[:min_count]
        print(f"   将处理前 {min_count} 个")
    
    # 替换占位符
    new_content = content
    success_count = 0
    
    for i, (placeholder, image_file) in enumerate(zip(sorted_placeholders, sorted_images), 1):
        # 计算相对路径
        md_path = Path(md_file).parent
        rel_path = os.path.relpath(image_file, md_path)
        
        # 构建图片Markdown语法
        caption = image_file.stem.replace('_', ' ').replace('-', ' ')
        image_markdown = f'![{caption}]({rel_path})'
        
        # 替换占位符
        if placeholder in new_content:
            new_content = new_content.replace(placeholder, image_markdown)
            print(f"  ✅ 替换 {placeholder} → {image_file.name}")
            success_count += 1
        else:
            print(f"  ⚠️ 占位符未找到: {placeholder}")
    
    # 写入文件
    if success_count > 0:
        with open(md_file, 'w', encoding='utf-8') as f:
            f.write(new_content)
        
        print(f"\n✅ 批量插入完成: {success_count}/{len(sorted_placeholders)} 个图片已插入")
        return True
    else:
        print("\n❌ 批量插入失败: 未插入任何图片")
        return False

def copy_image_to_md_directory(md_file, image_file):
    """
    将图片复制到Markdown文件所在目录
    """
    md_dir = Path(md_file).parent
    image_name = Path(image_file).name
    dest_path = md_dir / image_name
    
    try:
        shutil.copy2(image_file, dest_path)
        print(f"✅ 图片已复制到: {dest_path}")
        return str(dest_path)
    except Exception as e:
        print(f"❌ 复制图片失败: {e}")
        return None

def main():
    parser = argparse.ArgumentParser(description='将PNG图片插入到Markdown文件')
    parser.add_argument('--md-file', required=True, help='Markdown文件路径')
    parser.add_argument('--image', help='图片文件路径（单文件模式）')
    parser.add_argument('--image-dir', help='图片目录路径（批量模式）')
    parser.add_argument('--placeholder', help='要替换的占位符（如 [IMAGE_1]）')
    parser.add_argument('--section', help='要插入的章节标题（如 ## 技术路线图）')
    parser.add_argument('--caption', help='图片标题')
    parser.add_argument('--position', choices=['before', 'after', 'replace'], 
                       default='after', help='插入位置（默认after）')
    parser.add_argument('--relative-path', action='store_true', default=True,
                       help='使用相对路径（默认）')
    parser.add_argument('--absolute-path', action='store_false', dest='relative_path',
                       help='使用绝对路径')
    parser.add_argument('--copy-image', action='store_true',
                       help='将图片复制到Markdown文件所在目录')
    parser.add_argument('--batch', action='store_true', help='批量模式')
    parser.add_argument('--pattern', help='图片文件模式（如 *.png）')
    parser.add_argument('--placeholder-prefix', default='[IMAGE_',
                       help='占位符前缀（默认[IMAGE_）')
    
    args = parser.parse_args()
    
    print("=" * 60)
    print("Markdown图片插入工具")
    print("=" * 60)
    
    # 检查Markdown文件
    if not Path(args.md_file).exists():
        print(f"❌ Markdown文件不存在: {args.md_file}")
        sys.exit(1)
    
    # 批量模式
    if args.batch:
        if not args.image_dir:
            print("❌ 批量模式需要 --image-dir 参数")
            sys.exit(1)
        
        success = batch_insert_images(
            args.md_file, args.image_dir,
            pattern=args.pattern,
            placeholder_prefix=args.placeholder_prefix
        )
        
        if success:
            print(f"\n✅ 批量插入完成！")
            print(f"Markdown文件: {args.md_file}")
        else:
            print("\n❌ 批量插入失败")
            sys.exit(1)
    
    # 单文件模式
    else:
        if not args.image:
            print("❌ 单文件模式需要 --image 参数")
            sys.exit(1)
        
        # 复制图片（如果需要）
        image_path = args.image
        if args.copy_image:
            new_path = copy_image_to_md_directory(args.md_file, args.image)
            if new_path:
                image_path = new_path
            else:
                print("⚠️ 图片复制失败，使用原始路径")
        
        success = insert_image_to_markdown(
            args.md_file, image_path,
            placeholder=args.placeholder,
            section=args.section,
            caption=args.caption,
            position=args.position,
            relative_path=args.relative_path
        )
        
        if success:
            print(f"\n✅ 插入完成！")
            print(f"Markdown文件: {args.md_file}")
            print(f"图片文件: {image_path}")
        else:
            print("\n❌ 插入失败")
            sys.exit(1)

if __name__ == "__main__":
    main()

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)