Add OpenClaw skills, platform kit, and template docs
Made-with: Cursor
This commit is contained in:
13
toutiao-publisher/.github/workflows/release_skill.yaml
vendored
Normal file
13
toutiao-publisher/.github/workflows/release_skill.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# 打 tag(如 v1.0.2)后触发:加密打包、调用平台 API 同步元数据(入库)、上传制品、清理旧版本。
|
||||
# 逻辑在 admin/jiangchang-platform-kit 的 reusable-release-skill.yaml 中。
|
||||
name: 头条技能发布
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: admin/jiangchang-platform-kit/.github/workflows/reusable-release-skill.yaml@main
|
||||
with:
|
||||
artifact_platform: windows
|
||||
pyarmor_platform: windows.x86_64
|
||||
8
toutiao-publisher/.gitignore
vendored
Normal file
8
toutiao-publisher/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
.Python
|
||||
.venv/
|
||||
venv/
|
||||
.env
|
||||
.env.*
|
||||
40
toutiao-publisher/README.md
Normal file
40
toutiao-publisher/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# 头条号批量发布(toutiao-publisher)
|
||||
|
||||
头条号批量发布技能仓库;当前为**占位阶段**,仅含 CLI 骨架与文档,**发布功能待后续迭代**。
|
||||
|
||||
## 目录一览
|
||||
|
||||
| 路径 | 作用 |
|
||||
|------|------|
|
||||
| `SKILL.md` | 技能清单(YAML 头 + Markdown 正文) |
|
||||
| `release.ps1` | 本地一键发布(依赖与 `jiangchang-platform-kit` 并列,见 `account-manager` 同款) |
|
||||
| `scripts/skill_main.py` | CLI 入口:`health` / `version` |
|
||||
| `docs/` | 运行时与可移植性说明 |
|
||||
| `optional/` | 可选片段(路径、SQLite 等),默认不引用 |
|
||||
|
||||
## 本地试跑
|
||||
|
||||
```bash
|
||||
python scripts/skill_main.py health
|
||||
python scripts/skill_main.py version
|
||||
```
|
||||
|
||||
## 版本
|
||||
|
||||
与 `SKILL.md` 中 `version` 字段对齐更新。
|
||||
|
||||
## Git 远程(避免推到模板仓)
|
||||
|
||||
从 `skill-template` 克隆的目录,默认 `origin` 仍指向模板仓库。本技能应使用独立仓库,例如:
|
||||
|
||||
```text
|
||||
http://120.25.191.12:3000/admin/toutiao-publisher.git
|
||||
```
|
||||
|
||||
在 Gitea 上**新建同名空仓库**后执行:
|
||||
|
||||
```bash
|
||||
git remote set-url origin http://120.25.191.12:3000/admin/toutiao-publisher.git
|
||||
git push -u origin main
|
||||
git push origin v1.0.1 # 若本地已有 tag 且需同步
|
||||
```
|
||||
52
toutiao-publisher/SKILL.md
Normal file
52
toutiao-publisher/SKILL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
# ---------------------------------------------------------------------------
|
||||
# 技能清单(Skill Manifest)
|
||||
# ---------------------------------------------------------------------------
|
||||
name: 头条号批量发布
|
||||
description: 头条号批量发布技能(骨架阶段:仅健康检查与版本;发布逻辑待实现)。
|
||||
version: 0.1.0
|
||||
author: 深圳匠厂科技有限公司
|
||||
metadata:
|
||||
openclaw:
|
||||
slug: toutiao-publisher
|
||||
emoji: "📰"
|
||||
category: "内容发布"
|
||||
skill:
|
||||
slug: toutiao-publisher
|
||||
emoji: "📰"
|
||||
category: "内容发布"
|
||||
allowed-tools:
|
||||
- bash
|
||||
---
|
||||
|
||||
# 头条号批量发布(toutiao-publisher)
|
||||
|
||||
## 使用时机
|
||||
|
||||
- 用户需要**在头条号侧批量或自动化发布内容**时(具体话术与流程待业务实现后补充)。
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### 健康检查
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/skill_main.py health
|
||||
```
|
||||
|
||||
### 查看版本
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/skill_main.py version
|
||||
```
|
||||
|
||||
### 发布与其它子命令
|
||||
|
||||
实现中:后续将在 `scripts/` 下增加发布入口,并在此文档补充命令与参数说明。
|
||||
|
||||
## 环境依赖
|
||||
|
||||
详见本仓库 `docs/RUNTIME.md`(`CLAW_DATA_ROOT`、`CLAW_USER_ID` 等)。
|
||||
|
||||
## 数据与隐私
|
||||
|
||||
本技能若产生持久化数据,应仅写入 `{CLAW_DATA_ROOT}/{CLAW_USER_ID}/toutiao-publisher/` 下;不得将用户数据提交到版本库。
|
||||
56
toutiao-publisher/docs/PORTABILITY.md
Normal file
56
toutiao-publisher/docs/PORTABILITY.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 多宿主(多 Claw)可移植性说明
|
||||
|
||||
## 设计目标
|
||||
|
||||
同一套技能仓库应能在**不同 Claw 实现**下工作,只要宿主满足本文档的**最小契约**:能启动进程、传入环境变量、并把 `SKILL.md` 提供给编排层阅读。
|
||||
|
||||
## 行业上常见的「技能包」形态
|
||||
|
||||
- **声明式清单**(Markdown + YAML 头):描述名称、描述、版本、工具权限、触发场景。
|
||||
- **可执行入口**:一至多个脚本/二进制,由宿主通过 `bash` / `python` 等调用。
|
||||
- **用户数据与代码分离**:持久化数据落在用户可写目录,不写在安装目录内。
|
||||
|
||||
本仓库按上述惯例组织;具体宿主如何解析 `SKILL.md` 的 YAML 键名,以各宿主文档为准。
|
||||
|
||||
## 标识技能:`metadata.skill`
|
||||
|
||||
`SKILL.md` 中使用 **`metadata.skill.slug`**(及 `metadata.openclaw.slug`)作为**可移植**的机器可读标识(短横线命名,如 `toutiao-publisher`)。
|
||||
|
||||
若你的宿主仍要求其它键名(例如历史实现里的嵌套字段),请在宿主侧做**映射**,或在 `SKILL.md` 中**并列声明**两组 metadata(保持 `slug` 值一致)。不要在业务代码里写死某一宿主品牌名。
|
||||
|
||||
## 环境变量:推荐前缀 `CLAW_*`
|
||||
|
||||
为减少对单一产品名的耦合,文档与可选片段推荐使用:
|
||||
|
||||
| 变量 | 含义 |
|
||||
|------|------|
|
||||
| `CLAW_DATA_ROOT` | 用户数据根目录(多技能共享的上一级) |
|
||||
| `CLAW_USER_ID` | 当前工作空间或用户标识,用于数据隔离 |
|
||||
| `CLAW_SKILLS_ROOT` | 可选;多个技能并排安装时的根目录,便于 `subprocess` 调用兄弟技能 |
|
||||
|
||||
宿主若已使用其它名称,推荐在**启动子进程时**注入别名,例如:
|
||||
|
||||
- 将宿主内部的「数据根」映射为 `CLAW_DATA_ROOT`
|
||||
- 将宿主内部「用户 ID」映射为 `CLAW_USER_ID`
|
||||
|
||||
这样技能脚本无需分支判断宿主品牌。
|
||||
|
||||
## 路径布局约定(逻辑路径)
|
||||
|
||||
在 `CLAW_DATA_ROOT` 与 `CLAW_USER_ID` 可用时,本技能推荐将私有数据放在:
|
||||
|
||||
```text
|
||||
{CLAW_DATA_ROOT}/{CLAW_USER_ID}/{skill_slug}/
|
||||
```
|
||||
|
||||
其中 `skill_slug` 与 `SKILL.md` 中 `metadata.skill.slug` 一致。若环境变量缺失,`optional/paths_snippet.py` 中提供了**仅用于开发机**的 fallback(见该文件注释),生产环境应由宿主注入变量。
|
||||
|
||||
## 发布与制品
|
||||
|
||||
不同组织对加密、签名、制品格式要求不同。`.github/workflows/release_skill.yaml` 仅作占位:**务必替换**为你们自己的复用工作流或删除。
|
||||
|
||||
## 自检
|
||||
|
||||
- [ ] `SKILL.md` 中 `slug` 与目录名/制品名策略是否与宿主一致
|
||||
- [ ] 宿主文档要求的环境变量是否已全部注入
|
||||
- [ ] 是否在文档中说明了「未注入变量时的行为」(拒绝运行 / 本地 fallback)
|
||||
55
toutiao-publisher/docs/RUNTIME.md
Normal file
55
toutiao-publisher/docs/RUNTIME.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# 运行时契约(环境变量与目录)
|
||||
|
||||
本文档定义技能进程**建议依赖**的外部条件,便于不同 Claw 宿主统一接入。业务技能应**读取环境变量**,而不是在代码里写死路径或用户名。
|
||||
|
||||
## 必需程度说明
|
||||
|
||||
- **强烈建议**:生产环境由宿主注入;技能应对缺失给出明确错误提示,避免静默写到意外目录。
|
||||
- **可选**:没有时技能仍可部分运行(例如只读 `health`)。
|
||||
|
||||
## 变量一览
|
||||
|
||||
### `CLAW_DATA_ROOT`(强烈建议)
|
||||
|
||||
用户数据根。多个技能、多个用户的数据都在此根之下分区。
|
||||
|
||||
- 典型场景:组织策略指定的盘符路径或 `~/.your-org-data`。
|
||||
- 未设置时:技能**不应**猜测网络盘;开发机 fallback 仅限 `optional/paths_snippet.py` 中说明的情形。
|
||||
|
||||
### `CLAW_USER_ID`(强烈建议)
|
||||
|
||||
当前会话所代表的用户或工作空间 ID(字符串)。与数据隔离强相关。
|
||||
|
||||
- 用于拼接:`{CLAW_DATA_ROOT}/{CLAW_USER_ID}/{skill_slug}/`
|
||||
- 未设置时:可用匿名占位(如 `_anon`)**仅用于开发**,生产应显式注入。
|
||||
|
||||
### `CLAW_SKILLS_ROOT`(可选)
|
||||
|
||||
多个技能以并列目录安装时的根路径,例如:
|
||||
|
||||
```text
|
||||
{CLAW_SKILLS_ROOT}/skill-a/scripts/...
|
||||
{CLAW_SKILLS_ROOT}/skill-b/scripts/...
|
||||
```
|
||||
|
||||
编排型技能若需要通过子进程调用兄弟技能,应基于该变量定位脚本,避免写死绝对路径。
|
||||
|
||||
## 本技能推荐的数据目录
|
||||
|
||||
```text
|
||||
{CLAW_DATA_ROOT}/{CLAW_USER_ID}/{skill_slug}/
|
||||
```
|
||||
|
||||
- `skill_slug`:与 `SKILL.md` 内 `metadata.skill.slug` 一致。
|
||||
- 在此目录下可放置 SQLite 文件、缓存、上传临时文件等;**不要**向版本库提交该目录内容。
|
||||
|
||||
## 标准输出约定(建议)
|
||||
|
||||
为便于宿主与自动化解析,建议:
|
||||
|
||||
- 致命错误:单行前缀 `ERROR:`,例如 `ERROR:MISSING_ENV_CLAW_DATA_ROOT`
|
||||
- 成功:人类可读一行或多行;若有机读需求,可用 `JSON` 单行输出并在 `SKILL.md` 中说明格式。
|
||||
|
||||
## 与具体宿主的关系
|
||||
|
||||
若某宿主文档规定了另一套变量名,应在**宿主启动技能子进程时**注入为本文档中的 `CLAW_*` 名称,或在技能内使用一层极薄的 `getenv` 封装(见 `optional/paths_snippet.py` 注释示例)。**不要在业务模块中散落多套变量名判断。**
|
||||
33
toutiao-publisher/docs/SKILL_TYPES.md
Normal file
33
toutiao-publisher/docs/SKILL_TYPES.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 技能形态与自检清单(无业务)
|
||||
|
||||
开发前先选定形态,避免把「编排、存储、浏览器」混在一个脚本里难以测试。
|
||||
|
||||
## 类型 A:无状态工具型
|
||||
|
||||
- **特征**:不持久化用户数据,或只读配置文件;输入输出主要在 stdin/stdout。
|
||||
- **数据目录**:通常不需要 `CLAW_DATA_ROOT` 下的专属库;若需要缓存,仍建议放在契约目录下。
|
||||
- **自检**:离线可跑;`health` 不访问网络也可成功。
|
||||
|
||||
## 类型 B:本地持久化型
|
||||
|
||||
- **特征**:使用 SQLite、本地文件等保存用户数据。
|
||||
- **数据目录**:必须使用 `{CLAW_DATA_ROOT}/{CLAW_USER_ID}/{skill_slug}/`。
|
||||
- **自检**:首次运行自动建库/建表;文档中说明库文件路径与备份方式。
|
||||
|
||||
## 类型 C:编排型(调用其它技能或外部 CLI)
|
||||
|
||||
- **特征**:自身逻辑薄,主要 `subprocess` 或 HTTP 调用其它组件。
|
||||
- **依赖**:在 `SKILL.md` 中明确写出**先决条件**(兄弟技能已安装、某 CLI 在 PATH 等)。
|
||||
- **自检**:`health` 可检查兄弟可执行文件是否存在;缺失时打印清晰错误。
|
||||
|
||||
## 类型 D:混合型
|
||||
|
||||
- **特征**:既有本地存储,又调用外部能力。
|
||||
- **建议**:拆模块(存储 / 编排 / 领域逻辑),入口脚本只做参数解析与调度。
|
||||
|
||||
## 发布前通用自检
|
||||
|
||||
- [ ] `SKILL.md` 中触发条件与示例命令与实际入口一致
|
||||
- [ ] 未注入 `CLAW_DATA_ROOT` / `CLAW_USER_ID` 时行为已文档化
|
||||
- [ ] 不向仓库提交用户数据、密钥、大型二进制
|
||||
- [ ] 错误信息包含「如何修复」(缺什么环境变量、缺哪个依赖)
|
||||
17
toutiao-publisher/optional/README.md
Normal file
17
toutiao-publisher/optional/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# optional/ 目录说明
|
||||
|
||||
本目录下的文件**不会**被 `scripts/skill_main.py` 自动引用。
|
||||
|
||||
## 为什么要单独放
|
||||
|
||||
- 避免可选片段拖慢最小 `health` 起步,按需再复制进业务代码。
|
||||
- 需要时**整文件复制**到 `scripts/` 或你们自己的包路径下,再按文件头注释改名、改常量。
|
||||
|
||||
## 文件列表
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| `paths_snippet.py` | `CLAW_*` 数据目录解析与 fallback 说明 |
|
||||
| `sqlite_minimal.py` | 无业务含义的 SQLite 建表示例 |
|
||||
|
||||
本技能数据子目录与 `SKILL_SLUG` 为 `toutiao-publisher`;若复制片段到其它项目请改为对应 slug 与表名。
|
||||
92
toutiao-publisher/optional/paths_snippet.py
Normal file
92
toutiao-publisher/optional/paths_snippet.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
可选片段:路径与环境变量(请复制到 scripts/ 或作为独立模块使用)
|
||||
================================================================
|
||||
|
||||
【用途】
|
||||
统一解析「用户数据根」「用户 ID」「本技能私有目录」,避免在业务代码里重复 os.getenv。
|
||||
|
||||
【使用步骤】
|
||||
1. 将本文件复制到 skills/your-slug/scripts/paths.py(或任意模块名)。
|
||||
2. 把 SKILL_SLUG 改为与 SKILL.md 中 metadata.skill.slug 一致。
|
||||
3. 在业务代码中: from paths import get_skill_data_dir (按实际包路径调整)
|
||||
|
||||
【可移植性】
|
||||
- 优先读取标准名 CLAW_*(见 docs/RUNTIME.md)。
|
||||
- 若你的组织在宿主侧仍使用历史变量名,可在此文件 _aliases 列表中追加 (标准名, 备选名),
|
||||
由宿主注入其一即可;不要在业务里再写第三套名字。
|
||||
|
||||
【注意】
|
||||
- 未设置 CLAW_DATA_ROOT 时的 fallback 仅适合开发机;生产环境应由宿主注入。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# TODO: 复制本文件后改为你的 slug(与 SKILL.md metadata.skill.slug 一致)
|
||||
SKILL_SLUG = "toutiao-publisher"
|
||||
|
||||
|
||||
def _getenv_first(names: tuple[str, ...]) -> str:
|
||||
"""按顺序读取多个环境变量名,返回第一个非空值。"""
|
||||
for n in names:
|
||||
v = (os.getenv(n) or "").strip()
|
||||
if v:
|
||||
return v
|
||||
return ""
|
||||
|
||||
|
||||
def get_data_root() -> str:
|
||||
"""
|
||||
用户数据根目录。
|
||||
顺序:CLAW_DATA_ROOT → (可选)宿主别名,见下方元组。
|
||||
若皆空:Windows 默认 D:\\claw-data;其它系统默认 ~/.claw-data —— 仅开发便利,生产请注入 CLAW_DATA_ROOT。
|
||||
"""
|
||||
root = _getenv_first(
|
||||
(
|
||||
"CLAW_DATA_ROOT",
|
||||
# 在此追加组织内别名,例如 "MYORG_USER_DATA_ROOT",
|
||||
)
|
||||
)
|
||||
if root:
|
||||
return root
|
||||
if sys.platform == "win32":
|
||||
return r"D:\claw-data"
|
||||
return os.path.join(os.path.expanduser("~"), ".claw-data")
|
||||
|
||||
|
||||
def get_user_id() -> str:
|
||||
"""当前用户或工作空间 ID;未设置时用 _anon(仅开发)。"""
|
||||
uid = _getenv_first(
|
||||
(
|
||||
"CLAW_USER_ID",
|
||||
# 在此追加别名,例如 "MYORG_WORKSPACE_ID",
|
||||
)
|
||||
)
|
||||
return uid or "_anon"
|
||||
|
||||
|
||||
def get_skill_data_dir() -> str:
|
||||
"""
|
||||
本技能可写目录:{数据根}/{用户ID}/{skill_slug}/
|
||||
会自动 os.makedirs(..., exist_ok=True)。
|
||||
"""
|
||||
path = os.path.join(get_data_root(), get_user_id(), SKILL_SLUG)
|
||||
os.makedirs(path, exist_ok=True)
|
||||
return path
|
||||
|
||||
|
||||
def get_skills_root() -> str:
|
||||
"""
|
||||
可选:并列安装的多技能根目录。
|
||||
未设置 CLAW_SKILLS_ROOT 时,默认使用本文件所在仓库的上一级目录的上一级
|
||||
(即:.../toutiao-publisher/optional/ → 仅作开发时并列技能推断参考)。
|
||||
"""
|
||||
root = _getenv_first(("CLAW_SKILLS_ROOT",))
|
||||
if root:
|
||||
return root
|
||||
# optional/ 下:仓库根为 dirname(dirname(__file__))
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
return os.path.dirname(here)
|
||||
48
toutiao-publisher/optional/sqlite_minimal.py
Normal file
48
toutiao-publisher/optional/sqlite_minimal.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
可选片段:最小 SQLite 示例(请复制后按需修改)
|
||||
==============================================
|
||||
|
||||
【用途】
|
||||
演示「单表 + 自增主键 + INTEGER 时间戳」的一种严谨写法;与具体业务无关。
|
||||
|
||||
【使用步骤】
|
||||
1. 复制到 scripts/db_example.py(或并入你的模块)。
|
||||
2. 修改 TABLE_SQL 中的表名与字段;保持时间字段为 INTEGER Unix 秒(UTC)若需跨时区一致。
|
||||
3. 在入口脚本中仅在需要持久化时 import。
|
||||
|
||||
【注意】
|
||||
- 本示例不做迁移兼容;schema 变更请用你们组织的迁移策略。
|
||||
- 数据库文件路径建议:get_skill_data_dir() / "skill.db"(paths_snippet 中函数)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
# 示例表:与任何业务无关
|
||||
TABLE_SQL = """
|
||||
CREATE TABLE IF NOT EXISTS skill_audit (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT, -- 自增主键
|
||||
action TEXT NOT NULL, -- 动作标识,如 health_ok
|
||||
created_at INTEGER NOT NULL -- Unix 秒 UTC
|
||||
);
|
||||
"""
|
||||
|
||||
|
||||
def connect(db_path: str) -> sqlite3.Connection:
|
||||
return sqlite3.connect(db_path)
|
||||
|
||||
|
||||
def init_db(conn: sqlite3.Connection) -> None:
|
||||
conn.execute(TABLE_SQL)
|
||||
conn.commit()
|
||||
|
||||
|
||||
def record_action(conn: sqlite3.Connection, action: str) -> None:
|
||||
conn.execute(
|
||||
"INSERT INTO skill_audit (action, created_at) VALUES (?, ?)",
|
||||
(action, int(time.time())),
|
||||
)
|
||||
conn.commit()
|
||||
23
toutiao-publisher/release.ps1
Normal file
23
toutiao-publisher/release.ps1
Normal file
@@ -0,0 +1,23 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Prefix = "v",
|
||||
[string]$Message = "正式发布",
|
||||
[switch]$AutoCommit,
|
||||
[switch]$RequireClean,
|
||||
[string]$CommitMessage,
|
||||
[switch]$DryRun
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$sharedScript = Join-Path $scriptDir "..\jiangchang-platform-kit\tools\release.ps1"
|
||||
$sharedScript = [System.IO.Path]::GetFullPath($sharedScript)
|
||||
|
||||
if (-not (Test-Path $sharedScript)) {
|
||||
throw "Shared release script not found: $sharedScript"
|
||||
}
|
||||
|
||||
& $sharedScript @PSBoundParameters
|
||||
exit $LASTEXITCODE
|
||||
83
toutiao-publisher/scripts/skill_main.py
Normal file
83
toutiao-publisher/scripts/skill_main.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
头条号发布技能 — CLI 入口
|
||||
========================
|
||||
|
||||
【职责】
|
||||
- 作为宿主调用时的统一 CLI 入口(子进程、终端、CI 均可)。
|
||||
- 只做:参数解析、环境检查、分发到具体子命令;复杂逻辑放到同目录其它模块。
|
||||
|
||||
【如何扩展】
|
||||
1. 在 main() 的 dispatch 字典中增加 "your_cmd": handler 项。
|
||||
2. 实现 handler(argv) 或 handler();出错时打印 ERROR: 前缀信息并 sys.exit(非0)。
|
||||
3. 在仓库根目录 SKILL.md「执行步骤」中补充示例命令。
|
||||
|
||||
【多宿主注意】
|
||||
- 不要在本文件写死某一品牌宿主名。
|
||||
- 路径与环境变量约定见 ../docs/RUNTIME.md;可选辅助代码见 ../optional/paths_snippet.py(需自行复制或 import 路径按项目调整)。
|
||||
|
||||
【编码】
|
||||
Windows 下若宿主仍使用系统默认编码,可在宿主侧设置 UTF-8;此处不强制改 sys.stdout(避免与宿主捕获冲突)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from typing import Callable, Dict, List, Optional
|
||||
|
||||
# 与 SKILL.md 中 metadata.openclaw.slug / metadata.skill.slug 保持一致
|
||||
SKILL_SLUG = "toutiao-publisher"
|
||||
|
||||
|
||||
def cmd_version(_args: argparse.Namespace) -> int:
|
||||
"""打印版本信息(与 SKILL.md frontmatter 中 version 应对齐,此处为占位)。"""
|
||||
payload = {
|
||||
"skill_slug": SKILL_SLUG,
|
||||
"version": "0.1.0",
|
||||
"entry": "skill_main.py",
|
||||
}
|
||||
print(json.dumps(payload, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_health(_args: argparse.Namespace) -> int:
|
||||
"""
|
||||
健康检查:应快速、可离线(除非技能本身强依赖网络)。
|
||||
失败时打印 ERROR: 前缀,便于宿主与自动化解析。
|
||||
"""
|
||||
# 示例:检查 Python 版本(可按需改为检查关键依赖 import)
|
||||
if sys.version_info < (3, 9):
|
||||
print("ERROR:PYTHON_VERSION need >= 3.9", file=sys.stderr)
|
||||
return 1
|
||||
print(f"OK skill={SKILL_SLUG} python={sys.version.split()[0]}")
|
||||
return 0
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
p = argparse.ArgumentParser(
|
||||
description="toutiao-publisher — Toutiao batch publish skill CLI (skeleton).",
|
||||
)
|
||||
sub = p.add_subparsers(dest="command", required=True)
|
||||
|
||||
sp = sub.add_parser("version", help="Print version JSON.")
|
||||
sp.set_defaults(handler=cmd_version)
|
||||
|
||||
sp = sub.add_parser("health", help="Quick health check.")
|
||||
sp.set_defaults(handler=cmd_health)
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def main(argv: Optional[List[str]] = None) -> int:
|
||||
argv = argv if argv is not None else sys.argv[1:]
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
handler: Callable[[argparse.Namespace], int] = args.handler
|
||||
return handler(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user