Skill: mojo-bo-coder/hivulse-openclaw-skill (version 0.1.4)

--- name: hivulseAI description: hivulse蜂巢 AI 是一款面向软件开发的自动化技术文档生成工具，通过指定目录代码一键生成多种规范化技术文档。目前已支持的文档类型包括：用户需求说明书、需求规格说明书、系统概要设计说明、系统详细设计说明等10几种报告。申请API Key请访问 www.hivulse.com metadata: { "openclaw": { "emoji": "📄", "requires": { "env": ["HIVULSE_API_KEY"] }, "primaryEnv": "HIVULSE_API_KEY" } } user-invocable: true --- # hivulseAI - 自动化技术文档生成工具 通过API接口将指定目录的文件上传并生成各种技术文档的完整自动化工具。 ## 🚀 快速开始 ### 环境变量设置 ```bash export HIVULSE_API_KEY="your-api-key-here" ``` ## 📋 支持的文档类型 | 编号 | 文档类型 | 描述 | |------|----------|------| | 19 | 用户需求说明书 | 用户需求分析文档 | | 2 | 需求规格说明书 | 详细需求规格 | | 4 | 系统概要设计说明 | 系统架构设计 | | 5 | 系统详细设计说明 | 详细设计文档 | | 8 | 软件单元测试计划 | 单元测试计划 | | 9 | 软件单元测试用例 | 单元测试用例 | | 10 | 软件单元测试报告 | 单元测试报告 | | 1 | 系统测试计划 | 系统测试计划 | | 12 | 系统测试用例 | 系统测试用例 | | 15 | 系统测试报告 | 系统测试报告 | | 13 | 网络安全漏洞自评报告 | 安全评估报告 | | 20 | 软件用户测试用例 | 用户测试用例 | | 21 | 软件用户测试报告 | 用户测试报告 | ## 🎯 触发关键词 在OpenClaw会话中，当用户提到以下关键词时会自动触发此技能： - "生成技术文档" - "创建文档" - "文档生成" - "hivulseAI" - "上传代码生成文档" - "需求规格说明书" - "系统设计文档" ## 🔧 OpenClaw技能调用方式 ### 方式1：直接触发 在对话中直接使用触发关键词，例如： - "帮我生成技术文档" - "使用hivulseAI生成需求规格说明书" - "为这个项目创建系统设计文档" ## 📋 参数说明 | 参数 | 说明 | 示例 | |------|------|------| | 项目路径 | 要生成文档的代码项目目录 | `/Users/project/myapp` | | 文档类型 | 文档类型编号（2-21） | `2`（需求规格说明书） | | 任务名称 | 可选，文档任务名称 | `"项目需求分析"` | ## 🌐 API配置 - **API密钥**：通过配置文件设置，无需环境变量 ### 配置文件位置： `~/.hivulseai/config.json` ### 手动编辑配置： ```json { "api_key": "your-api-key-here", "last_used_directory": "" } ``` ## 📁 文件过滤规则 系统会自动过滤以下目录和文件： - `node_modules` - Node.js依赖目录 - `venv` - Python虚拟环境 - `.git` - Git版本控制 - `__pycache__` - Python缓存 - `.idea` - IDE配置 - `.vscode` - VS Code配置 - `*.pyc` - Python编译文件 - `*.log` - 日志文件 ## 🔄 API调用流程 ### 1. 文件上传阶段 ```bash POST /api/v1/repo/upload/file/ - 第一个文件：不带branch_id - 后续文件：带branch_id（从第一个文件响应中获取） ``` ### 2. 状态检查阶段 ```bash POST /api/v1/repo/upload/status/ - 参数：uuid（使用default_branch_id） ``` ### 3. 文档生成阶段 ```bash POST /api/v1/template_wiki/ - 参数：task_name, template_base_id, branch_id, repo_id, is_advanced ``` ## ⚠️ 注意事项 1. **API密钥安全**：确保`HIVULSE_API_KEY`环境变量正确设置 2. **网络连接**：确保可以访问指定的API地址 3. **文件权限**：确保对目标目录有读取权限 4. **文件大小**：注意单个文件大小限制 5. **备份重要文件**：建议先备份重要代码 ## 🛠️ 故障排除 ### 常见错误 - "API密钥未设置" → 检查`HIVULSE_API_KEY`环境变量 - "目录不存在" → 检查路径是否正确 - "上传失败" → 检查网络连接和API服务状态 - "文档类型不支持" → 检查文档类型编号 ## 📞 支持 如有问题，请检查： 1. API服务是否正常运行 2. 环境变量是否正确设置 3. 网络连接是否正常 4. 文件路径和权限是否正确

path: README.md
content: # hivulseAI

自动化技术文档生成工具，通过API接口将指定目录的文件上传并生成各种技术文档。

## 功能特性

- 🔍 自动扫描目录文件，过滤无关目录（node_modules、venv等）
- 📤 批量文件上传到API接口
- 📄 支持13种技术文档类型生成
- 🚀 完整的自动化流程
- 💻 支持命令行和交互式两种使用方式

## 支持的文档类型

| 编号 | 文档类型 |
|------|----------|
| 19 | 用户需求说明书 |
| 2 | 需求规格说明书 |
| 4 | 系统概要设计说明 |
| 5 | 系统详细设计说明 |
| 8 | 软件单元测试计划 |
| 9 | 软件单元测试用例 |
| 10 | 软件单元测试报告 |
| 1 | 系统测试计划 |
| 12 | 系统测试用例 |
| 15 | 系统测试报告 |
| 13 | 网络安全漏洞自评报告 |
| 20 | 软件用户测试用例 |
| 21 | 软件用户测试报告 |

## 安装依赖

```bash
pip install -r requirements.txt
```

## 使用方法

### 交互式使用

```bash
python interactive.py
```

按照提示：
1. 输入项目目录路径
2. 选择文档类型编号
3. 确认开始处理

### 命令行使用

```bash
python hivulseAI.py <目录路径> <文档类型编号> [--task-name 任务名称] [--base-url API地址]
```

示例：
```bash
python hivulseAI.py /path/to/project 4 --task-name "我的项目系统设计"
```


## 过滤目录

系统会自动过滤以下目录：
- node_modules
- venv
- .git
- __pycache__
- .idea
- .vscode

## 文件结构

```
hivulseAI/
├── SKILL.md          # Skill说明文档
├── hivulseAI.py      # 主程序
├── interactive.py    # 交互式界面
├── requirements.txt  # 依赖包
└── README.md         # 使用说明
```

## 错误处理

- 目录不存在或无法访问时会提示错误
- 文件上传失败会中断流程
- API连接失败会有详细错误信息
- 支持键盘中断操作

## 开发说明

主要类：`HivulseAI`

核心方法：
- `get_directory_files()` - 获取目录文件
- `upload_file()` - 上传单个文件
- `upload_all_files()` - 批量上传
- `check_upload_status()` - 检查上传状态
- `generate_document()` - 生成文档
- `run()` - 完整流程执行

## 注意事项

1. 确保API服务正常运行
2. 目录需要有读取权限
3. 网络连接稳定
4. 文件大小不要超过API限制


path: config.py
content: #!/usr/bin/env python3
"""
配置文件管理模块
"""

import os
import json
from pathlib import Path

class ConfigManager:
    def __init__(self, config_file: str = "config.json"):
        self.config_file = config_file
        self.config_dir = Path.home() / ".hivulseai"
        self.config_path = self.config_dir / config_file
        
        # 确保配置目录存在
        self.config_dir.mkdir(exist_ok=True)
        
        self.config = self._load_config()
    
    def _load_config(self) -> dict:
        """加载配置文件"""
        if self.config_path.exists():
            try:
                with open(self.config_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except (json.JSONDecodeError, IOError):
                # 配置文件损坏，创建新的
                return self._create_default_config()
        else:
            return self._create_default_config()
    
    def _create_default_config(self) -> dict:
        """创建默认配置"""
        return {
            "api_key": "",
            "last_used_directory": ""
        }
    
    def save_config(self) -> bool:
        """保存配置到文件"""
        try:
            with open(self.config_path, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, indent=2, ensure_ascii=False)
            return True
        except IOError:
            return False
    
    def get_api_key(self) -> str:
        """获取API密钥"""
        return self.config.get("api_key", "")
    
    def set_api_key(self, api_key: str):
        """设置API密钥"""
        self.config["api_key"] = api_key
        self.save_config()
    

    
    def get_last_directory(self) -> str:
        """获取上次使用的目录"""
        return self.config.get("last_used_directory", "")
    
    def set_last_directory(self, directory: str):
        """设置上次使用的目录"""
        self.config["last_used_directory"] = directory
        self.save_config()
    
    def has_valid_config(self) -> bool:
        """检查是否有有效的配置"""
        return bool(self.get_api_key())
    
    def show_config(self):
        """显示当前配置"""
        print("\n📋 当前配置:")
        print(f"   API密钥: {'*' * min(len(self.get_api_key()), 20)}..." if self.get_api_key() else "未设置")
        print(f"   API地址: http://localhost:8001 (固定)")
        print(f"   上次目录: {self.get_last_directory() or '无'}")

def setup_config():
    """配置向导"""
    config = ConfigManager()
    
    print("🔧 hivulseAI 配置向导")
    print("=" * 40)
    
    # 显示当前配置
    config.show_config()
    
    # 询问是否修改配置
    if config.has_valid_config():
        choice = input("\n是否修改配置? (y/n): ").strip().lower()
        if choice not in ['y', 'yes', '是']:
            return config
    
    # 设置API密钥
    while True:
        [REDACTED_SECRET]"\n🔑 请输入API密钥: ").strip()
        if [REDACTED_SECRET])
            break
        else:
            print("❌ API密钥不能为空")
    
    # API地址固定为 http://localhost:8001
    print("🌐 API地址已固定为: http://localhost:8001")
    
    print("\n✅ 配置完成!")
    config.show_config()
    
    return config

if __name__ == "__main__":
    setup_config()

path: hivulseAI.py
content: #!/usr/bin/env python3
"""
hivulseAI - 自动化技术文档生成工具
"""

import os
import requests
import json
import time
from pathlib import Path
from typing import List, Dict, Optional, Tuple

class HivulseAI:
    def __init__(self, api_key: str = None):
        # 优先使用传入的参数，否则尝试多种配置源
        self.[REDACTED_SECRET]

        if not self.api_key:
            # 尝试从OpenClaw配置读取
            self.[REDACTED_SECRET])

        if not self.api_key:
            # 尝试从本地配置文件读取
            from config import ConfigManager
            config = ConfigManager()
            self.[REDACTED_SECRET])

        self.base_url = 'https://cloud.hivulse.com'
        self.repo_id = None
        self.default_branch_id = None

        # 文档类型映射
        self.doc_types = {
            "19": "用户需求说明书",
            "2": "需求规格说明书",
            "4": "系统概要设计说明",
            "5": "系统详细设计说明",
            "8": "软件单元测试计划",
            "9": "软件单元测试用例",
            "10": "软件单元测试报告",
            "1": "系统测试计划",
            "12": "系统测试用例",
            "15": "系统测试报告",
            "13": "网络安全漏洞自评报告",
            "20": "软件用户测试用例",
            "21": "软件用户测试报告"
        }

        # 验证API密钥
        if not self.[REDACTED_SECRET]"❌ API密钥未设置")
            print("\n📋 配置方式:")
            print("1. OpenClaw配置界面: 在skills.entries.hivulseAI.apiKey中设置")
            print("2. 本地配置文件: ~/.hivulseai/config.json")
            print("3. 运行配置向导: python3 config.py")
            print("\n💡 推荐使用OpenClaw配置界面设置API密钥")
            raise ValueError("API密钥未配置")

        # 设置请求头，包含API密钥
        self.headers = {}
        if self.[REDACTED_SECRET]'X-API-KEY'] = f'{self.api_key}'

        # 需要过滤的目录
        self.exclude_dirs = {'node_modules', 'venv', '.git', '__pycache__', '.idea', '.vscode'}
        # 需要过滤的文件后缀
        self.exclude_extensions = {'.pyc', '.log'}

    def _get_api_key_from_openclaw_config(self):
        """尝试从OpenClaw配置读取API密钥"""
        try:
            import subprocess
            import json

            # 尝试直接读取OpenClaw配置文件
            config_path = "/Users/superlk/.openclaw/openclaw.json"
            if os.path.exists(config_path):
                with open(config_path, 'r', encoding='utf-8') as f:
                    config_content = f.read()

                # 解析JSON配置
                import re
                # 查找skills.entries.hivulseAI.apiKey字段
                pattern = r'"skills"\s*:\s*{[^}]*"entries"\s*:\s*{[^}]*"hivulseAI"\s*:\s*{[^}]*"apiKey"\s*:\s*"([^"]+)"[^}]*}'
                match = re.search(pattern, config_content)

                if match:
                    [REDACTED_SECRET])
                    if api_key != "__OPENCLAW_REDACTED__":
                        print(f"✅ 从OpenClaw配置读取API密钥")
                        return api_key
                    else:
                        print("⚠️ OpenClaw配置中API密钥被安全隐藏")
                        return None

        except Exception as e:
            print(f"⚠️ 读取OpenClaw配置失败: {e}")
            # 如果无法读取OpenClaw配置，回退到本地配置
            pass

        return None



    def get_directory_files(self, directory: str) -> List[str]:
        """获取目录下所有文件，过滤掉指定目录"""
        file_paths = []

        for root, dirs, files in os.walk(directory):
            # 过滤掉不需要的目录
            dirs[:] = [d for d in dirs if d not in self.exclude_dirs]

            for file in files:
                # 过滤掉不需要的文件后缀
                if any(file.endswith(ext) for ext in self.exclude_extensions):
                    continue
                file_path = os.path.join(root, file)
                file_paths.append(file_path)

        return file_paths



    def upload_file(self, file_path: str, directory: str, branch_id: Optional[str] = None, unified_file_path: str = None) -> Dict:
        """上传单个文件到API"""
        url = f"{self.base_url}/api/v1/claw/upload/file/"

        # 修复路径格式化：使用项目名称开头的相对路径
        project_name = unified_file_path
        relative_path = os.path.relpath(file_path, directory)
        api_file_path = f"{project_name}/{relative_path}"

        with open(file_path, 'rb') as f:
            files = {'file': (os.path.basename(file_path), f)}
            data = {'file_path': api_file_path}

            if branch_id:
                data['branch_id'] = branch_id

            response = requests.post(url, files=files, data=data, headers=self.headers)

            # 如果返回"项目已存在"错误，直接抛出异常，强制重新上传
            if response.status_code == 412 and "项目已经存在" in response.text:
                print(f"⚠️ 项目已存在，API响应: {response.text}")
                raise Exception("项目已存在，需要重新上传")

            response.raise_for_status()
            result = response.json()
            print(f"🔍 API响应详情: {result}")
            return result

    def upload_all_files(self, directory: str) -> bool:
        """上传目录下所有文件"""
        file_paths = self.get_directory_files(directory)

        if not file_paths:
            print("❌ 目录中没有找到文件")
            return False

        print(f"📁 找到 {len(file_paths)} 个文件，开始上传...")

        # 生成统一的file_path：用户目录最后一层_时间戳
        import datetime
        dir_name = os.path.basename(os.path.normpath(directory))
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        unified_file_path = f"{dir_name}_{timestamp}"
        print(f"📝 统一file_path: {unified_file_path}")

        # 直接执行文件上传，不检查已存在项目
        for i, file_path in enumerate(file_paths):
            try:
                print(f"📤 上传文件 {i+1}/{len(file_paths)}: {file_path}")

                relative_path = os.path.relpath(file_path, directory)

                if i == 0:
                    # 第一个文件不带branch_id
                    result = self.upload_file(file_path,directory=directory, unified_file_path=unified_file_path)
                    self.repo_id = result.get('data',{}).get('repo_id')
                    self.default_branch_id = result.get('data',{}).get('default_branch_id')
                    print(f"✅ 第一个文件上传成功，repo_id: {self.repo_id}, branch_id: {self.default_branch_id}")
                else:
                    # 后续文件带branch_id，使用相同的统一file_path
                    result = self.upload_file(file_path,directory=directory,branch_id= self.default_branch_id, unified_file_path=unified_file_path)
                    print(f"✅ 文件上传成功")

            except Exception as e:
                print(f"❌ 文件上传失败: {file_path}, 错误: {e}")
                return False

        return True

    def check_upload_status(self) -> bool:
        """检查上传状态"""
        if not self.default_branch_id:
            print("❌ 没有有效的branch_id")
            return False

        url = f"{self.base_url}/api/v1/claw/upload/status/"
        data = {"uuid": self.default_branch_id}

        try:
            response = requests.post(url, json=data, headers=self.headers)
            response.raise_for_status()

            result = response.json()
            print(f"📊 上传状态: {result}")
            return True

        except Exception as e:
            print(f"❌ 检查上传状态失败: {e}")
            return False

    def generate_document(self, doc_type: str, task_name: str) -> bool:
        """生成指定类型的文档"""
        if not self.repo_id or not self.default_branch_id:
            print("❌ 缺少必要的参数 (repo_id 或 branch_id)")
            return False

        if doc_type not in self.doc_types:
            print(f"❌ 不支持的文档类型: {doc_type}")
            print(f"支持的文档类型: {list(self.doc_types.keys())}")
            return False

        url = f"{self.base_url}/api/v1/claw/template_wiki/"
        data = {
            "task_name": task_name,
            "template_base_id": [{"prefix": "", "uuid": doc_type}],
            "branch_id": self.default_branch_id,
            "repo_id": self.repo_id,
            "is_advanced": False
        }

        try:
            response = requests.post(url, json=data, headers=self.headers)
            response.raise_for_status()

            result = response.json()
            print(f"✅ 文档生成成功: {self.doc_types[doc_type]}")
            print(f"📋 任务ID: {result.get('task_id', '未知')}")
            return True

        except Exception as e:
            print(f"❌ 文档生成失败: {e}")
            return False

    def run(self, directory: str, doc_type: str, task_name: str) -> bool:
        """运行完整的文档生成流程"""
        print(f"🚀 开始处理目录: {directory}")
        print(f"📄 文档类型: {self.doc_types.get(doc_type, doc_type)}")

        # 1. 上传文件
        if not self.upload_all_files(directory):
            return False
        time.sleep(5)
        # 2. 检查上传状态
        if not self.check_upload_status():
            return False

        # 3. 生成文档
        if not self.generate_document(doc_type, task_name):
            return False

        print("🎉 所有操作完成！等待文档生成后邮件回复")
        return True


def show_document_types():
    """显示所有支持的文档类型"""
    doc_types = {
        "19": "用户需求说明书",
        "2": "需求规格说明书",
        "4": "系统概要设计说明",
        "5": "系统详细设计说明",
        "8": "软件单元测试计划",
        "9": "软件单元测试用例",
        "10": "软件单元测试报告",
        "1": "系统测试计划",
        "12": "系统测试用例",
        "15": "系统测试报告",
        "13": "网络安全漏洞自评报告",
        "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    print("\n📋 支持的13种文档类型：")
    print("=" * 40)
    for key, value in doc_types.items():
        print(f"  {key}: {value}")
    print("=" * 40)
    print("\n💡 使用方法: python hivulseAI.py <目录> <文档类型编号>")


def main():
    """命令行入口"""
    import argparse

    parser = argparse.ArgumentParser(description='hivulseAI - 自动化技术文档生成工具')
    parser.add_argument('directory', nargs='?', help='项目目录路径')
    parser.add_argument('doc_type', nargs='?', help='文档类型编号')
    parser.add_argument('--task-name', help='任务名称', default='自动生成技术文档')
    parser.add_argument('--list-types', action='store_true', help='显示所有支持的文档类型')

    args = parser.parse_args()

    # 如果指定了--list-types，显示文档类型列表
    if args.list_types:
        show_document_types()
        return

    # 检查必需参数
    if not args.directory or not args.doc_type:
        print("❌ 错误: 需要指定目录和文档类型")
        print("\n💡 使用方法: python hivulseAI.py <目录> <文档类型编号>")
        print("💡 查看文档类型: python hivulseAI.py --list-types")
        return

    if not os.path.exists(args.directory):
        print(f"❌ 目录不存在: {args.directory}")
        return

    # 验证文档类型
    doc_types = {
        "19": "用户需求说明书", "2": "需求规格说明书", "4": "系统概要设计说明",
        "5": "系统详细设计说明", "8": "软件单元测试计划", "9": "软件单元测试用例",
        "10": "软件单元测试报告", "1": "系统测试计划", "12": "系统测试用例",
        "15": "系统测试报告", "13": "网络安全漏洞自评报告", "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    if args.doc_type not in doc_types:
        print(f"❌ 不支持的文档类型: {args.doc_type}")
        print("💡 使用 --list-types 查看支持的文档类型")
        return

    # 创建实例并运行
    ai = HivulseAI()
    ai.run(args.directory, args.doc_type, args.task_name)


if __name__ == "__main__":
    main()


path: hivulseai_openclaw.py
content: #!/usr/bin/env python3
"""
hivulseAI OpenClaw Skill Implementation

从OpenClaw配置中读取API密钥，支持技能页面直接配置
"""

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

def get_config_value(path):
    """从OpenClaw配置中获取值"""
    try:
        # 直接读取配置文件
        config_file = Path.home() / ".openclaw" / "openclaw.json"

        if config_file.exists():
            with open(config_file, 'r') as f:
                config_data = json.load(f)

            # 从配置中提取apiKey
            if 'skills' in config_data and 'entries' in config_data['skills']:
                hivulse_config = config_data['skills']['entries'].get('hivulseAI', {})
                if path == 'skills.entries.hivulseAI.apiKey':
                    [REDACTED_SECRET]'apiKey', '')
                    # 检查是否是占位符值
                    if api_key and api_key != 'your-hivulse-api-key-here':
                        return api_key
                    return ''


        return ''
    except Exception as e:
        print(f"❌ 读取配置失败: {e}")
        return ''

def get_api_key():
    """获取API密钥，优先从OpenClaw配置中读取"""
    # 1. 先尝试从OpenClaw配置中读取
    [REDACTED_SECRET]'skills.entries.hivulseAI.apiKey')

    if api_key and api_key != 'your-hivulse-api-key-here':
        return api_key

    # 2. 再尝试从环境变量中读取
    [REDACTED_SECRET]'HIVULSE_API_KEY')
    if [REDACTED_SECRET] api_key

    # 3. 如果都没有，提示用户配置
    print("❌ 错误: hivulseAI API密钥未配置")
    print("💡 请在OpenClaw技能页面中配置API密钥:")
    print("   1. 打开OpenClaw配置界面")
    print("   2. 找到 skills.entries.hivulseAI.apiKey")
    print("   3. 输入您的hivulseAI API密钥")
    print("   4. 保存配置")
    print("")
    print("💡 或者设置环境变量:")
    print("   export HIVULSE_API_KEY='your-api-key'")

    return ''



    # 2. 默认使用 http://localhost:8001
    return 'http://localhost:8001'

def validate_directory(directory):
    """验证目录是否存在"""
    if not os.path.exists(directory):
        print(f"❌ 错误: 目录不存在: {directory}")
        return False

    if not os.path.isdir(directory):
        print(f"❌ 错误: 路径不是目录: {directory}")
        return False

    return True

def validate_doc_type(doc_type):
    """验证文档类型"""
    doc_types = {
        "19": "用户需求说明书",
        "2": "需求规格说明书",
        "4": "系统概要设计说明",
        "5": "系统详细设计说明",
        "8": "软件单元测试计划",
        "9": "软件单元测试用例",
        "10": "软件单元测试报告",
        "1": "系统测试计划",
        "12": "系统测试用例",
        "15": "系统测试报告",
        "13": "网络安全漏洞自评报告",
        "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    if doc_type not in doc_types:
        print(f"❌ 错误: 不支持的文档类型: {doc_type}")
        print("📄 支持的文档类型:")
        for key, value in doc_types.items():
            print(f"  {key}: {value}")
        return False

    return True

def main():
    """主函数 - 从命令行参数获取信息"""
    if len(sys.argv) < 3:
        print("❌ 用法: python hivulseai_openclaw.py <目录> <文档类型> [任务名称]")
        print("")
        print("📄 支持的文档类型:")
        doc_types = {
            "19": "用户需求说明书",
            "2": "需求规格说明书",
            "4": "系统概要设计说明",
            "5": "系统详细设计说明",
            "8": "软件单元测试计划",
            "9": "软件单元测试用例",
            "10": "软件单元测试报告",
            "1": "系统测试计划",
            "12": "系统测试用例",
            "15": "系统测试报告",
            "13": "网络安全漏洞自评报告",
            "20": "软件用户测试用例",
            "21": "软件用户测试报告"
        }
        for key, value in doc_types.items():
            print(f"  {key}: {value}")
        sys.exit(1)

    directory = sys.argv[1]
    doc_type = sys.argv[2]
    task_name = sys.argv[3] if len(sys.argv) > 3 else None

    # 验证参数
    if not validate_directory(directory):
        sys.exit(1)

    if not validate_doc_type(doc_type):
        sys.exit(1)

    # 获取API配置
    [REDACTED_SECRET])
    if not [REDACTED_SECRET])


    # 生成任务名称
    if not task_name:
        doc_names = {
            "19": "用户需求说明书",
            "2": "需求规格说明书",
            "4": "系统概要设计说明",
            "5": "系统详细设计说明",
            "8": "软件单元测试计划",
            "9": "软件单元测试用例",
            "10": "软件单元测试报告",
            "1": "系统测试计划",
            "12": "系统测试用例",
            "15": "系统测试报告",
            "13": "网络安全漏洞自评报告",
            "20": "软件用户测试用例",
            "21": "软件用户测试报告"
        }

        project_name = os.path.basename(os.path.abspath(directory))
        doc_name = doc_names.get(doc_type, "技术文档")
        task_name = f"{project_name}项目{doc_name}生成"

    print(f"🚀 hivulseAI 开始处理")
    print(f"📁 目录: {directory}")
    print(f"📄 文档类型: {doc_type}")
    print(f"📋 任务名称: {task_name}")
    print(f"🔑 API密钥: {api_key[:10]}...")

    # 设置环境变量，供主技能使用
    os.environ['HIVULSE_API_KEY'] = api_key

    # 调用主技能
    try:
        skill_dir = Path(__file__).parent
        main_script = skill_dir / "hivulseai_skill.py"

        if main_script.exists():
            # 调用主技能脚本
            cmd = [
                'python3', str(main_script),
                directory, doc_type,
                '--task-name', task_name
            ]

            result = subprocess.run(cmd, cwd=skill_dir)
            sys.exit(result.returncode)
        else:
            print("❌ 主技能脚本不存在")
            sys.exit(1)

    except Exception as e:
        print(f"❌ 执行错误: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()


path: hivulseai_skill.py
content: #!/usr/bin/env python3
"""
hivulseAI OpenClaw Skill Implementation

标准化的OpenClaw技能实现，通过环境变量配置API密钥。
"""

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

def get_config():
    """从配置文件获取配置"""
    from config import ConfigManager
    config = ConfigManager()

    [REDACTED_SECRET])

    if not [REDACTED_SECRET]"❌ 错误: API密钥未设置")
        print("\n📋 请选择配置方式:")
        print("1. 运行配置向导: python3 config.py")
        print("2. 手动编辑配置文件: ~/.hivulseai/config.json")
        print("\n📝 配置文件内容示例:")
        print('''{
  "api_key": "your-api-key-here",
  "last_used_directory": ""
}''')
        sys.exit(1)

    return {
        'api_key': api_key,
    }

def validate_directory(directory):
    """验证目录是否存在"""
    if not os.path.exists(directory):
        print(f"❌ 错误: 目录不存在: {directory}")
        sys.exit(1)

    if not os.path.isdir(directory):
        print(f"❌ 错误: 路径不是目录: {directory}")
        sys.exit(1)

    return os.path.abspath(directory)

def validate_doc_type(doc_type):
    """验证文档类型"""
    doc_types = {
        "19": "用户需求说明书",
        "2": "需求规格说明书",
        "4": "系统概要设计说明",
        "5": "系统详细设计说明",
        "8": "软件单元测试计划",
        "9": "软件单元测试用例",
        "10": "软件单元测试报告",
        "1": "系统测试计划",
        "12": "系统测试用例",
        "15": "系统测试报告",
        "13": "网络安全漏洞自评报告",
        "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    if doc_type not in doc_types:
        print(f"❌ 错误: 不支持的文档类型: {doc_type}")
        print("📄 支持的文档类型:")
        for key, value in doc_types.items():
            print(f"  {key}: {value}")
        sys.exit(1)

    return doc_type

def generate_task_name(directory, doc_type):
    """生成任务名称"""
    doc_names = {
        "19": "用户需求说明书",
        "2": "需求规格说明书",
        "4": "系统概要设计说明",
        "5": "系统详细设计说明",
        "8": "软件单元测试计划",
        "9": "软件单元测试用例",
        "10": "软件单元测试报告",
        "1": "系统测试计划",
        "12": "系统测试用例",
        "15": "系统测试报告",
        "13": "网络安全漏洞自评报告",
        "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    project_name = os.path.basename(os.path.abspath(directory))
    doc_name = doc_names.get(doc_type, "技术文档")

    return f"{project_name}项目{doc_name}生成"

def main():
    """主函数 - 标准OpenClaw技能入口"""
    parser = argparse.ArgumentParser(description='hivulseAI - 自动化技术文档生成')
    parser.add_argument('directory', nargs='?', help='项目目录路径')
    parser.add_argument('doc_type', nargs='?', help='文档类型编号')
    parser.add_argument('--task-name', help='任务名称', default=None)
    parser.add_argument('--interactive', action='store_true', help='交互式模式')
    parser.add_argument('--list-types', action='store_true', help='列出支持的文档类型')

    args = parser.parse_args()

    # 列出支持的文档类型
    if args.list_types:
        doc_types = {
            "19": "用户需求说明书",
            "2": "需求规格说明书",
            "4": "系统概要设计说明",
            "5": "系统详细设计说明",
            "8": "软件单元测试计划",
            "9": "软件单元测试用例",
            "10": "软件单元测试报告",
            "1": "系统测试计划",
            "12": "系统测试用例",
            "15": "系统测试报告",
            "13": "网络安全漏洞自评报告",
            "20": "软件用户测试用例",
            "21": "软件用户测试报告"
        }

        print("\n📋 支持的13种文档类型：")
        print("=" * 40)
        for key, value in doc_types.items():
            print(f"  {key}: {value}")
        print("=" * 40)
        print("\n💡 使用方法: python hivulseai_skill.py <目录> <文档类型编号>")
        print("💡 交互式模式: python hivulseai_skill.py --interactive")
        return

    # 交互式模式
    if args.interactive:
        # 导入交互式模块
        skill_dir = Path(__file__).parent
        interactive_path = skill_dir / "interactive.py"

        if interactive_path.exists():
            os.system(f"python {interactive_path}")
        else:
            print("❌ 交互式模块不存在")
        return

    # 获取配置
    config = get_config()

    # 验证参数
    if not args.directory or not args.doc_type:
        print("❌ 错误: 需要指定目录和文档类型")
        print("💡 用法: python hivulseai_skill.py <目录> <文档类型>")
        print("💡 或使用: python hivulseai_skill.py --interactive")
        print("💡 查看类型: python hivulseai_skill.py --list-types")
        sys.exit(1)

    directory = validate_directory(args.directory)
    doc_type = validate_doc_type(args.doc_type)

    # 生成任务名称
    if args.task_name:
        task_name = args.task_name
    else:
        task_name = generate_task_name(directory, doc_type)


    print(f"🚀 hivulseAI 开始处理")
    print(f"📁 目录: {directory}")
    print(f"📄 文档类型: {doc_type}")
    print(f"📋 任务名称: {task_name}")

    # 导入并执行主逻辑
    try:
        # 动态导入主模块
        skill_dir = Path(__file__).parent
        sys.path.insert(0, str(skill_dir))

        from hivulseAI import HivulseAI

        # 创建实例并执行
        ai = HivulseAI([REDACTED_SECRET]'api_key'])
        success = ai.run(directory, doc_type, task_name)

        if success:
            print("\n🎉 hivulseAI 处理完成！")
            sys.exit(0)
        else:
            print("\n❌ hivulseAI 处理失败")
            sys.exit(1)

    except ImportError as e:
        print(f"❌ 导入错误: {e}")
        print("💡 确保hivulseAI.py文件存在")
        sys.exit(1)
    except Exception as e:
        print(f"❌ 执行错误: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()


path: interactive.py
content: #!/usr/bin/env python3
"""
hivulseAI 交互式界面
"""

import os
import sys
from hivulseAI import HivulseAI
from config import ConfigManager, setup_config

def select_directory():
    """让用户选择目录"""
    while True:
        directory = input("📁 请输入项目目录路径: ").strip()

        if not directory:
            print("❌ 目录不能为空")
            continue

        if not os.path.exists(directory):
            print("❌ 目录不存在，请重新输入")
            continue

        if not os.path.isdir(directory):
            print("❌ 输入的不是目录，请重新输入")
            continue

        return directory

def select_document_type():
    """让用户选择文档类型"""
    doc_types = {
        "19": "用户需求说明书",
        "2": "需求规格说明书",
        "4": "系统概要设计说明",
        "5": "系统详细设计说明",
        "8": "软件单元测试计划",
        "9": "软件单元测试用例",
        "10": "软件单元测试报告",
        "1": "系统测试计划",
        "12": "系统测试用例",
        "15": "系统测试报告",
        "13": "网络安全漏洞自评报告",
        "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    print("\n📄 请选择要生成的文档类型:")
    for key, value in doc_types.items():
        print(f"  {key}: {value}")

    while True:
        choice = input("\n请输入文档类型编号: ").strip()

        if choice in doc_types:
            return choice
        else:
            print("❌ 无效的选择，请重新输入")

def get_task_name(directory: str, doc_type: str) -> str:
    """根据输入生成任务名称"""
    doc_names = {
        "19": "用户需求说明书",
        "2": "需求规格说明书",
        "4": "系统概要设计说明",
        "5": "系统详细设计说明",
        "8": "软件单元测试计划",
        "9": "软件单元测试用例",
        "10": "软件单元测试报告",
        "1": "系统测试计划",
        "12": "系统测试用例",
        "15": "系统测试报告",
        "13": "网络安全漏洞自评报告",
        "20": "软件用户测试用例",
        "21": "软件用户测试报告"
    }

    project_name = os.path.basename(os.path.abspath(directory))
    doc_name = doc_names.get(doc_type, "技术文档")

    return f"{project_name}项目{doc_name}生成"

def main():
    """主交互函数"""
    print("=" * 50)
    print("🚀 hivulseAI - 自动化技术文档生成工具")
    print("=" * 50)

    # 配置管理
    config = setup_config()

    if not config.has_valid_config():
        print("❌ 配置不完整，请先设置API密钥")
        return

    # 获取配置信息
    [REDACTED_SECRET])
    last_directory = config.get_last_directory()

    # 选择目录
    if last_directory and os.path.exists(last_directory):
        use_last = input(f"📁 是否使用上次的目录 ({last_directory})? (y/n): ").strip().lower()
        if use_last in ['y', 'yes', '是']:
            directory = last_directory
        else:
            directory = select_directory()
    else:
        directory = select_directory()

    # 保存当前目录
    config.set_last_directory(directory)

    # 选择文档类型
    doc_type = select_document_type()

    # 生成任务名称
    task_name = get_task_name(directory, doc_type)

    print(f"\n📋 任务信息:")
    print(f"   目录: {directory}")
    print(f"   文档类型: {doc_type}")
    print(f"   任务名称: {task_name}")

    confirm = input("\n确认开始处理? (y/n): ").strip().lower()
    if confirm not in ['y', 'yes', '是']:
        print("👋 操作已取消")
        return

    # 创建实例并运行
    ai = HivulseAI([REDACTED_SECRET])

    try:
        success = ai.run(directory, doc_type, task_name)
        if success:
            print("\n🎉 文档生成流程完成！")
        else:
            print("\n❌ 文档生成流程失败")
    except KeyboardInterrupt:
        print("\n\n👋 用户中断操作")
    except Exception as e:
        print(f"\n❌ 发生错误: {e}")

if __name__ == "__main__":
    main()


path: package.json
content: {
  "name": "hivulseAI",
  "version": "1.0.0",
  "openclaw": {
    "skill": {
      "name": "hivulseAI",
      "version": "1.0.0"
    }
  }
}


path: requirements.txt
content: requests>=2.25.0
pathlib2>=2.3.0

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