# Skills 技能

Skills 是 DCC-MCP-Core 的核心构建块。每个 Skill 代表一个可以在 DCC 应用程序（Maya、Blender、Houdini 等）中执行的离散操作。

## 架构

DCC-MCP-Core 采用基于注册表的 skill 执行模型，后端使用 Rust 的 DashMap 实现线程安全并发访问：

- **`ToolRegistry`** — 线程安全的 skill 元数据存储（name、description、tags、DCC、version、JSON schemas）
- **`ToolDispatcher`** — 将验证后的调用路由到注册的 Python 处理器
- **`ToolValidator`** — 基于 JSON Schema 的输入验证
- **`VersionedRegistry`** — 支持语义版本解析的多版本 skill 管理

所有 skill 在运行时被发现和注册。**没有基类或 Pydantic 模型** —— skill 是通过元数据注册的普通 Python 函数。

## ToolRegistry

`ToolRegistry` 是所有 DCC skill 操作的中央注册表。使用 JSON Schema 注册 skill 进行输入验证：

```python
import json
from dcc_mcp_core import ToolRegistry

reg = ToolRegistry()

reg.register(
    name="create_sphere",
    description="在 DCC 场景中创建多边形球体",
    category="geometry",
    tags=["geo", "create", "mesh"],
    dcc="maya",
    version="1.0.0",
    input_schema=json.dumps({
        "type": "object",
        "required": ["radius"],
        "properties": {
            "radius": {"type": "number", "minimum": 0.1, "description": "球体半径"},
            "segments": {"type": "integer", "minimum": 4, "default": 16},
            "name": {"type": "string", "description": "可选的球体名称"}
        }
    }),
)
```

### 发现和查询

```python
# 获取所有注册了 skill 的 DCC
dccs = reg.get_all_dccs()
print(dccs)  # ["maya", "blender", "houdini"]

# 列出 Maya 的所有 skill
maya_skills = reg.list_actions_for_dcc("maya")
print(maya_skills)  # ["create_sphere", "create_cube", ...]

# 获取完整元数据
meta = reg.get_action("create_sphere", dcc_name="maya")
print(meta["version"])  # "1.0.0"

# 按类别和标签搜索
results = reg.search_actions(category="geometry", tags=["create"])
for r in results:
    print(r["name"], r["dcc"])

# 所有类别和标签
categories = reg.get_categories()
tags = reg.get_tags(dcc_name="maya")
```

### Dunder 访问

```python
reg.register("echo", dcc="python")
print("echo" in reg)  # True
print(len(reg))        # 已注册 skill 的数量
```

## ToolDispatcher

`ToolDispatcher` 与 `ToolRegistry` 配对，提供验证后的 skill 执行路由：

```python
import json
from dcc_mcp_core import ToolRegistry, ToolDispatcher

reg = ToolRegistry()
reg.register(
    "create_sphere",
    dcc="maya",
    input_schema=json.dumps({
        "type": "object",
        "required": ["radius"],
        "properties": {"radius": {"type": "number"}}
    }),
)
dispatcher = ToolDispatcher(reg)

def handle_create_sphere(params):
    radius = params["radius"]
    # 在此调用 Maya API（例如通过 pymel 或 maya.cmds）
    return {"created": True, "radius": radius}

dispatcher.register_handler("create_sphere", handle_create_sphere)

# 使用 JSON 字符串分派（wire format）
result = dispatcher.dispatch("create_sphere", json.dumps({"radius": 2.0}))
# result = {"action": "create_sphere", "output": {"created": True, "radius": 2.0}, "validation_skipped": False}
```

## ToolValidator

独立的验证器，用于根据 schema 检查 JSON 参数：

```python
from dcc_mcp_core import ToolValidator

validator = ToolValidator.from_schema_json(
    '{"type": "object", "required": ["radius"], '
    '"properties": {"radius": {"type": "number", "minimum": 0}}}'
)

ok, errors = validator.validate('{"radius": 1.5}')
print(ok, errors)  # True, []

ok, errors = validator.validate('{"radius": -1}')
print(ok, errors)  # False, ["radius must be >= 0"]
```

或从已存在的 `ToolRegistry` action 创建：

```python
from dcc_mcp_core import ToolRegistry, ToolValidator

reg = ToolRegistry()
reg.register("create_sphere", dcc="maya", input_schema='{"type": "object", "properties": {"radius": {"type": "number"}}}')

validator = ToolValidator.from_action_registry(reg, "create_sphere", dcc_name="maya")
```

## 结果模型

所有 skill 执行结果都规范化为 `ToolResult`：

```python
from dcc_mcp_core import success_result, error_result, from_exception

# 成功
result = success_result(
    message="Sphere created",
    prompt="Consider adding materials",  # AI 指导
    object_name="sphere1",
    position=[0, 0, 0],
)
print(result.success)    # True
print(result.prompt)    # "Consider adding materials"
print(result.context)   # {"object_name": "sphere1", "position": [0, 0, 0]}

# 错误
result = error_result(
    message="Failed to create sphere",
    error="Maya API error: object already exists",
    object_name="sphere1",
)
print(result.success)  # False
print(result.error)    # "Maya API error: object already exists"

# 从异常创建
try:
    raise RuntimeError("connection refused")
except Exception:
    result = from_exception("Connection to Maya lost")
    print(result.success)  # False
```

## VersionedRegistry

对于需要在多个 skill 版本间保持向后兼容的 API：

```python
from dcc_mcp_core import VersionedRegistry, VersionConstraint

vr = VersionedRegistry()

# 注册同一 skill 的多个版本
vr.register_versioned("create_sphere", dcc="maya", version="1.0.0",
    description="Basic sphere creation", category="geometry", tags=["geo"])
vr.register_versioned("create_sphere", dcc="maya", version="2.0.0",
    description="Sphere with UV support", category="geometry", tags=["geo", "uv"])

# 解析最佳版本
result = vr.resolve("create_sphere", "maya", "^1.0.0")
print(result["version"])   # "2.0.0"

# 所有匹配的版本
all_v = vr.resolve_all("create_sphere", "maya", ">=1.0.0")
print([v["version"] for v in all_v])  # ["1.0.0", "2.0.0"]

# 最新版本
print(vr.latest_version("create_sphere", "maya"))  # "2.0.0"
```

## EventBus

订阅 skill 执行生命周期事件，用于监控、日志或链式调用：

```python
from dcc_mcp_core import EventBus

bus = EventBus()

def on_before_execute(event, **kwargs):
    print(f"Executing {event} with {kwargs}")

def on_after_execute(event, **kwargs):
    print(f"Completed {event}")

# 订阅所有 "before_execute" 事件（通配符）
id1 = bus.subscribe("action.before_execute.*", on_before_execute)

# 订阅特定 skill
id2 = bus.subscribe("action.after_execute.create_sphere", on_after_execute)

# 取消订阅
bus.unsubscribe("action.before_execute.*", id1)

# 手动发布
bus.publish("custom.event", custom_data="value")
```
