Skill: awamwang/wiz-migration (version 1.0.0)

--- name: wiz-migration description: 为知笔记迁移辅助技能，提供自动检测存储目录、导出操作引导、附件批量迁移等完整迁移流程 version: 1.0.0 author: OpenClaw Assistant supported_models: ["*"] tags: ["migration", "wiz", "笔记", "数据迁移"] --- # 为知笔记迁移技能 为知笔记数据迁移辅助工具，提供自动化检测、交互式引导和一键迁移功能。 ## 功能特性 - 🔍 **智能检测存储目录**：自动查找为知笔记数据目录，支持手动输入 - 📝 **导出操作引导**：生成带详细步骤的 .md 模板，指导用户正确导出 - 📎 **附件批量迁移**：自动复制所有 _Attachments 目录到目标位置 - 🖥️ **跨平台支持**：Windows 批处理脚本，简化操作 - ⚡ **增量复制**：自动跳过已存在的文件，支持重复执行 ## 快速开始 ### 1. 启动迁移向导 ```bash # 启动交互式迁移流程 openclaw skill wiz-migration start # 或在 Python 脚本中调用 from wiz_migration import start_wizard start_wizard() ``` ### 2. 按照向导步骤操作 1. **检测存储目录**：自动尝试查找 `C:\Users\Administrator\Documents\My Knowledge\Data\` 2. **输入导出路径**：提供为知笔记导出后的 HTML 文件夹路径 3. **生成导出指南**：保存为 `wiz_export_guide.md` 4. **附件迁移**：选择是否自动运行批处理脚本迁移附件 ## 导出操作指南 ### 为知笔记导出设置（必做） 在运行迁移前，需要先在为知笔记中执行导出操作： 1. 整理笔记：将所有要迁移的目录和文档移动到同一个父目录下 2. 选中笔记本/笔记 → 右键 → 导出文件 → 导出 HTML 3. **关键选项**： - ✅ 选择 **"导出为多个网页文件（含附件）"** - ❌ 不要选 **"单个 HTML 文件"**（附件会被 base64 内嵌） - ❌ 不要勾选 **"渲染 Markdown 笔记"**（会丢失原始结构） 4. 导出到独立空文件夹（如 `Wiz_Export`） ### 导出后的目录结构 ``` Wiz_Export/ ├── 笔记本1/ │ ├── 笔记1.html │ ├── 笔记1_files/ # 该笔记的所有附件（图片、PDF、Word等） │ └── 笔记2.html └── 笔记本2/ ├── 笔记3.html └── 笔记3_files/ ``` ### 导出后检查 - 每个 `.html` 旁应有同名 `_files` 文件夹 - 打开任一 HTML，确认图片/附件能正常显示 - 路径应为相对路径（如 `笔记1_files/xxx.png`） ## 附件迁移脚本说明 ### 功能特点 - 批量复制所有 `_Attachments` 目录 - 已存在自动跳过，可重复执行 - 不覆盖现有文件 ### 使用方法 在 PowerShell 或 CMD 中运行： ```batch @echo off setlocal enabledelayedexpansion chcp 65001 >nul title 批量复制 _Attachments 目录 :: ====================== 请修改这里的路径 ====================== set "SOURCE_DIR=C:\Users\Administrator\Documents\My Knowledge" set "TARGET_DIR=G:\Data\knowledge\wiz" :: ============================================================== echo ============================================== echo 批量复制 _Attachments 目录 echo 功能：已存在自动跳过，可重复执行，不覆盖 echo ============================================== echo 源目录：%SOURCE_DIR% echo 目标目录：%TARGET_DIR% echo. set COUNT=0 set SKIP=0 for /d /r "%SOURCE_DIR%" %%d in (*_Attachments) do ( set "FULL_PATH=%%d" set "REL_PATH=!FULL_PATH:%SOURCE_DIR%=!" set "DEST_PATH=%TARGET_DIR%!REL_PATH!" echo 源目录：!FULL_PATH! echo 目标路径：!DEST_PATH! if exist "!DEST_PATH!" ( echo ⏭️ 已存在，跳过：!REL_PATH! set /a SKIP+=1 ) else ( mkdir "!DEST_PATH!" xcopy "!FULL_PATH!\*" "!DEST_PATH!\" /E /H /C /R /Q >nul echo ✅ 复制成功：!REL_PATH! set /a COUNT+=1 ) echo. ) echo ============================================== echo 任务完成 echo 本次新增复制：!COUNT! 个 echo 已存在跳过：!SKIP! 个 echo ============================================== pause exit /b ``` ### 配置说明 修改脚本中的两个路径变量： ```batch set "SOURCE_DIR=你的为知笔记原始数据目录" set "TARGET_DIR=你要迁移到的目标目录" ``` ## API 接口 ### Python 模块调用 ```python from wiz_migration import ( detect_wiz_data_dir, generate_export_guide, run_attachment_migration, start_wizard ) # 1. 检测为知笔记数据目录 data_dir = detect_wiz_data_dir() if not data_dir: print("未自动检测到，请手动输入路径") # 2. 生成导出指南 guide_path = generate_export_guide( export_dir="C:/path/to/Wiz_Export", output_file="wiz_export_guide.md" ) # 3. 运行附件迁移 result = run_attachment_migration( source_dir="C:/Users/Administrator/Documents/My Knowledge", target_dir="G:/Data/knowledge/wiz", script_path="scripts/copy_attachments.bat" ) # 4. 完整向导 start_wizard() ``` ## 错误处理 | 错误情况 | 原因 | 解决方案 | |---------|------|----------| | 无法自动检测目录 | 非标准安装路径 | 手动输入数据目录路径 | | 导出路径不存在 | 还未执行导出操作 | 先在为知笔记中导出 HTML | | 附件复制失败 | 权限不足 | 以管理员身份运行脚本 | | 中文乱码 | CMD 编码问题 | 确保脚本包含 `chcp 65001` 设置 | ## 注意事项 1. **备份原始数据**：迁移前务必备份整个 `My Knowledge` 目录 2. **导出格式**：必须选择"多个网页文件（含附件）"格式 3. **路径不要包含空格**：或使用引号包裹路径 4. **附件大小**：大附件（>100MB）可能需要较长时间 5. **重复执行**：附件迁移脚本可安全重复运行，不会覆盖已有文件 ## 迁移完成检查清单 - [ ] 为知笔记已导出 HTML 到独立文件夹 - [ ] 每个 HTML 文件旁都有对应的 `_files` 文件夹 - [ ] 打开 HTML 能正常显示图片和附件 - [ ] 已运行附件迁移脚本或手动复制 - [ ] 目标目录中所有附件已就位 - [ ] 在浏览器中测试打开的 HTML 文件路径是否正确 ## 后续处理 迁移完成后，你可能需要： 1. **转换为 Markdown**：使用 `wiz2md` 等工具将 HTML 转换为 Markdown 2. **导入笔记软件**：如 Obsidian、Logseq、Notion 等 3. **建立双向链接**：在新笔记系统中重建关联 4. **清理重复**：使用去重工具清理重复内容 ## 技术细节 ### 为知笔记数据目录结构 ``` My Knowledge/ ├── Data/ │ ├── 账号1/ │ │ ├── index/ │ │ └── attachments/ │ └── 账号2/ └── _Attachments/ # 全局附件目录（部分版本） ``` ### 存储目录检测逻辑 ```python def detect_wiz_data_dir(): """检测标准安装路径""" possible_paths = [ r"C:\Users\Administrator\Documents\My Knowledge\Data", r"C:\Users\%USERNAME%\Documents\My Knowledge\Data", os.path.expanduser(r"~/Documents/My Knowledge/Data") ] for path in possible_paths: if os.path.exists(path): return path return None ``` ## 支持 如有问题，请检查： - 是否为标准安装路径 - 是否已正确导出 HTML 格式 - 是否有足够的文件读写权限

path: README.md
content: # 为知笔记迁移技能 (Wiz Migration)

> 版本: 1.0.0 | 作者: OpenClaw Assistant

为知笔记数据迁移辅助工具，提供自动化检测、交互式引导和一键迁移功能。

## 快速使用

```bash
# 启动交互式向导
python -m wiz_migration

# 或使用入口文件
python bin/wiz-migrate
```

## 功能特点

- 🔍 **智能检测**：自动查找为知笔记数据目录
- 📝 **导出指南**：生成详细的 HTML 导出操作指南
- 📎 **附件迁移**：批量复制所有附件文件
- 🖥️ **跨平台**：支持 Windows 批处理脚本
- ⚡ **增量复制**：自动跳过已存在的文件

## 主要功能

### 1. 自动检测数据目录

自动识别标准安装路径：
- `C:\Users\Administrator\Documents\My Knowledge\Data`
- `$HOME/Documents/My Knowledge/Data`

如果自动检测失败，支持手动输入路径。

### 2. 生成导出指南

在 `wiz_export_guide.md` 中生成：
- 为知笔记导出的详细步骤
- 关键选项说明（避免常见错误）
- 目录结构示例
- 导出后检查清单

**关键提醒：**
- ✅ 必须选择"导出为多个网页文件（含附件）"
- ❌ 不要选择"单个 HTML 文件"（附件会被内嵌）
- ❌ 不要勾选"渲染 Markdown 笔记"（会丢失结构）

### 3. 附件批量迁移

自动复制所有 `_Attachments` 目录：
- 已存在自动跳过
- 可重复执行，不覆盖
- 提供详细进度和统计

同时提供 Windows 批处理脚本 `copy_attachments.bat` 供独立使用。

### 4. 交互式向导

`start_wizard()` 提供完整的一步一步迁移流程：
1. 检测数据目录
2. 生成导出指南
3. 迁移附件
4. 完成检查和后续建议

## API 使用方法

```python
from wiz_migration import (
    detect_wiz_data_dir,
    generate_export_guide,
    run_attachment_migration,
    start_wizard
)

# 检测数据目录
data_dir = detect_wiz_data_dir()

# 生成导出指南
guide_path = generate_export_guide(
    export_dir="C:/Wiz_Export",
    output_file="export_guide.md"
)

# 迁移附件
result = run_attachment_migration(
    source_dir="C:/Users/Admin/Documents/My Knowledge",
    target_dir="G:/Data/wiz"
)

# 完整向导
start_wizard()
```

## 目录结构

```
wiz-migration/
├── SKILL.md              # 技能说明文档
├── README.md             # 本文件
├── __init__.py           # 包入口
├── bin/
│   ├── wiz-migrate       # 可执行入口（主程序）
│   └── __init__.py
├── scripts/
│   ├── detector.py       # 数据目录检测
│   ├── guide_generator.py  # 导出指南生成
│   ├── migrator.py       # 附件迁移逻辑
│   ├── copy_attachments.bat # Windows 批处理脚本
│   └── __init__.py
└── templates/
    └── (动态生成的模板文件)
```

## 为知笔记数据目录结构

```
My Knowledge/
├── Data/
│   ├── 账号1/
│   │   ├── index/       # 笔记索引
│   │   └── attachments/ # 账号附件
│   └── 账号2/
└── _Attachments/        # 全局附件目录
```

## 导出后的目录结构

```
Wiz_Export/
├── 笔记本1/
│   ├── 笔记1.html
│   ├── 笔记1_files/    # 该笔记的附件
│   └── 笔记2.html
└── 笔记本2/
    └── 笔记3_files/
```

## 系统要求

- Python 3.8+
- 操作系统：Windows / Linux / macOS
- 为知笔记客户端（用于导出）
- 足够的磁盘空间

## 注意事项

1. **备份优先**：迁移前务必备份整个 `My Knowledge` 目录
2. **导出格式**：必须使用"多个网页文件（含附件）"格式
3. **路径安全**：避免路径包含特殊字符或空格
4. **权限要求**：需要读取源目录、写入目标目录的权限
5. **增量复制**：脚本会自动跳过已存在的文件，可安全重复运行

## 常见问题

### Q: 为什么自动检测不到数据目录？

A: 可能是非标准安装路径或中文用户名。请手动输入完整路径。

### Q: 导出的 HTML 文件打不开？

A: 1) 确保用浏览器打开；2) 检查 `_files` 文件夹是否存在；3) 确认文件未被损坏。

### Q: 图片不显示？

A: 检查 `_files` 文件夹是否与 `.html` 文件在同一目录，路径是否为相对路径。

### Q: 附件复制失败？

A: 检查是否有足够的磁盘空间和文件读写权限。

## 后续步骤

迁移完成后建议：
1. 使用 `wiz2md` 等工具将 HTML 转换为 Markdown
2. 导入 Obsidian / Logseq / Notion 等笔记软件
3. 在新笔记系统中建立双向链接
4. 清理重复内容

## License

MIT

---

**注意**：本技能仅作为迁移辅助工具，不对数据丢失负责。请始终保留原始备份，直至确认迁移完成。


path: __init__.py
content: """
为知笔记迁移技能 - Python 包入口

提供完整的为知笔记数据迁移功能：
1. 自动检测为知笔记数据目录
2. 生成详细导出操作指南
3. 批量迁移附件文件
"""

__version__ = "1.0.0"
__author__ = "OpenClaw Assistant"

from scripts.detector import detect_wiz_data_dir, validate_data_dir
from scripts.guide_generator import generate_export_guide, append_migration_log
from scripts.migrator import run_attachment_migration, find_attachments

__all__ = [
    "detect_wiz_data_dir",
    "validate_data_dir",
    "generate_export_guide",
    "append_migration_log",
    "run_attachment_migration",
    "find_attachments",
    "start_wizard"
]

# 导入主程序中的 start_wizard 函数
try:
    from bin.wiz-migrate import start_wizard
    __all__.append("start_wizard")
except ImportError:
    pass


def quick_start():
    """
    快速启动向导
    
    相当于: start_wizard()
    """
    from bin.wiz-migrate import start_wizard
    start_wizard()


if __name__ == "__main__":
    quick_start()


path: bin/__init__.py
content: """wiz-migrate 入口模块"""


path: scripts/__init__.py
content: """
为知笔记迁移技能

用于帮助用户将为知笔记数据迁移到其他笔记软件。

主要功能：
1. 智能检测为知笔记数据目录
2. 生成详细的 HTML 导出操作指南
3. 批量迁移附件文件
4. 提供完整的交互式向导

用法:
  python -m wiz_migration          # 启动交互向导
  python -m wiz_migration detect   # 仅检测数据目录
  python -m wiz_migration guide    # 仅生成导出指南
  python -m wiz_migration migrate  # 仅迁移附件
  
或者使用技能入口:
  python bin/wiz-migrate
"""

__version__ = "1.0.0"


path: scripts/detector.py
content: #!/usr/bin/env python3
"""
为知笔记数据目录检测模块
"""

import os
from pathlib import Path


def detect_wiz_data_dir():
    """
    自动检测为知笔记数据目录
    
    返回:
        str: 检测到的数据目录路径，如果未找到则返回 None
    """
    possible_paths = [
        # Windows 标准路径
        r"C:\Users\Administrator\Documents\My Knowledge\Data",
        r"C:\Users\%USERNAME%\Documents\My Knowledge\Data",
        # 当前用户路径
        os.path.join(os.path.expanduser("~"), "Documents", "My Knowledge", "Data"),
        # Linux/Mac 可能路径 (如果使用跨平台版本)
        os.path.join(os.path.expanduser("~"), "Documents", "My Knowledge", "Data"),
        os.path.join(os.path.expanduser("~"), ".wiznotes", "Data"),
    ]
    
    for path in possible_paths:
        # 处理环境变量
        expanded_path = os.path.expandvars(path)
        if os.path.exists(expanded_path):
            return expanded_path
    
    return None


def validate_data_dir(path):
    """
    验证是否为有效的为知笔记数据目录
    
     Args:
        path: 要验证的路径
        
    Returns:
        tuple: (是否有效, 检测到的内容信息)
    """
    if not os.path.exists(path):
        return False, "路径不存在"
    
    p = Path(path)
    
    # 检查是否有 Data 子目录（标准结构）
    data_subdirs = list(p.iterdir())
    if not data_subdirs:
        return False, "目录为空"
    
    # 检查是否包含账号目录（通常有 index 或 attachments 子目录）
    for subdir in data_subdirs[:3]:  # 只看前3个
        if subdir.is_dir():
            # 检查是否为账号目录
            has_index = (subdir / "index").exists()
            has_attachments = (subdir / "attachments").exists() or (subdir / "_Attachments").exists()
            
            if has_index or has_attachments:
                return True, f"检测到账号目录: {subdir.name}"
    
    # 检查是否有 attachments 目录（Wiz 可能直接在 Data 下）
    if (p / "attachments").exists() or (p / "_Attachments").exists():
        return True, "检测到全局附件目录"
    
    return False, "未检测到典型为知笔记结构"


if __name__ == "__main__":
    # 直接运行测试
    detected = detect_wiz_data_dir()
    if detected:
        print(f"检测到数据目录: {detected}")
        
        valid, info = validate_data_dir(detected)
        if valid:
            print(f"✅ 目录有效: {info}")
        else:
            print(f"⚠️  目录可能无效: {info}")
    else:
        print("❌ 未检测到为知笔记数据目录")


path: scripts/guide_generator.py
content: #!/usr/bin/env python3
"""
为知笔记导出指南生成器
将导出要求转换为 Markdown 模板
"""

from pathlib import Path
from datetime import datetime


def generate_export_guide(export_dir, output_file=None):
    """
    生成导出操作指南 Markdown 文件
    
    Args:
        export_dir: 导出目录路径
        output_file: 输出文件路径，默认使用当前时间戳
        
    Returns:
        str: 生成的指南文件路径
    """
    export_path = Path(export_dir)
    
    # 生成文件名
    if output_file:
        guide_path = Path(output_file)
    else:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        guide_path = Path(f"wiz_export_guide_{timestamp}.md")
    
    guide_path = guide_path.resolve()
    
    # 生成 Markdown 内容
    content = f"""# 为知笔记导出操作指南

> 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
> 导出目录: {export_path}

## ⚠️  重要提醒

**这一步是为迁移做准备，请务必在迁移前完成！**

## 📋 导出前准备

### 1. 整理笔记

在开始导出前，建议先将为知笔记中要迁移的所有目录和文档
移动到同一个父目录下，这样可以在一次导出中完成所有内容的转换。

步骤：
1. 在左侧笔记本列表中，右键要导出的笔记本
2. 选择"移动到" → 选择目标笔记本或创建新笔记本
3. 重复直到所有要迁移的笔记都在同一父目录下

### 2. 确认导出设置

**必须选择正确的导出格式**，否则附件会被内嵌或丢失！

---

## 🚀 导出操作步骤

### 步骤一：选中要导出的内容

1. 在左侧笔记本列表中，选中要导出的笔记本
2. 如果要导出多个笔记本，可以按住 Ctrl 多选
3. 或选中父目录下的所有子笔记本

### 步骤二：开始导出

1. 右键点击选中的笔记本
2. 在右键菜单中选择 **"导出文件"**
3. 选择 **"导出 HTML"** 选项

### 步骤三：配置导出选项（关键！）

在弹出的导出对话框中，**必须** 设置以下选项：

#### ✅ 必须选择的选项

- **"导出为多个网页文件（含附件）"**
  - ⚠️  **不要**选择"单个 HTML 文件"！  
     否则附件会被 base64 内嵌到 HTML 中，难以分离
  
- **"保持目录结构"**（如果可用）
  - 这样导出后能保留笔记本的层级关系

#### ❌ 不要勾选的选项

- ~~"渲染 Markdown 笔记"~~
  - 这会丢失原始结构，笔记可能格式错乱
  
- ~~"导出为单个 HTML 文件"~~
  - 附件会内嵌，无法单独使用

#### 📁 导出位置

**目标文件夹：**

```
{export_path}
```

- 点击"浏览"按钮
- 选择或创建导出文件夹
- **建议使用空文件夹**，避免文件冲突

### 步骤四：开始导出

1. 确认选项无误后，点击 **"确定"** 或 **"导出"**
2. 等待导出完成（时间取决于笔记数量）
3. 如果导出中断，可以重新导出相同内容，会覆盖已有的

---

## 🔍 导出后检查

导出完成后，请按照以下清单检查：

### 目录结构检查

你的导出文件夹应该有这样的结构：

```
{export_path.name}/
├── 笔记本1/
│   ├── 笔记1.html
│   ├── 笔记1_files/
│   │   ├── 图片1.png
│   │   ├── 图片2.jpg
│   │   └── 附件.pdf
│   └── 笔记2.html
├── 笔记本2/
│   ├── 笔记3.html
│   └── 笔记3_files/
└── ...
```

**检查要点：**

1. ✅ 每个 `.html` 文件旁边都有一个同名 `_files` 文件夹
2. ✅ `_files` 文件夹中包含实际的图片和附件文件
3. ✅ 附件文件不是空的（检查文件大小）

### 内容检查

1. 随便打开一个 `.html` 文件
2. 检查图片是否能正常显示
3. 检查附件链接是否正常（如果是超链接）
4. 检查格式是否基本正常

### 路径检查

在浏览器中打开的 HTML 文件，其附件路径应该是相对路径，例如：

```html
<img src="笔记1_files/图片1.png">
```

**如果看到类似这样的路径，说明导出正确：**
- ✅ `笔记1_files/xxx.png` （正确，相对路径）
- ✅ `./笔记1_files/xxx.png` （正确）

**如果看到这些，说明有问题：**
- ❌ `file:///C:/Users/...` （绝对路径，可能无法在其他电脑使用）
- ❌ 长串的 `data:image/png;base64,...` （附件被内嵌了，选错选项）

---

## ⚠️  常见问题

### Q1: 没有看到"导出为多个网页文件"选项？

A: 为知笔记不同版本界面不同：
- PC 客户端：右键 → 导出文件 → 选择"HTML" → 在对话框中选"多个网页文件"
- 网页版：可能导出功能有限，建议使用客户端
- Mac 版：选项可能略有不同，但原理相同

### Q2: 导出的 HTML 文件打不开？

A: 
1. 检查是否用浏览器打开（不是用记事本）
2. 如果双击打不开，右键选择"打开方式" → 浏览器
3. 检查文件是否损坏（大小是否过小）

### Q3: 图片显示为空白或破损图标？

可能原因：
1. 导出时没有选择"含附件"选项
2. `_files` 文件夹和 `.html` 不在同一目录
3. 文件路径被修改过
4. 浏览器安全限制：有些浏览器会阻止本地文件访问

**解决方法：**
1. 确认 `_files` 文件夹存在且不为空
2. 确保没有移动 `.html` 或 `_files` 的位置
3. 尝试使用 Chrome/Edge 浏览器打开
4. 可以尝试将整个导出文件夹放到 Web 服务器下测试

### Q4: 附件链接不可用？

为知笔记导出的 HTML 中，附件可能是：
- 图片：嵌入在 HTML 中（显示正常）
- 文件：作为超链接存在（需要点击下载）

如果附件链接无效：
1. 检查 `_files` 文件夹中是否有对应文件
2. 检查文件名是否匹配（大小写敏感）
3. 如果是外部链接，可能需要网络连接

---

## ✅ 导出完成检查清单

完成检查后，打勾 ✅ 确认：

- [ ] 已在为知笔记中完成 HTML 导出（多个网页文件）
- [ ] 导出到指定文件夹（或已告知迁移人员）
- [ ] 文件夹中有多个子文件夹（笔记本名称）
- [ ] 每个子文件夹中有 `.html` 文件和 `_files` 文件夹
- [ ] 至少打开了 3 个 HTML 文件，图片/附件都能正常显示
- [ ] 附件文件大小正常（不是 0 字节）
- [ ] 已关闭为知笔记（避免文件被占用）

---

## 📞 需要帮助？

如果遇到问题：
1. 仔细阅读本指南的常见问题部分
2. 检查导出选项是否正确（这是最常见的问题）
3. 确认是否为最新版为知笔记
4. 截取导出对话框和目录结构的截图

---

## 🎯 下一步

导出完成后，请返回迁移向导，选择"自动迁移附件"或"手动迁移附件"。

迁移向导会：
- ✅ 自动复制所有 `_Attachments` 目录
- ✅ 智能跳过已存在的文件
- ✅ 保持目录结构不变
- ✅ 提供详细的进度和统计

祝你迁移顺利！

---

*本指南由为知笔记迁移向导自动生成*
"""
    
    # 写入文件
    with open(guide_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return str(guide_path)


def append_migration_log(export_dir, status, notes=""):
    """
    记录导出操作日志
    
    Args:
        export_dir: 导出目录
        status: 状态（completed/failed/partial）
        notes: 备注信息
    """
    log_path = Path("migration_log.json")
    
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "export_dir": export_dir,
        "status": status,
        "notes": notes
    }
    
    if log_path.exists():
        import json
        with open(log_path, 'r', encoding='utf-8') as f:
            logs = json.load(f)
    else:
        logs = []
    
    logs.append(log_entry)
    
    with open(log_path, 'w', encoding='utf-8') as f:
        json.dump(logs, f, indent=2, ensure_ascii=False)
    
    return str(log_path)


if __name__ == "__main__":
    # 测试
    test_dir = input("测试导出目录路径: ").strip() or r"C:\Wiz_Export"
    output = generate_export_guide(test_dir)
    print(f"指南已生成: {output}")


path: scripts/migrator.py
content: #!/usr/bin/env python3
"""
为知笔记附件迁移模块
"""

import os
import shutil
from pathlib import Path
from typing import Dict


def run_attachment_migration(source_dir, target_dir, script_path=None):
    """
    运行附件迁移
    
    Args:
        source_dir: 源数据目录（包含 _Attachments）
        target_dir: 目标目录
        script_path: 可选的批处理脚本路径
        
    Returns:
        dict: 迁移结果统计
    """
    source = Path(source_dir).resolve()
    target = Path(target_dir).resolve()
    
    if not source.exists():
        raise FileNotFoundError(f"源目录不存在: {source}")
    
    # 创建目标根目录
    target.mkdir(parents=True, exist_ok=True)
    
    stats = {
        "copied": 0,
        "skipped": 0,
        "failed": 0,
        "total_size": 0
    }
    
    print(f"正在扫描附件目录...")
    
    # 方法1: 使用批处理脚本（Windows）
    if script_path and os.name == 'nt' and Path(script_path).exists():
        return _run_batch_script(script_path, source_dir, target_dir)
    
    # 方法2: Python 实现跨平台版本
    return _copy_attachments_python(source, target, stats)


def _run_batch_script(script_path, source_dir, target_dir):
    """
    运行 Windows 批处理脚本
    
    注意：这会启动一个新进程，不是在 Python 中复制
    """
    import subprocess
    
    # 修改脚本中的路径
    script_content = Path(script_path).read_text(encoding='utf-8')
    
    # 替换路径
    script_content = script_content.replace(
        'set "SOURCE_DIR=C:\\Users\\Administrator\\Documents\\My Knowledge"',
        f'set "SOURCE_DIR={source_dir}"'
    )
    script_content = script_content.replace(
        'set "TARGET_DIR=G:\\Data\\knowledge\\wiz"',
        f'set "TARGET_DIR={target_dir}"'
    )
    
    # 写入临时脚本
    temp_script = Path("temp_copy_attachments.bat")
    temp_script.write_text(script_content, encoding='utf-8')
    
    try:
        print("正在运行批处理脚本...")
        result = subprocess.run(
            [str(temp_script)],
            shell=True,
            capture_output=True,
            text=True,
            encoding='utf-8'
        )
        
        print(result.stdout)
        if result.stderr:
            print(f"错误输出: {result.stderr}")
        
        # 解析结果（批处理脚本里的统计比较困难，简单返回）
        return {
            "copied": 0,  # 无法精确获取
            "skipped": 0,
            "failed": 0,
            "via_batch": True
        }
    finally:
        if temp_script.exists():
            temp_script.unlink()


def _copy_attachments_python(source: Path, target: Path, stats: Dict):
    """
    Python 实现附件复制
    
    查找并复制所有 _Attachments 目录
    """
    print(f"源目录: {source}")
    print(f"目标目录: {target}")
    print()
    
    # 查找所有 _Attachments 目录
    attachments_dirs = []
    
    # 递归查找
    for root, dirs, files in os.walk(source):
        for d in dirs:
            if d == "_Attachments" or d.endswith("_files"):
                attachments_dirs.append(Path(root) / d)
    
    if not attachments_dirs:
        print("⚠️  未找到 _Attachments 或 _files 目录")
        print("请确认:")
        print("  1. 源目录是否正确")
        print("  2. 是否为导出的 Wiz 数据")
        return stats
    
    print(f"找到 {len(attachments_dirs)} 个附件目录\n")
    
    total = len(attachments_dirs)
    
    for idx, attach_dir in enumerate(attachments_dirs, 1):
        try:
            # 计算相对路径
            rel_path = attach_dir.relative_to(source)
            dest_path = target / rel_path
            
            print(f"[{idx}/{total}] 处理: {rel_path}")
            
            if dest_path.exists():
                # 已存在，统计文件数量
                existing_files = list(dest_path.rglob("*"))
                existing_file_count = sum(1 for f in existing_files if f.is_file())
                print(f"  ⏭️  已存在，跳过 ({existing_file_count} 个文件)")
                stats["skipped"] += existing_file_count
                continue
            
            # 复制目录
            shutil.copytree(attach_dir, dest_path)
            
            # 统计文件数量
            copied_files = list(dest_path.rglob("*"))
            file_count = sum(1 for f in copied_files if f.is_file())
            
            stats["copied"] += file_count
            print(f"  ✅ 复制完成 ({file_count} 个文件)")
            
        except Exception as e:
            print(f"  ❌ 复制失败: {e}")
            stats["failed"] += 1
    
    print()
    print("=" * 60)
    print("统计结果:")
    print(f"  处理目录数: {total}")
    print(f"  ✅ 新复制文件: {stats['copied']}")
    print(f"  ⏭️  已存在跳过: {stats['skipped']}")
    print(f"  ❌ 失败目录: {stats['failed']}")
    print("=" * 60)
    
    return stats


def find_attachments(source_dir):
    """
    查找所有附件目录（供外部调用）
    
    Returns:
        list: 附件目录路径列表
    """
    source = Path(source_dir)
    attachments = []
    
    for root, dirs, files in os.walk(source):
        for d in dirs:
            if d == "_Attachments" or d.endswith("_files"):
                attachments.append(Path(root) / d)
    
    return attachments


def copy_attachments_batch(source_dir, target_dir):
    """
    批量复制附件（简化接口）
    
    Returns:
        dict: 统计信息
    """
    stats = {"copied": 0, "skipped": 0, "failed": 0}
    return run_attachment_migration(source_dir, target_dir, stats)


if __name__ == "__main__":
    import sys
    
    if len(sys.argv) >= 3:
        source = sys.argv[1]
        target = sys.argv[2]
        result = run_attachment_migration(source, target)
        print(json.dumps(result, indent=2, ensure_ascii=False))
    else:
        print("使用方法:")
        print("  python migrator.py <源目录> <目标目录>")
        print("\n示例:")
        print('  python migrator.py "C:\\Users\\Admin\\Documents\\My Knowledge" "G:\\Data\\wiz"')


path: skill.json
content: {
  "name": "wiz-migration",
  "description": "为知笔记迁移辅助技能，提供自动检测存储目录、导出操作引导、附件批量迁移等完整迁移流程",
  "version": "1.0.0",
  "author": "Awam Wang",
  "homepage": "https://github.com/awamwang/wiz-migration",
  "repository": {
    "type": "git",
    "url": "https://github.com/awamwang/wiz-migration.git"
  },
  "supported_models": ["*"],
  "tags": ["migration", "wiz", "notes", "data-migration"],
  "license": "MIT",
  "min_claw_version": "2025.1.0"
}

path: test_import.py
content: #!/usr/bin/env python3
"""
为知笔记迁移技能 - 测试脚本
"""

import sys
from pathlib import Path

# 添加技能目录到路径
SKILL_DIR = Path(__file__).parent.parent
sys.path.insert(0, str(SKILL_DIR))

print("正在测试 wiz_migration 技能导入...")

try:
    import wiz_migration
    print(f"✅ 包导入成功，版本: {wiz_migration.__version__}")
    
    # 测试函数是否存在
    functions = [
        'detect_wiz_data_dir',
        'validate_data_dir',
        'generate_export_guide',
        'run_attachment_migration',
        'start_wizard'
    ]
    
    print("\n检查导出函数:")
    for func in functions:
        if hasattr(wiz_migration, func):
            print(f"  ✅ {func}")
        else:
            print(f"  ❌ 缺失: {func}")
    
    # 测试检测功能
    print("\n测试自动检测:")
    detected = wiz_migration.detect_wiz_data_dir()
    if detected:
        print(f"  ✅ 检测到目录: {detected}")
    else:
        print("  ⚠️  未检测到目录（正常，如果不存在标准安装）")
    
    print("\n✅ 所有测试通过！技能已就绪。")
    
except Exception as e:
    print(f"❌ 导入失败: {e}")
    import traceback
    traceback.print_exc()
    sys.exit(1)


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