Skill: kaising-openclaw1/cli-notion (version 1.0.0)

# CLI-Notion SKILL.md **Version**: 1.0.0 **Type**: CLI Tool **Interface**: Command Line + JSON --- ## Description CLI-Notion 是 Notion 的命令行接口，让 AI Agent 可以直接操作 Notion。 --- ## Installation 设置环境变量： ```bash export NOTION_API_KEY=your_integration_secret ``` --- ## Commands ```bash # 创建页面 python cli-notion.py create-page --parent DB_ID --title "Task" # 列出页面 python cli-notion.py list-pages --database DB_ID # 获取页面 python cli-notion.py get-page PAGE_ID # 状态检查 python cli-notion.py status ``` --- ## License 商业许可 - ¥68

path: README.md
content: # CLI-Notion 🔷

**让 AI Agent 直接操作 Notion**

## 快速开始

```bash
# 设置 API Key
export NOTION_API_KEY=your_api_key

# 创建页面
python cli-notion.py create-page --parent DATABASE_ID --title "New Task"

# 列出页面
python cli-notion.py list-pages --database DATABASE_ID

# 获取页面
python cli-notion.py get-page PAGE_ID

# 检查状态
python cli-notion.py status

# JSON 输出 (Agent 使用)
python cli-notion.py --json list-pages --database DATABASE_ID
```

## 功能

- ✅ 创建页面
- ✅ 列出页面
- ✅ 获取页面详情
- ✅ API 状态检查
- ✅ JSON 输出 (AI Agent 集成)

## 获取 Notion API Key

1. 访问 https://www.notion.so/my-integrations
2. 创建新的 Integration
3. 复制 Internal Integration Secret

## 价格

- 早鸟价：¥48 (前 20 名)
- 正常价：¥68


path: _meta.json
content: {
  "name": "cli-notion",
  "version": "1.0.0",
  "description": "CLI interface for Notion - Make your workspace agent-native",
  "author": "CLI Skill Factory",
  "category": "productivity",
  "price": 68,
  "currency": "CNY",
  "license": "commercial",
  "python_version": ">=3.10",
  "tags": ["notion", "cli", "automation", "ai", "agent", "workspace"],
  "repository": "https://github.com/openclaw/workspace",
  "created_at": "2026-04-01T14:15:00+08:00"
}


path: cli-notion.py
content: #!/usr/bin/env python3
"""
CLI-Notion: Notion 命令行接口
让 AI Agent 可以直接操作 Notion
"""

import click
import json
import os
import requests
from pathlib import Path


@click.group(invoke_without_command=True)
@click.option('--api-key', envvar='NOTION_API_KEY', help='Notion API Key')
@click.option('--json', 'json_output', is_flag=True, help='Output in JSON format')
@click.pass_context
def cli(ctx, api_key, json_output):
    """CLI-Notion: Notion 命令行接口"""
    ctx.ensure_object(dict)
    ctx.obj['json_output'] = json_output
    ctx.obj['api_key'] = api_key
    ctx.obj['headers'] = {
        'Authorization': f'Bearer {api_key}',
        'Notion-Version': '2022-06-28',
        'Content-Type': 'application/json'
    } if api_key else {}
    
    if ctx.invoked_subcommand is None:
        click.echo("Use --help for available commands")


@cli.command()
@click.option('--parent', required=True, help='Parent database ID')
@click.option('--title', required=True, help='Page title')
@click.pass_context
def create_page(ctx, parent, title):
    """创建页面"""
    [REDACTED_SECRET]'api_key')
    if not [REDACTED_SECRET]"✗ 错误：需要 NOTION_API_KEY")
        return
    
    url = 'https://api.notion.com/v1/pages'
    data = {
        "parent": {"database_id": parent},
        "properties": {
            "Name": {
                "title": [{"text": {"content": title}}]
            }
        }
    }
    
    try:
        response = requests.post(url, headers=ctx.obj['headers'], json=data)
        response.raise_for_status()
        result = response.json()
        
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"action": "create_page", "id": result['id'], "title": title}))
        else:
            click.echo(f"✓ 已创建页面：{title}")
    except requests.exceptions.RequestException as e:
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"error": str(e)}))
        else:
            click.echo(f"✗ 创建失败：{str(e)}")


@cli.command()
@click.option('--database', required=True, help='Database ID')
@click.pass_context
def list_pages(ctx, database):
    """列出数据库中的页面"""
    [REDACTED_SECRET]'api_key')
    if not [REDACTED_SECRET]"✗ 错误：需要 NOTION_API_KEY")
        return
    
    url = f'https://api.notion.com/v1/databases/{database}/query'
    
    try:
        response = requests.post(url, headers=ctx.obj['headers'])
        response.raise_for_status()
        result = response.json()
        
        pages = []
        for page in result.get('results', []):
            title = page['properties'].get('Name', {}).get('title', [{}])[0].get('plain_text', 'Untitled')
            pages.append({"id": page['id'], "title": title})
        
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"pages": pages}))
        else:
            click.echo(f"📊 找到 {len(pages)} 个页面:")
            for p in pages[:10]:
                click.echo(f"  - {p['title']}")
            if len(pages) > 10:
                click.echo(f"  ... 还有 {len(pages) - 10} 个")
    except requests.exceptions.RequestException as e:
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"error": str(e)}))
        else:
            click.echo(f"✗ 查询失败：{str(e)}")


@cli.command()
@click.argument('page_id')
@click.pass_context
def get_page(ctx, page_id):
    """获取页面详情"""
    [REDACTED_SECRET]'api_key')
    if not [REDACTED_SECRET]"✗ 错误：需要 NOTION_API_KEY")
        return
    
    url = f'https://api.notion.com/v1/pages/{page_id}'
    
    try:
        response = requests.get(url, headers=ctx.obj['headers'])
        response.raise_for_status()
        result = response.json()
        
        if ctx.obj.get('json_output'):
            click.echo(json.dumps(result))
        else:
            click.echo(f"📄 页面详情：{page_id}")
    except requests.exceptions.RequestException as e:
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"error": str(e)}))
        else:
            click.echo(f"✗ 获取失败：{str(e)}")


@cli.command()
@click.pass_context
def status(ctx):
    """检查 API 状态"""
    [REDACTED_SECRET]'api_key')
    
    if not api_key:
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"status": "error", "message": "No API key"}))
        else:
            click.echo("✗ 未设置 NOTION_API_KEY")
        return
    
    # 简单测试：尝试获取用户信息
    url = 'https://api.notion.com/v1/users/me'
    try:
        response = requests.get(url, headers=ctx.obj['headers'])
        if response.status_code == 200:
            user = response.json()
            if ctx.obj.get('json_output'):
                click.echo(json.dumps({"status": "ok", "user": user['name']}))
            else:
                click.echo(f"✓ API 正常 | 用户：{user['name']}")
        else:
            if ctx.obj.get('json_output'):
                click.echo(json.dumps({"status": "error", "code": response.status_code}))
            else:
                click.echo(f"✗ API 错误：{response.status_code}")
    except requests.exceptions.RequestException as e:
        if ctx.obj.get('json_output'):
            click.echo(json.dumps({"status": "error", "message": str(e)}))
        else:
            click.echo(f"✗ 连接失败：{str(e)}")


if __name__ == '__main__':
    cli()


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