Skill: ravchen/nicebox-site-manager (version 1.0.1)

--- name: nicebox-site-manager description: Manage AI-built websites via NiceBox OpenClaw API. Supports article publishing, viewing messages, and checking site status. metadata: {"clawdbot":{"emoji":"🛠️","requires":{"bins":["python3"],"env":["AIBOX_API_KEY"]},"primaryEnv":"AIBOX_API_KEY"}} --- # NiceBox Site Manager Manage AI-built websites through the NiceBox OpenClaw API. Base URL: ```bash https://ai.nicebox.cn/api/openclaw ``` Authentication: ```bash Authorization: $AIBOX_API_KEY ``` This skill provides 3 main capabilities: * Publish article * View messages * Check site status ## Publish article Publish an article to your site. ```bash python3 {baseDir}/scripts/publish_article.py \ --title "Hello World" \ --content "<p>This is article content</p>" \ --summary "Optional summary" \ --author "NiceBox AI" \ --cover "https://example.com/cover.jpg" \ --status publish ``` Options: * `--title`: Article title (required) * `--content`: Article content, usually HTML (required) * `--summary`: Article summary (optional) * `--author`: Author name (optional) * `--cover`: Cover image URL (optional) * `--status`: `draft` or `publish` (default: `publish`) ## View messages List messages, inquiries, or leads from your site. ```bash python3 {baseDir}/scripts/list_messages.py python3 {baseDir}/scripts/list_messages.py --page 1 --page-size 20 python3 {baseDir}/scripts/list_messages.py --is-read 0 ``` Options: * `--page`: Page number (default: `1`) * `--page-size`: Number of items per page (default: `20`) * `--is-read`: Filter by read status, `0` unread / `1` read (optional) ## Check site status Check the current status of your site. ```bash python3 {baseDir}/scripts/site_status.py ``` No additional options required. ## Environment Set your API key before using this skill: ```bash export AIBOX_API_KEY="your_api_key" ``` Optional override for base URL: ```bash export AIBOX_BASE_URL="https://ai.nicebox.cn/api/openclaw" ``` ## Default endpoint assumptions This skill assumes the following API paths: * `POST /article/publish` * `GET /message/getlist` * `GET /site/status` If your actual backend uses different paths, update the `ENDPOINT_*` constants in the Python scripts. ## Notes * All requests use the HTTP `Authorization` header. * The API key is sent as plain header value: * `Authorization: YOUR_KEY` * Output is printed as formatted JSON for easier debugging and agent use. * If your API field names differ, update the payload fields in the scripts.

path: scripts/list_messages.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import json
import argparse
import urllib.request
import urllib.parse
import urllib.error


DEFAULT_BASE_URL = "https://ai.nicebox.cn/api/openclaw"
ENDPOINT_LIST_MESSAGES = "/message/getlist"


def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)


def get_env(name: str, default: str = "") -> str:
    return os.environ.get(name, default).strip()


def build_url(base_url: str, endpoint: str, params: dict = None) -> str:
    url = base_url.rstrip("/") + endpoint
    if params:
        clean = {k: v for k, v in params.items() if v is not None and v != ""}
        if clean:
            url += "?" + urllib.parse.urlencode(clean)
    return url


def http_get(url: str, api_key: str, timeout: int = 30):
    req = urllib.request.Request(
        url=url,
        method="GET",
        headers={
            "Authorization": api_key,
            "Accept": "application/json",
            "User-Agent": "nicebox-openclaw-skill/1.0",
        },
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read().decode("utf-8", errors="replace")
            return resp.getcode(), raw
    except urllib.error.HTTPError as e:
        raw = e.read().decode("utf-8", errors="replace")
        return e.code, raw
    except Exception as e:
        raise RuntimeError(f"Request failed: {e}") from e


def parse_args():
    parser = argparse.ArgumentParser(description="List messages from NiceBox OpenClaw API")
    parser.add_argument("--page", type=int, default=1, help="Page number")
    parser.add_argument("--page-size", type=int, default=20, help="Items per page")
    parser.add_argument("--is-read", choices=["0", "1"], default=None, help="0 unread, 1 read")
    parser.add_argument("--base-url", default=get_env("AIBOX_BASE_URL", DEFAULT_BASE_URL), help="API base URL")
    return parser.parse_args()


def main():
    args = parse_args()

    [REDACTED_SECRET]"AIBOX_API_KEY")
    if not [REDACTED_SECRET]"Error: AIBOX_API_KEY is not set")
        sys.exit(2)

    params = {
        "page": args.page,
        "page_size": args.page_size,
    }
    if args.is_read is not None:
        params["is_read"] = args.is_read

    url = build_url(args.base_url, ENDPOINT_LIST_MESSAGES, params)

    try:
        status_code, raw = http_get(url, api_key)
    except RuntimeError as e:
        eprint(str(e))
        sys.exit(1)

    try:
        parsed = json.loads(raw)
        print(json.dumps({
            "ok": 200 <= status_code < 300,
            "status_code": status_code,
            "request_url": url,
            "response": parsed,
        }, ensure_ascii=False, indent=2))
    except json.JSONDecodeError:
        print(json.dumps({
            "ok": 200 <= status_code < 300,
            "status_code": status_code,
            "request_url": url,
            "response_raw": raw,
        }, ensure_ascii=False, indent=2))

    sys.exit(0 if 200 <= status_code < 300 else 1)


if __name__ == "__main__":
    main()


path: scripts/publish_article.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import json
import argparse
import urllib.request
import urllib.error


DEFAULT_BASE_URL = "https://ai.nicebox.cn/api/openclaw"
ENDPOINT_PUBLISH_ARTICLE = "/article/publish"


def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)


def get_env(name: str, default: str = "") -> str:
    return os.environ.get(name, default).strip()


def build_url(base_url: str, endpoint: str) -> str:
    return base_url.rstrip("/") + endpoint


def http_post_json(url: str, api_key: str, payload: dict, timeout: int = 30):
    data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    req = urllib.request.Request(
        url=url,
        data=data,
        method="POST",
        headers={
            "Authorization": api_key,
            "Content-Type": "application/json",
            "Accept": "application/json",
            "User-Agent": "nicebox-openclaw-skill/1.0",
        },
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read().decode("utf-8", errors="replace")
            return resp.getcode(), raw
    except urllib.error.HTTPError as e:
        raw = e.read().decode("utf-8", errors="replace")
        return e.code, raw
    except Exception as e:
        raise RuntimeError(f"Request failed: {e}") from e


def parse_args():
    parser = argparse.ArgumentParser(description="Publish article to NiceBox OpenClaw API")
    parser.add_argument("--title", required=True, help="Article title")
    parser.add_argument("--content", required=True, help="Article HTML/content")
    parser.add_argument("--summary", default="", help="Article summary")
    parser.add_argument("--author", default="", help="Author name")
    parser.add_argument("--cover", default="", help="Cover image URL")
    parser.add_argument("--status", default="publish", choices=["draft", "publish"], help="Article status")
    parser.add_argument("--base-url", default=get_env("AIBOX_BASE_URL", DEFAULT_BASE_URL), help="API base URL")
    return parser.parse_args()


def main():
    args = parse_args()

    [REDACTED_SECRET]"AIBOX_API_KEY")
    if not [REDACTED_SECRET]"Error: AIBOX_API_KEY is not set")
        sys.exit(2)

    payload = {
        "title": args.title,
        "content": args.content,
        "summary": args.summary,
        "author": args.author,
        "cover": args.cover,
        "status": args.status,
    }

    # 去掉空字段，避免某些后端严格校验
    payload = {k: v for k, v in payload.items() if v != ""}

    url = build_url(args.base_url, ENDPOINT_PUBLISH_ARTICLE)

    try:
        status_code, raw = http_post_json(url, api_key, payload)
    except RuntimeError as e:
        eprint(str(e))
        sys.exit(1)

    try:
        parsed = json.loads(raw)
        print(json.dumps({
            "ok": 200 <= status_code < 300,
            "status_code": status_code,
            "request_url": url,
            "payload": payload,
            "response": parsed,
        }, ensure_ascii=False, indent=2))
    except json.JSONDecodeError:
        print(json.dumps({
            "ok": 200 <= status_code < 300,
            "status_code": status_code,
            "request_url": url,
            "payload": payload,
            "response_raw": raw,
        }, ensure_ascii=False, indent=2))

    sys.exit(0 if 200 <= status_code < 300 else 1)


if __name__ == "__main__":
    main()


path: scripts/site_status.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import json
import argparse
import urllib.request
import urllib.parse
import urllib.error


DEFAULT_BASE_URL = "https://ai.nicebox.cn/api/openclaw"
ENDPOINT_SITE_STATUS = "/site/status"


def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)


def get_env(name: str, default: str = "") -> str:
    return os.environ.get(name, default).strip()


def build_url(base_url: str, endpoint: str, params: dict = None) -> str:
    url = base_url.rstrip("/") + endpoint
    if params:
        clean = {k: v for k, v in params.items() if v is not None and v != ""}
        if clean:
            url += "?" + urllib.parse.urlencode(clean)
    return url


def http_get(url: str, api_key: str, timeout: int = 30):
    req = urllib.request.Request(
        url=url,
        method="GET",
        headers={
            "Authorization": api_key,
            "Accept": "application/json",
            "User-Agent": "nicebox-openclaw-skill/1.0",
        },
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read().decode("utf-8", errors="replace")
            return resp.getcode(), raw
    except urllib.error.HTTPError as e:
        raw = e.read().decode("utf-8", errors="replace")
        return e.code, raw
    except Exception as e:
        raise RuntimeError(f"Request failed: {e}") from e


def parse_args():
    parser = argparse.ArgumentParser(description="Check site status from NiceBox OpenClaw API")
    parser.add_argument("--base-url", default=get_env("AIBOX_BASE_URL", DEFAULT_BASE_URL), help="API base URL")
    return parser.parse_args()


def main():
    args = parse_args()

    [REDACTED_SECRET]"AIBOX_API_KEY")
    if not [REDACTED_SECRET]"Error: AIBOX_API_KEY is not set")
        sys.exit(2)

    url = build_url(args.base_url, ENDPOINT_SITE_STATUS)

    try:
        status_code, raw = http_get(url, api_key)
    except RuntimeError as e:
        eprint(str(e))
        sys.exit(1)

    try:
        parsed = json.loads(raw)
        print(json.dumps({
            "ok": 200 <= status_code < 300,
            "status_code": status_code,
            "request_url": url,
            "response": parsed,
        }, ensure_ascii=False, indent=2))
    except json.JSONDecodeError:
        print(json.dumps({
            "ok": 200 <= status_code < 300,
            "status_code": status_code,
            "request_url": url,
            "response_raw": raw,
        }, ensure_ascii=False, indent=2))

    sys.exit(0 if 200 <= status_code < 300 else 1)


if __name__ == "__main__":
    main()


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