Add generic Claw skill-template (manifest, CLI, docs, optional snippets)
Made-with: Cursor
This commit is contained in:
27
.github/workflows/release_skill.yaml
vendored
Normal file
27
.github/workflows/release_skill.yaml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# 技能发布工作流(占位)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 不同组织使用不同的复用工作流、制品格式与加密策略。
|
||||
# 使用本模板时,请将下面 jobs 整段替换为你们自己的 workflow,
|
||||
# 或删除本文件若暂不需要 GitHub Actions。
|
||||
#
|
||||
# 设计原则(行业常见):
|
||||
# - 通过 tag 触发发布(如 v*)
|
||||
# - 制品与版本号可追溯,与 SKILL.md 中 version 对齐
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
name: skill-release-placeholder
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Placeholder
|
||||
run: |
|
||||
echo "Replace this workflow with your organization's reusable workflow."
|
||||
echo "Example pattern: jobs.release.uses: <org>/<kit>/.github/workflows/reusable-release-skill.yaml@ref"
|
||||
exit 0
|
||||
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
.Python
|
||||
.venv/
|
||||
venv/
|
||||
.env
|
||||
.env.*
|
||||
38
README.md
Normal file
38
README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Claw 技能项目模板(通用)
|
||||
|
||||
本目录是一个**与具体业务无关**的技能(Skill)工程骨架,供团队在各类 **Claw / Agent 宿主**(桌面端、网关、IDE 插件等)上交付可安装技能包时参考。
|
||||
|
||||
## 你从这里能得到什么
|
||||
|
||||
- **行业标准对齐**:技能以「清单文件 + 可执行入口 + 文档」组织——与常见的 Agent Skill、CLI 工具包、内部自动化脚本仓库的惯例一致;不绑定某一厂商私有协议。
|
||||
- **可移植约定**:数据目录、用户隔离、兄弟技能路径等通过**环境变量契约**描述(见 `docs/RUNTIME.md`);不同宿主只需注入同名变量或做一层别名映射。
|
||||
- **低学习成本**:每个文件顶部与关键步骤都有注释;按下面顺序做即可跑通第一个命令。
|
||||
|
||||
## 建议的上手顺序(约 15~30 分钟)
|
||||
|
||||
1. **复制本模板**为新仓库或新目录,全局把占位符 `your-skill-slug` / `Your Skill Display Name` 换成你的技能标识(与 `SKILL.md` 里 `metadata.skill.slug` 一致)。
|
||||
2. **阅读** `docs/RUNTIME.md`,确认你的宿主会注入哪些环境变量;若宿主使用另一套名字,在宿主侧做映射,或改 `optional/paths_snippet.py` 中的读取顺序(文件内有说明)。
|
||||
3. **本地试跑**:`python scripts/skill_main.py health` 应输出成功信息。
|
||||
4. **扩展子命令**:在 `scripts/skill_main.py` 的 `dispatch` 中增加分支;业务逻辑放在同目录其它模块或子包中,保持入口轻薄。
|
||||
5. **编写/调整 `SKILL.md`**:只改「何时触发、如何调用、参数含义」,不要写实现细节;实现细节放在 `docs/` 或代码注释里。
|
||||
6. **发布**:若使用 GitHub Actions,编辑 `.github/workflows/release_skill.yaml`,把 `uses:` 指向**你们组织**的复用工作流;若不用 CI,可删除该目录。
|
||||
|
||||
## 目录一览
|
||||
|
||||
| 路径 | 作用 |
|
||||
|------|------|
|
||||
| `SKILL.md` | 技能清单(YAML 头 + Markdown 正文),供宿主与协作者阅读 |
|
||||
| `scripts/skill_main.py` | 推荐唯一 CLI 入口;含 `health` / `version` 示例 |
|
||||
| `docs/RUNTIME.md` | 环境与目录契约(多宿主通用) |
|
||||
| `docs/SKILL_TYPES.md` | 常见技能形态与自检清单 |
|
||||
| `docs/PORTABILITY.md` | 多 Claw 宿主差异与兼容建议 |
|
||||
| `optional/` | 可选复制进项目的片段(路径、SQLite 示例),**不默认 import** |
|
||||
|
||||
## 不要做的事
|
||||
|
||||
- 不要在模板中提交真实密钥、真实业务表结构或平台专用逻辑。
|
||||
- 不要把模板改成只支持某一种宿主;特殊项写在 `docs/PORTABILITY.md` 的「宿主附录」中。
|
||||
|
||||
## 版本
|
||||
|
||||
模板自身版本见 `SKILL.md` 的 `version` 字段;与你技能的业务版本一致更新即可。
|
||||
56
SKILL.md
Normal file
56
SKILL.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
# ---------------------------------------------------------------------------
|
||||
# 技能清单(Skill Manifest)
|
||||
# 行业常见做法:YAML 头描述元数据,正文 Markdown 描述「何时用、怎么调」。
|
||||
# 不同 Claw 宿主解析字段可能略有差异;可移植标识请使用 metadata.skill.slug。
|
||||
# ---------------------------------------------------------------------------
|
||||
name: 您的技能显示名称
|
||||
description: 一句话说明技能做什么(给编排层与人类阅读,不写实现细节)。
|
||||
version: 1.0.0
|
||||
author: 深圳匠厂科技有限公司
|
||||
metadata:
|
||||
skill:
|
||||
# 机器可读、稳定标识:小写字母、数字、短横线;与数据子目录名一致。
|
||||
slug: your-skill-slug
|
||||
emoji: "📦"
|
||||
category: "通用"
|
||||
# 宿主若限制可调用的工具类型,在此列出(按宿主文档填写)。
|
||||
allowed-tools:
|
||||
- bash
|
||||
---
|
||||
|
||||
# Your Skill Display Name
|
||||
|
||||
## 使用时机
|
||||
|
||||
<!-- 由技能作者填写:用户在自然语言里怎样表达时应触发本技能。 -->
|
||||
|
||||
- 示例:用户说「检查技能是否可用」「运行某某任务」
|
||||
|
||||
## 执行步骤
|
||||
|
||||
<!-- 将 {baseDir} 替换为宿主提供的技能根目录;若宿主使用其它占位符,以宿主文档为准。 -->
|
||||
|
||||
### 健康检查(推荐自动化先跑)
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/skill_main.py health
|
||||
```
|
||||
|
||||
### 查看版本
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/skill_main.py version
|
||||
```
|
||||
|
||||
### 扩展子命令
|
||||
|
||||
在 `scripts/skill_main.py` 中增加新的子命令分支,并在此处追加对应示例命令与参数说明。
|
||||
|
||||
## 环境依赖
|
||||
|
||||
详见本仓库 `docs/RUNTIME.md`(`CLAW_DATA_ROOT`、`CLAW_USER_ID` 等)。
|
||||
|
||||
## 数据与隐私
|
||||
|
||||
本技能若产生持久化数据,应仅写入 `{CLAW_DATA_ROOT}/{CLAW_USER_ID}/your-skill-slug/` 下;不得将用户数据提交到版本库。
|
||||
56
docs/PORTABILITY.md
Normal file
56
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`** 作为**可移植**的机器可读标识(短横线命名,如 `my-skill`)。
|
||||
|
||||
若你的宿主仍要求其它键名(例如历史实现里的嵌套字段),请在宿主侧做**映射**,或在 `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
docs/RUNTIME.md
Normal file
55
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
docs/SKILL_TYPES.md
Normal file
33
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
optional/README.md
Normal file
17
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 建表示例 |
|
||||
|
||||
复制后务必全局替换 `your-skill-slug` 与表名,避免与别的技能冲突。
|
||||
92
optional/paths_snippet.py
Normal file
92
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 = "your-skill-slug"
|
||||
|
||||
|
||||
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 时,默认使用本文件所在仓库的上一级目录的上一级
|
||||
(即:.../skill-template/scripts/ → 误推断;复制后请改为 BASE_DIR 逻辑)。
|
||||
"""
|
||||
root = _getenv_first(("CLAW_SKILLS_ROOT",))
|
||||
if root:
|
||||
return root
|
||||
# 模板占位:脚本位于 scripts/,仓库根为 dirname(dirname(__file__))
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
return os.path.dirname(here)
|
||||
48
optional/sqlite_minimal.py
Normal file
48
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 template_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 template_audit (action, created_at) VALUES (?, ?)",
|
||||
(action, int(time.time())),
|
||||
)
|
||||
conn.commit()
|
||||
83
scripts/skill_main.py
Normal file
83
scripts/skill_main.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
技能入口脚本(模板)
|
||||
====================
|
||||
|
||||
【职责】
|
||||
- 作为宿主调用时的统一 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.skill.slug 保持一致(模板占位,复制后请修改)
|
||||
SKILL_SLUG = "your-skill-slug"
|
||||
|
||||
|
||||
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="Claw skill CLI template — replace SKILL_SLUG and add subcommands.",
|
||||
)
|
||||
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