# use_vala_skillhub 管理 Vala SkillHub 上的技能:推送(上传)和安装。 SkillHub 基于 Gitea,每个技能对应一个独立的 Git 仓库。推送时使用 `./tmp` 临时目录,不在 `./skills` 内创建 `.git`,避免影响 workspace 级别的 git 备份。 ## 命名规则 仓库名格式:`{skill_name}.{source_name}` - `skill_name`:技能目录名(如 `cron_job`、`web_scraper`) - `source_name`:来源名称,即当前数字员工的 name(如 `xiaoxi`) - 如果 `source_name` 为 `vala`,表示公司级别的官方技能 示例: - `cron_job.xiaoxi` — xiaoxi 的定时任务技能 - `web_scraper.vala` — 公司官方的爬虫技能 ## 配置 操作前需要确认以下配置(保存到 `./.vala_skillhub_config`,即当前 workspace 根目录下): | 配置项 | 说明 | 默认值 | |--------|------|--------| | `GITEA_URL` | Gitea 服务地址 | `https://git.valavala.com` | | `GITEA_TOKEN` | Gitea API Token(需有创建仓库和推送权限) | — | | `GITEA_OWNER` | SkillHub 组织名 | `vala_skillhub` | | `SOURCE_NAME` | 当前数字员工的 name,用于组合仓库名 | — | 如果配置文件不存在,请询问用户获取以上信息后创建: ```bash cat > ./.vala_skillhub_config < GITEA_OWNER=vala_skillhub SOURCE_NAME= EOF ``` 后续操作前先加载配置: ```bash source ./.vala_skillhub_config ``` --- ## 操作一:推送技能到 SkillHub 将本地 `./skills` 下的技能目录推送到 SkillHub。 **核心原则**:使用 `./tmp/skill_push/` 作为临时工作区,不在 `./skills` 内执行任何 git 操作,保持 workspace 干净。 ### 流程 1. **确定仓库名**:`repo_name = {skill_dir_name}.{SOURCE_NAME}` 2. **检查远程仓库是否存在**: ```bash curl -s -o /dev/null -w "%{http_code}" \ "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${repo_name}" \ -H "Authorization: token ${GITEA_TOKEN}" ``` - 返回 200 → 仓库已存在,跳到步骤 4 - 返回 404 → 需要创建,执行步骤 3 3. **创建远程仓库**: ```bash curl -s -X POST "${GITEA_URL}/api/v1/orgs/${GITEA_OWNER}/repos" \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name": "'${repo_name}'", "private": false, "description": "技能描述", "auto_init": false}' ``` 4. **复制到临时目录并推送**: ```bash # 清理并准备临时目录 rm -rf ./tmp/skill_push/${repo_name} mkdir -p ./tmp/skill_push/${repo_name} # 复制技能内容(不含隐藏文件的 .git 等) cp -r ./skills/${skill_dir_name}/* ./tmp/skill_push/${repo_name}/ cp -r ./skills/${skill_dir_name}/.[!.]* ./tmp/skill_push/${repo_name}/ 2>/dev/null || true # 在临时目录中执行 git 操作 cd ./tmp/skill_push/${repo_name} git init git checkout -b main git add -A git commit -m "update: sync skill $(date +%Y-%m-%d)" git remote add origin https://oauth2:${GITEA_TOKEN}@${GITEA_URL#https://}/${GITEA_OWNER}/${repo_name}.git git push -u origin main --force ``` 5. **清理临时目录**: ```bash cd - rm -rf ./tmp/skill_push/${repo_name} ``` ### 批量推送 遍历 `./skills/` 下所有子目录,对每个目录重复以上流程。注意跳过 `use_vala_skillhub` 目录本身。 --- ## 操作二:安装 / 更新技能 从 SkillHub 下载技能到本地 `./skills` 目录。若本地已存在同名目录,则**清空后重新下载**,确保与远程版本一致。 **注意**:不使用 `git clone`,而是下载归档解压,避免在 `./skills` 下产生 `.git` 目录。 ### 流程 1. **确定要安装的仓库名**(完整名,如 `cron_job.xiaoxi`) 2. **下载并解压**(已存在则先清空再覆盖): ```bash repo_name="cron_job.xiaoxi" target_dir="./skills/${repo_name}" # 如果已存在,清空目录内容以确保与远程一致(删除远程已移除的文件) rm -rf "${target_dir}" mkdir -p "${target_dir}" # 通过 Gitea API 下载 tar.gz 归档并解压(自动尝试 main/master) curl -sL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${repo_name}/archive/main.tar.gz" \ -H "Authorization: token ${GITEA_TOKEN}" \ | tar xz --strip-components=1 -C "${target_dir}" 2>/dev/null \ || curl -sL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${repo_name}/archive/master.tar.gz" \ -H "Authorization: token ${GITEA_TOKEN}" \ | tar xz --strip-components=1 -C "${target_dir}" ``` --- ## 操作三:列出 SkillHub 上的技能 ```bash curl -s "${GITEA_URL}/api/v1/orgs/${GITEA_OWNER}/repos?page=1&limit=50&sort=updated" \ -H "Authorization: token ${GITEA_TOKEN}" ``` 返回 JSON 数组,每个元素包含 `name`、`description`、`updated_at` 等字段。如结果满 50 条,继续翻页 `page=2`。 --- ## 操作四:自动同步(变更检测 + 自动推送) 当 skill 发生新增或更新时,自动检测变更并仅推送有变化的 skill。 ### 哈希状态文件 使用 `./.vala_skill_hashes`(workspace 根目录下)记录每个 skill 上次推送时的内容哈希,格式为每行一条记录: ``` skill_dir_name hash ``` 示例: ``` cron_job a3f2b8c9... web_scraper 7d1e4f6a... ``` ### 计算 skill 目录哈希 对 skill 目录内所有文件(含文件路径)计算综合哈希,确保文件新增、删除、重命名、内容修改都能被检测到: ```bash compute_skill_hash() { local skill_dir="$1" (cd "${skill_dir}" && find . -type f -not -path '*/\.*' | LC_ALL=C sort | while read f; do echo "FILE:$f"; cat "$f"; done | sha256sum | awk '{print $1}') } ``` ### check_and_push 完整流程 1. **加载配置和哈希状态**: ```bash source ./.vala_skillhub_config HASH_FILE=./.vala_skill_hashes touch "${HASH_FILE}" ``` 2. **遍历 `./skills/` 下所有 skill 目录**,对每个 skill: ```bash for skill_dir in ./skills/*/; do skill_name=$(basename "${skill_dir}") # 跳过 use_vala_skillhub 自身 if [ "${skill_name}" = "use_vala_skillhub" ]; then continue fi # 计算当前哈希 current_hash=$(compute_skill_hash "${skill_dir}") # 读取上次推送的哈希 stored_hash=$(grep "^${skill_name} " "${HASH_FILE}" | awk '{print $2}') if [ "${current_hash}" = "${stored_hash}" ]; then echo "[skip] ${skill_name} — 无变更" continue fi echo "[sync] ${skill_name} — 检测到变更,开始推送..." # 执行推送(同操作一的流程) repo_name="${skill_name}.${SOURCE_NAME}" # 检查远程仓库是否存在 http_code=$(curl -s -o /dev/null -w "%{http_code}" \ "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${repo_name}" \ -H "Authorization: token ${GITEA_TOKEN}") # 如果不存在则创建 if [ "${http_code}" = "404" ]; then # 从 skill.json 读取描述(如果有) desc="" if [ -f "${skill_dir}/skill.json" ]; then desc=$(cat "${skill_dir}/skill.json" | grep '"description"' | head -1 | sed 's/.*"description"[[:space:]]*:[[:space:]]*"\(.*\)".*/\1/') fi curl -s -X POST "${GITEA_URL}/api/v1/orgs/${GITEA_OWNER}/repos" \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name": "'"${repo_name}"'", "private": false, "description": "'"${desc}"'", "auto_init": false}' fi # 复制到临时目录并推送 rm -rf ./tmp/skill_push/${repo_name} mkdir -p ./tmp/skill_push/${repo_name} cp -r ${skill_dir}* ./tmp/skill_push/${repo_name}/ cp -r ${skill_dir}.[!.]* ./tmp/skill_push/${repo_name}/ 2>/dev/null || true cd ./tmp/skill_push/${repo_name} git init git checkout -b main git add -A git commit -m "auto-sync: ${skill_name} $(date +%Y-%m-%d_%H:%M)" git remote add origin "https://oauth2:${GITEA_TOKEN}@${GITEA_URL#https://}/${GITEA_OWNER}/${repo_name}.git" git push -u origin main --force cd - # 清理临时目录 rm -rf ./tmp/skill_push/${repo_name} # 更新哈希状态文件 # 先移除旧记录,再追加新记录 grep -v "^${skill_name} " "${HASH_FILE}" > "${HASH_FILE}.tmp" || true echo "${skill_name} ${current_hash}" >> "${HASH_FILE}.tmp" mv "${HASH_FILE}.tmp" "${HASH_FILE}" echo "[done] ${skill_name} — 推送完成" done ``` 3. **输出同步摘要**:推送完成后,汇总本次同步了哪些 skill(跳过了哪些)。 ### 单个 skill 的快速同步 当你明确知道哪个 skill 发生了变更时,可以仅对该 skill 执行 check_and_push,无需遍历所有目录: ```bash skill_name="目标skill名" skill_dir="./skills/${skill_name}" # 然后执行上面循环体中的逻辑 ``` --- ## 数字员工行为规范(重要) 作为数字员工,你**必须**在以下场景中自动执行 `check_and_push`: 1. **创建新 skill 后** — 在 `./skills/` 下新建了 skill 目录并完成编写后,立即执行同步 2. **修改现有 skill 后** — 对 `./skills/` 下任何 skill 的文件做了修改后,立即执行同步 3. **删除 skill 文件后** — 如果删除了 skill 中的某些文件(重构等),同步以保持远程一致 4. **定时兜底**(可选) — 如果你拥有 `cron_job` 技能,建议设置每日一次的全量 check_and_push 作为安全网 ### 推送时机建议 - **立即推送**:skill 的功能性变更完成且验证通过后 - **不要推送**:正在编辑中间态、尚未完成的 skill - **批量场景**:如果一次性修改了多个 skill,在全部完成后执行一次全量 check_and_push 即可 ### 自动推送日志 每次推送后,建议在控制台输出简短日志,方便追溯: ``` [auto-sync] 2025-04-01 23:00 — 推送 2 个 skill: cron_job, web_scraper | 跳过 3 个(无变更) ```