Skill: tonakic/up-skill-to-clawhub (version 1.0.0)

--- name: up-skill-to-clawhub description: Package and publish OpenClaw skills to ClawHub registry. Use when user wants to upload, publish, or update a skill to ClawHub. Triggers on phrases like "upload skill", "publish skill", "push to clawhub", "update skill on clawhub". --- # Up Skill to ClawHub / 上传技能到 ClawHub **English**: A workflow guide for packaging and publishing OpenClaw skills to ClawHub registry. **中文**: 打包并发布 OpenClaw 技能到 ClawHub 注册表的工作流程指南。 --- ## Prerequisites / 前提条件 ### English 1. ClawHub account and API token 2. Skill folder with valid SKILL.md 3. `npx clawhub@latest` CLI tool ### 中文 1. ClawHub 账户和 API Token 2. 包含有效 SKILL.md 的技能文件夹 3. `npx clawhub@latest` CLI 工具 --- ## Quick Start / 快速开始 ### English ```bash # Login to ClawHub npx clawhub@latest login --token YOUR_API_TOKEN --no-browser # Publish skill npx clawhub@latest publish /path/to/skill-folder --version 1.0.0 ``` ### 中文 ```bash # 登录 ClawHub npx clawhub@latest login --token YOUR_API_TOKEN --no-browser # 发布技能 npx clawhub@latest publish /path/to/skill-folder --version 1.0.0 ``` --- ## Workflow Steps / 工作流程 ### Step 1: Prepare Skill / 步骤 1：准备技能 **English**: Ensure the skill folder contains required files: - `SKILL.md` - Main skill documentation (required) - `_meta.json` - Metadata with version info - `scripts/` - Python/shell scripts - `references/` - Config files, sample data **中文**: 确保技能文件夹包含必要文件： - `SKILL.md` - 主技能文档（必需） - `_meta.json` - 包含版本信息的元数据 - `scripts/` - Python/shell 脚本 - `references/` - 配置文件、示例数据 **File Structure / 文件结构**: ``` skill-name/ ├── SKILL.md # Required / 必需 ├── _meta.json # Metadata / 元数据 ├── scripts/ │ └── main.py # Scripts / 脚本 └── references/ └── config.json # Configs / 配置 ``` ### Step 2: Update Version / 步骤 2：更新版本 **English**: Update `_meta.json` with new version: ```json { "ownerId": "YOUR_OWNER_ID", "slug": "skill-name", "version": "1.0.1", "publishedAt": 1700000000000 } ``` **中文**: 更新 `_meta.json` 版本号： ```json { "ownerId": "YOUR_OWNER_ID", "slug": "skill-name", "version": "1.0.1", "publishedAt": 1700000000000 } ``` ### Step 3: Sanitize Sensitive Data / 步骤 3：清理敏感数据 **English**: ⚠️ IMPORTANT: Before publishing, remove or replace: - Real MAC addresses → Use `AA:BB:CC:DD:EE:FF` - Real IP addresses → Use `192.168.1.100` - Real API keys → Use `YOUR_API_KEY` or `sk-xxx...` - Real passwords → Use `YOUR_PASSWORD` - Personal device names → Use `example-pc`, `my-device` - Real phone numbers → Use `+1-555-123-4567` - Real email addresses → Use `[REDACTED_SECRET]` **中文**: ⚠️ 重要：发布前必须移除或替换： - 真实 MAC 地址 → 使用 `AA:BB:CC:DD:EE:FF` - 真实 IP 地址 → 使用 `192.168.1.100` - 真实 API 密钥 → 使用 `YOUR_API_KEY` 或 `sk-xxx...` - 真实密码 → 使用 `YOUR_PASSWORD` - 个人设备名称 → 使用 `example-pc`、`my-device` - 真实电话号码 → 使用 `+1-555-123-4567` - 真实邮箱地址 → 使用 `[REDACTED_SECRET]` ### Step 4: Update Documentation / 步骤 4：更新文档 **English**: Update SKILL.md with: - Version number in changelog - New features/changes - Bilingual (EN/CN) documentation **中文**: 更新 SKILL.md： - 更新日志中的版本号 - 新功能/变更说明 - 中英文双语文档 ### Step 5: Login to ClawHub / 步骤 5：登录 ClawHub **English**: ```bash npx clawhub@latest login --token YOUR_API_TOKEN --no-browser ``` **中文**: ```bash npx clawhub@latest login --token YOUR_API_TOKEN --no-browser ``` ### Step 6: Publish / 步骤 6：发布 **English**: ```bash npx clawhub@latest publish /path/to/skill-folder \ --version 1.0.1 \ --changelog "Added new feature. Fixed bug." ``` **中文**: ```bash npx clawhub@latest publish /path/to/skill-folder \ --version 1.0.1 \ --changelog "添加新功能。修复问题。" ``` ### Step 7: Verify & Restore / 步骤 7：验证并恢复 **English**: 1. Verify publication on clawhub.ai 2. Restore real configuration if needed for local use **中文**: 1. 在 clawhub.ai 验证发布成功 2. 如需本地使用，恢复真实配置 --- ## CLI Reference / CLI 命令参考 ### Login / 登录 ```bash npx clawhub@latest login --token YOUR_API_TOKEN --no-browser ``` ### Publish / 发布 ```bash npx clawhub@latest publish <path> [options] ``` | Option | Description | 说明 | |--------|-------------|------| | `--version <ver>` | Version (semver) | 版本号（语义化版本） | | `--slug <slug>` | Skill slug | 技能标识符 | | `--changelog <text>` | Changelog text | 更新日志 | | `--tags <tags>` | Comma-separated tags | 逗号分隔的标签 | ### Check Login / 检查登录状态 ```bash npx clawhub@latest whoami ``` ### Search / 搜索 ```bash npx clawhub@latest search <query> ``` ### Install / 安装 ```bash npx clawhub@latest install <slug> ``` --- ## Example Session / 示例会话 **User / 用户**: "Upload my skill to clawhub, version 1.0.1" **Agent actions / Agent 操作**: 1. Check skill folder structure / 检查技能文件夹结构 2. Update `_meta.json` version / 更新版本号 3. Scan for sensitive data / 扫描敏感数据 4. Replace with generic values / 替换为通用值 5. Login to ClawHub / 登录 ClawHub 6. Publish with changelog / 发布并附带更新日志 7. Report success / 报告成功 8. Restore original config / 恢复原始配置 --- ## Troubleshooting / 故障排除 ### "Not logged in" / "未登录" ```bash npx clawhub@latest login --token YOUR_API_TOKEN --no-browser ``` ### "Path must be a folder" / "路径必须是文件夹" - Ensure path points to a directory / 确保路径指向目录 - Check SKILL.md exists / 检查 SKILL.md 是否存在 ### "Version must be valid semver" / "版本号必须是有效的语义化版本" - Use format: `1.0.0`, `1.0.1`, `2.0.0` / 使用格式：`1.0.0`、`1.0.1`、`2.0.0` ### Publishing fails / 发布失败 1. Check internet connection / 检查网络连接 2. Verify API token is valid / 验证 API Token 有效 3. Ensure version is higher than existing / 确保版本号高于现有版本 --- ## Security Checklist / 安全检查清单 Before publishing, verify / 发布前验证： - [ ] No real MAC addresses / 无真实 MAC 地址 - [ ] No real IP addresses / 无真实 IP 地址 - [ ] No API keys or tokens / 无 API 密钥或令牌 - [ ] No passwords / 无密码 - [ ] No personal names or devices / 无个人姓名或设备名 - [ ] No phone numbers / 无电话号码 - [ ] No email addresses / 无邮箱地址 - [ ] No private URLs / 无私有 URL --- ## Skill Template / 技能模板 ``` skill-name/ ├── SKILL.md # Main documentation / 主文档 ├── _meta.json # Metadata / 元数据 ├── scripts/ │ └── main.py # Main script / 主脚本 └── references/ ├── config.json # Config template / 配置模板 └── README.md # Reference docs / 参考文档 ``` ### SKILL.md Template / SKILL.md 模板 ```markdown --- name: skill-name description: Brief description of what this skill does. --- # Skill Name / 技能名称 **English**: Description in English. **中文**: 中文描述。 ## Quick Start / 快速开始 ## Usage / 使用方法 ## Configuration / 配置 ## Troubleshooting / 故障排除 ``` ### _meta.json Template / _meta.json 模板 ```json { "ownerId": "YOUR_OWNER_ID", "slug": "skill-name", "version": "1.0.0", "publishedAt": 1700000000000 } ```

path: _meta.json
content: ownerId: kn74fv0nv7m451zfc47ctgppr583ahqw
slug: up-skill-to-clawhub
version: 1.0.0
publishedAt: 0

path: references/config.template.json
content: _comment: ClawHub API configuration template. Copy to local config and fill in your values.
_comment_cn: ClawHub API 配置模板。复制到本地配置并填入你的值。
apiToken: YOUR_CLAWHUB_API_TOKEN
ownerId: YOUR_OWNER_ID
_note: This file should NOT be published to ClawHub. Add to .gitignore.
_note_cn: 此文件不应发布到 ClawHub。请添加到 .gitignore。

path: scripts/scan_sensitive.py
content: #!/usr/bin/env python3
"""
Scan skill folder for sensitive data before publishing to ClawHub.
扫描技能文件夹中的敏感数据，在发布到 ClawHub 之前检查。

Usage / 用法:
    python3 scan_sensitive.py /path/to/skill-folder
"""

import os
import re
import sys
from pathlib import Path
from typing import List, Tuple

# Patterns for sensitive data / 敏感数据匹配模式
SENSITIVE_PATTERNS = [
    # MAC addresses (not generic AA:BB:CC:DD:EE:FF)
    (r'(?i)(?<!AA:BB:CC:DD:EE:FF)([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}', 'MAC address / MAC 地址'),
    
    # IP addresses (private ranges, exclude common examples)
    (r'\b(192\.168\.\d{1,3}\.\d{1,3})\b', 'Private IP address / 私有 IP 地址'),
    (r'\b(10\.\d{1,3}\.\d{1,3}\.\d{1,3})\b', 'Private IP address / 私有 IP 地址'),
    (r'\b(172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b', 'Private IP address / 私有 IP 地址'),
    
    # API keys and tokens
    (r'(?i)(api[_-]?key|token|secret|password)\s*[=:]\s*["\']?[^\s"\'<>]+', 'API key/Token/Password / API密钥/令牌/密码'),
    (r'(?i)(sk-[a-zA-Z0-9]{20,})', 'API key (OpenAI style) / API 密钥'),
    (r'(?i)(clh_[a-zA-Z0-9]{20,})', 'ClawHub API token / ClawHub API 令牌'),
    
    # Phone numbers
    (r'\b\+?[1-9]\d{1,3}[-.\s]?\d{3,4}[-.\s]?\d{4}\b', 'Phone number / 电话号码'),
    
    # Email addresses
    (r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', 'Email address / 邮箱地址'),
]

# Whitelist patterns (safe to include) / 白名单模式（安全可包含）
WHITELIST = [
    r'192\.168\.1\.\d+',  # Common example subnet / 常见示例子网
    r'example\.com',
    r'user@example',
    r'YOUR_',
    r'xxx',
    r'placeholder',
    r'AA:BB:CC:DD:EE:FF',
]


def is_whitelisted(text: str) -> bool:
    """Check if text matches whitelist patterns."""
    for pattern in WHITELIST:
        if re.search(pattern, text, re.IGNORECASE):
            return True
    return False


def scan_file(file_path: Path) -> List[Tuple[int, str, str]]:
    """Scan a file for sensitive data patterns.
    
    Returns list of (line_number, matched_text, pattern_name)
    """
    findings = []
    
    try:
        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
            lines = f.readlines()
    except Exception:
        return findings
    
    for line_num, line in enumerate(lines, 1):
        for pattern, name in SENSITIVE_PATTERNS:
            matches = re.finditer(pattern, line)
            for match in matches:
                matched_text = match.group(0)
                if not is_whitelisted(matched_text):
                    findings.append((line_num, matched_text, name))
    
    return findings


def scan_folder(folder_path: Path) -> dict:
    """Scan all files in a folder for sensitive data.
    
    Returns dict: {file_path: [(line_num, matched_text, pattern_name), ...]}
    """
    results = {}
    
    for root, dirs, files in os.walk(folder_path):
        # Skip hidden directories and common non-text dirs
        dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', '__pycache__', '.git']]
        
        for file in files:
            if file.startswith('.'):
                continue
            
            file_path = Path(root) / file
            
            # Only scan text files
            text_extensions = {'.md', '.json', '.py', '.sh', '.txt', '.yaml', '.yml', '.toml', '.js', '.ts'}
            if file_path.suffix.lower() not in text_extensions:
                continue
            
            findings = scan_file(file_path)
            if findings:
                results[file_path] = findings
    
    return results


def main():
    if len(sys.argv) < 2:
        print("Usage / 用法: python3 scan_sensitive.py <skill-folder>")
        print("\nScans skill folder for sensitive data before publishing.")
        print("在发布前扫描技能文件夹中的敏感数据。")
        return 1
    
    folder = Path(sys.argv[1])
    if not folder.exists():
        print(f"Error / 错误: Folder not found / 文件夹不存在: {folder}")
        return 1
    
    print(f"Scanning / 正在扫描: {folder}")
    print("-" * 50)
    
    results = scan_folder(folder)
    
    if not results:
        print("\n✓ No sensitive data found / 未发现敏感数据")
        print("  Safe to publish / 可以安全发布")
        return 0
    
    print("\n⚠ Sensitive data found / 发现敏感数据:\n")
    
    for file_path, findings in results.items():
        rel_path = file_path.relative_to(folder)
        print(f"📄 {rel_path}")
        for line_num, matched_text, pattern_name in findings:
            print(f"   Line {line_num}: {pattern_name}")
            print(f"   → {matched_text}")
        print()
    
    print("Please replace with generic values before publishing.")
    print("请在发布前替换为通用值。")
    return 1


if __name__ == "__main__":
    sys.exit(main())


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