feat: 新增 account 和 plan 目录

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 16:26:22 +08:00
parent 243a190124
commit 0cab33b16b
694 changed files with 161549 additions and 0 deletions

View File

@@ -0,0 +1,546 @@
---
name: openakita/skills@yuque-skills
description: Manage Yuque (语雀) knowledge bases, documents, and team collaboration through API integration. Supports personal search, weekly reports, knowledge base management, document CRUD, and group collaboration workflows. Based on yuque/yuque-skills.
license: MIT
metadata:
author: openakita
version: "1.0.0"
---
# Yuque Skills — 语雀知识管理
## When to Use
- 用户需要搜索语雀中的文档和知识
- 需要创建、编辑、发布语雀文档
- 需要生成周报/月报并发布到语雀
- 需要管理知识库结构(目录、分类)
- 需要在团队知识库中进行协作
- 需要从语雀导出文档或同步内容
- 需要统计知识库的使用数据
---
## Prerequisites
### 必需配置
| 配置项 | 说明 |
|--------|------|
| `YUQUE_TOKEN` | 语雀 API Token |
| `YUQUE_HOST` | 语雀 API 地址(默认 `https://www.yuque.com/api/v2` |
**获取 Token**
1. 登录语雀 → 点击头像 → 设置 → Token
2. 或访问https://www.yuque.com/settings/tokens
3. 创建新 Token勾选所需权限
`.env` 中配置:
```
YUQUE_TOKEN=your_yuque_token_here
YUQUE_HOST=https://www.yuque.com/api/v2
```
> 企业版语雀的 Host 格式为 `https://your-company.yuque.com/api/v2`
### 必需依赖
| 依赖 | 用途 | 安装方式 |
|------|------|---------|
| `httpx` | HTTP API 调用 | `pip install httpx` |
### 可选依赖
| 依赖 | 用途 | 安装方式 |
|------|------|---------|
| `markdownify` | HTML → Markdown 转换 | `pip install markdownify` |
| `beautifulsoup4` | HTML 解析 | `pip install beautifulsoup4` |
### 验证配置
```bash
curl -s -H "X-Auth-Token: $YUQUE_TOKEN" "https://www.yuque.com/api/v2/user" | python -m json.tool
```
---
## Instructions
### 语雀核心概念
| 概念 | 英文 | 说明 |
|------|------|------|
| 用户 | User | 个人账号 |
| 团队 | Group | 组织/团队空间 |
| 知识库 | Book/Repo | 文档集合,类似文件夹 |
| 文档 | Doc | 具体的内容页面 |
| 目录 | TOC | 知识库内的文档组织结构 |
| 协作者 | Collaborator | 知识库的共同维护者 |
### API 基础调用
所有 API 请求需携带 Token
```python
import httpx
YUQUE_HOST = os.environ.get("YUQUE_HOST", "https://www.yuque.com/api/v2")
YUQUE_TOKEN = os.environ["YUQUE_TOKEN"]
headers = {
"X-Auth-Token": YUQUE_TOKEN,
"Content-Type": "application/json",
"User-Agent": "OpenAkita-Agent/1.0"
}
async def yuque_api(method, path, data=None):
async with httpx.AsyncClient() as client:
url = f"{YUQUE_HOST}{path}"
response = await client.request(method, url, headers=headers, json=data)
response.raise_for_status()
return response.json()["data"]
```
### 权限说明
| 权限 | 可执行操作 |
|------|-----------|
| 只读 | 搜索、查看文档、导出 |
| 读写 | 创建、编辑、删除文档 |
| 管理 | 知识库设置、成员管理 |
---
## Workflows
### Workflow 1: 个人文档搜索
**步骤 1 — 获取用户信息**
```python
user = await yuque_api("GET", "/user")
user_login = user["login"]
print(f"当前用户: {user['name']} ({user_login})")
```
**步骤 2 — 搜索文档**
```python
async def search_docs(query, scope="user"):
"""搜索语雀文档"""
params = {
"q": query,
"type": "doc",
"scope": scope,
}
result = await yuque_api("GET", f"/search?q={query}&type=doc")
return result
```
**步骤 3 — 获取文档内容**
```python
async def get_doc(repo_slug, doc_slug):
"""获取文档详细内容"""
doc = await yuque_api("GET", f"/repos/{repo_slug}/docs/{doc_slug}")
return {
"title": doc["title"],
"body": doc["body"], # Markdown 格式
"body_html": doc["body_html"], # HTML 格式
"word_count": doc["word_count"],
"updated_at": doc["updated_at"],
}
```
**步骤 4 — 返回搜索结果摘要**
---
### Workflow 2: 周报/月报生成
**步骤 1 — 收集周报内容**
向用户询问或从其他来源汇总:
| 模块 | 内容 |
|------|------|
| 本周完成 | 已完成的工作项列表 |
| 进行中 | 正在推进的工作 |
| 下周计划 | 下周的工作安排 |
| 风险与阻塞 | 需要协助的问题 |
| 数据指标 | 关键 KPI 变化 |
**步骤 2 — 生成 Markdown 内容**
```python
def generate_weekly_report(data):
"""生成周报 Markdown"""
report = f"""# 周报 | {data['date_range']}
## ✅ 本周完成
{format_task_list(data['completed'])}
## 🔄 进行中
{format_task_list(data['in_progress'])}
## 📋 下周计划
{format_task_list(data['next_week'])}
## ⚠️ 风险与阻塞
{format_risk_list(data['risks'])}
## 📊 关键指标
{format_metrics_table(data['metrics'])}
"""
return report
```
**步骤 3 — 发布到语雀**
```python
async def publish_report(repo_slug, title, content):
"""发布周报到指定知识库"""
doc_data = {
"title": title,
"slug": generate_slug(title),
"body": content,
"format": "markdown",
"status": 1, # 0=草稿, 1=发布
}
result = await yuque_api("POST", f"/repos/{repo_slug}/docs", data=doc_data)
return result
```
**步骤 4 — 返回文档链接**
---
### Workflow 3: 知识库管理
**列出所有知识库**
```python
async def list_repos(user_login=None, group_login=None):
"""列出知识库"""
if group_login:
repos = await yuque_api("GET", f"/groups/{group_login}/repos")
else:
repos = await yuque_api("GET", f"/users/{user_login}/repos")
return [{
"id": r["id"],
"name": r["name"],
"slug": r["slug"],
"description": r["description"],
"docs_count": r["items_count"],
"namespace": r["namespace"],
"public": r["public"],
"updated_at": r["updated_at"],
} for r in repos]
```
**获取知识库目录**
```python
async def get_toc(repo_namespace):
"""获取知识库的目录结构"""
toc = await yuque_api("GET", f"/repos/{repo_namespace}/toc")
return toc
```
**创建知识库**
```python
async def create_repo(user_or_group_login, name, description="", public=0):
"""创建新知识库"""
data = {
"name": name,
"slug": slugify(name),
"description": description,
"public": public, # 0=私有, 1=公开
"type": "Book",
}
result = await yuque_api("POST", f"/users/{user_or_group_login}/repos", data=data)
return result
```
---
### Workflow 4: 文档 CRUD 操作
**创建文档**
```python
async def create_doc(repo_namespace, title, body, format="markdown"):
data = {
"title": title,
"slug": generate_slug(title),
"body": body,
"format": format,
}
return await yuque_api("POST", f"/repos/{repo_namespace}/docs", data=data)
```
**更新文档**
```python
async def update_doc(repo_namespace, doc_id, title=None, body=None):
data = {}
if title:
data["title"] = title
if body:
data["body"] = body
return await yuque_api("PUT", f"/repos/{repo_namespace}/docs/{doc_id}", data=data)
```
**删除文档**
```python
async def delete_doc(repo_namespace, doc_id):
return await yuque_api("DELETE", f"/repos/{repo_namespace}/docs/{doc_id}")
```
**导出文档**
```python
async def export_doc(repo_namespace, doc_slug, format="markdown"):
"""导出文档为指定格式"""
doc = await get_doc(repo_namespace, doc_slug)
if format == "markdown":
return doc["body"]
elif format == "html":
return doc["body_html"]
elif format == "text":
from bs4 import BeautifulSoup
return BeautifulSoup(doc["body_html"], "html.parser").get_text()
```
---
### Workflow 5: 团队协作
**列出团队**
```python
async def list_groups():
"""列出用户加入的所有团队"""
groups = await yuque_api("GET", "/users/groups")
return [{
"id": g["id"],
"name": g["name"],
"login": g["login"],
"description": g["description"],
"members_count": g["members_count"],
} for g in groups]
```
**团队知识库报告**
```python
async def generate_team_report(group_login):
"""生成团队知识库使用报告"""
repos = await list_repos(group_login=group_login)
report = {
"total_repos": len(repos),
"total_docs": sum(r["docs_count"] for r in repos),
"repos_detail": [],
}
for repo in repos:
docs = await yuque_api("GET", f"/repos/{repo['namespace']}/docs")
recent_docs = sorted(docs, key=lambda d: d["updated_at"], reverse=True)[:5]
report["repos_detail"].append({
"name": repo["name"],
"doc_count": repo["docs_count"],
"recent_updates": [d["title"] for d in recent_docs],
})
return report
```
**知识库协作者管理**
```python
async def add_collaborator(repo_namespace, user_login, role="writer"):
"""添加知识库协作者"""
data = {
"login": user_login,
"role": role, # reader, writer, admin
}
return await yuque_api("POST", f"/repos/{repo_namespace}/collaborators", data=data)
```
---
### Workflow 6: 知识库内容同步
将外部内容同步到语雀,或从语雀同步到本地:
**从 Markdown 文件同步到语雀**
```python
async def sync_markdown_to_yuque(md_dir, repo_namespace):
"""将本地 Markdown 文件目录同步到语雀知识库"""
import glob
md_files = glob.glob(f"{md_dir}/**/*.md", recursive=True)
for md_file in md_files:
with open(md_file, "r", encoding="utf-8") as f:
content = f.read()
title = os.path.splitext(os.path.basename(md_file))[0]
existing = await search_doc_by_title(repo_namespace, title)
if existing:
await update_doc(repo_namespace, existing["id"], body=content)
print(f"更新: {title}")
else:
await create_doc(repo_namespace, title, content)
print(f"创建: {title}")
```
**从语雀导出到本地**
```python
async def export_repo_to_local(repo_namespace, output_dir):
"""将语雀知识库导出为本地 Markdown 文件"""
docs = await yuque_api("GET", f"/repos/{repo_namespace}/docs")
os.makedirs(output_dir, exist_ok=True)
for doc_info in docs:
doc = await get_doc(repo_namespace, doc_info["slug"])
file_path = os.path.join(output_dir, f"{doc_info['slug']}.md")
with open(file_path, "w", encoding="utf-8") as f:
f.write(f"# {doc['title']}\n\n{doc['body']}")
print(f"导出: {doc['title']} -> {file_path}")
```
---
## Output Format
### 搜索结果
```
🔍 搜索 "项目规范" 共找到 5 条结果:
1. 📄 代码规范 v2.0
- 知识库: 工程团队/开发规范
- 更新时间: 2025-02-28
- 链接: https://www.yuque.com/team/repo/doc-slug
2. 📄 项目管理规范
- 知识库: PMO/流程文档
- 更新时间: 2025-02-25
- 链接: https://www.yuque.com/team/repo/doc-slug2
...
```
### 周报输出
生成后返回发布链接和摘要。
### 知识库统计
```
📊 团队知识库统计
- 总知识库数: 12
- 总文档数: 456
- 本月新增: 28 篇
- 最活跃知识库: "产品设计" (本月 12 篇更新)
- 最近更新:
1. API 接口文档 v3 (2 小时前)
2. Q1 OKR 复盘 (昨天)
3. 新员工入职手册 (3 天前)
```
---
## Common Pitfalls
### 1. Token 权限不足
**症状**API 返回 401 或 403
**解决**
- 确认 Token 有读写权限
- 企业版语雀可能需要管理员授权
- 检查 Token 是否过期
### 2. namespace 格式错误
语雀的 namespace 格式为 `{user_or_group_login}/{repo_slug}`,例如 `myteam/dev-docs`
**错误**:使用 repo 名称代替 slug
**正确**:使用 URL 中的 slug
### 3. Markdown 与 HTML 格式混淆
语雀文档有两种内容格式:
- `body`Markdown 格式(创建时使用 `format: "markdown"`
- `body_html`HTML 格式
创建文档时需明确指定 `format` 参数。
### 4. API 频率限制
语雀 API 有请求频率限制:
- 个人版:约 100 次/分钟
- 企业版:通常更高
**解决**:批量操作时添加延迟:
```python
import asyncio
for doc in docs:
await process_doc(doc)
await asyncio.sleep(0.5)
```
### 5. 文档 slug 冲突
同一知识库中 slug 必须唯一。创建文档前先检查是否已存在:
```python
async def safe_create_doc(repo_namespace, title, body):
slug = generate_slug(title)
existing = await find_doc_by_slug(repo_namespace, slug)
if existing:
slug = f"{slug}-{int(time.time())}"
return await create_doc(repo_namespace, title, body, slug=slug)
```
### 6. 企业版与个人版 API 差异
企业版语雀的部分 API 路径和参数可能有差异:
- Host 不同(`your-company.yuque.com`
- 部分接口需要额外权限
- 团队管理接口更丰富
### 7. 大文档性能问题
超过 5 万字的文档在创建/更新时可能超时。建议:
- 拆分为多篇文档
- 使用分页上传
- 图片先上传到 CDN 再引用
---
## EXTEND.md 扩展
用户可在技能同目录下创建 `EXTEND.md` 添加:
- 默认知识库 namespace
- 团队的语雀 Host 地址
- 周报/月报模板定制
- 常用知识库列表和别名
- 自定义文档模板