Files
agent-skills/devops/gitea-code-sync/SKILL.md
Hermes Agent ccc63d1e70 first commit
2026-05-10 13:52:46 +08:00

14 KiB
Raw Blame History

name, description, version, author, license, metadata
name description version author license metadata
gitea-code-sync 通过 Gitea 仓库进行代码同步的工作流 — agent 在云端写代码推送到仓库,用户在本地拉取 1.0.0 Hermes Agent MIT
hermes
tags platforms
git
gitea
workflow
deployment
qqbot

Gitea 代码同步工作流

背景

Agent 部署在云端服务器,用户在本机。简单项目完全交给 agent 开发agent 写完后 push 到 Gitea 仓库,用户在本地 pull。

Gitea 凭证

  • 平台: https://gitea.ephron.ren
  • 用户: Elaina
  • Token: 存储在 ~/.netrc
  • 配置: git config --global credential.helper store

工作流程

Agent 端(云端)

  1. 收到项目开发任务后,在 /home/ubuntu/projects/ 目录下创建项目
  2. 开发完成后,初始化 git如果还没有
    cd /home/ubuntu/projects/<project_name>
    git init
    git remote add origin https://gitea.ephron.ren/Elaina/<repo_name>.git
    git add .
    git commit -m "Initial commit"
    git push -u origin main
    

通过 Gitea API 创建仓库

# Token 从 ~/.netrc 读取
TOKEN=$(grep gitea.ephron.ren -A1 ~/.netrc | grep password | awk '{print $2}')
curl -s -u "token:$TOKEN" "https://gitea.ephron.ren/api/v1/user/repos" \
  -X POST -H "Content-Type: application/json" \
  -d '{"name": "repo_name", "private": true, "description": "项目描述"}'

用户端(本地)

# 克隆仓库
git clone https://gitea.ephron.ren/Elaina/<repo_name>.git

# 后续更新
git pull origin main

交付物类型判断

用户说"推送到仓库"时,先判断交付物类型,不要默认推源代码:

用户用词 期望交付物 推送内容
修复方案、分析报告、方案文档 Markdown 文档(问题描述 + 根因 + diff + 验证) .md 文件到新仓库
代码、实现、开发 源代码 项目代码到仓库
测试结果、测试报告 测试报告文档 .md 文件到仓库

教训:用户说"修复方案推送到新仓库",意思是推送一份修复方案文档(分析+方案),不是把修改后的源代码推过去。

仓库隐私性规则(用户偏好)

创建仓库时根据内容隐私性判断:

  • 私有库: 内部测试、敏感数据、个人项目、QA 测试
  • 公开库: 开源项目、公开文档、展示性内容

私有库添加协作者: 创建后将用户的 Gitea 用户名添加为 write 权限协作者。Gitea 用户名需通过 API 确认(如 curl -u "token:TOKEN" "https://gitea.ephron.ren/api/v1/repos/{owner}/{repo}/collaborators" 列出现有协作者可作为参考)。已确认有效的 Gitea 用户名: ephron_ren

Gitea API 操作

盘点所有仓库(含私有)

TOKEN=$(awk '/gitea.ephron.ren/{found=1} found && /password/{print $2; exit}' ~/.netrc)
for user in Elaina ephron_ren; do
  echo "=== $user ==="
  curl -s -H "Authorization: token $TOKEN" \
    "https://gitea.ephron.ren/api/v1/users/$user/repos?limit=100" \
    | jq -r '.[] | "\(.full_name) | \(.private) | \(.updated_at[:10])"'
done

⚠️ /api/v1/repos/search 不返回私有仓库,盘点必须用 /api/v1/user/repos/api/v1/users/{username}/repos。详见 references/repo-inventory.md

修改仓库可见性

# 改为私有
curl -s -X PATCH -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"private": true}' \
  "https://gitea.ephron.ren/api/v1/repos/{owner}/{repo}"

# 改为公开
curl -s -X PATCH -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"private": false}' \
  "https://gitea.ephron.ren/api/v1/repos/{owner}/{repo}"

添加协作者

curl -s -X PUT -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"permission": "write"}' \
  "https://gitea.ephron.ren/api/v1/repos/{owner}/{repo}/collaborators/{username}"

常见错误

  • remote: Push to create is not enabled for users. + HTTP 403: 远程仓库不存在,需要先通过 API 创建。参见上方"通过 Gitea API 创建仓库"
  • user should be an owner or a collaborator with admin write: 当前 token 用户不是仓库 owner需要 owner 操作或 fork 到自己账号下
  • user does not exist: 用户名拼写错误Gitea 用户名区分大小写
  • User permission denied for writing: 当前 token 对目标仓库没有写权限(例如 ephron_ren/ephron.ren 对 Elaina 是只读的)

Push 被拒后的排错流程

git push 返回 403 时,先确认远程仓库是否存在:

# 检查仓库是否存在
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: token $TOKEN" \
  "https://gitea.ephron.ren/api/v1/repos/{owner}/{repo}"
# 404 = 仓库不存在 → 需要创建
# 200 = 仓库存在 → 权限问题

如果仓库不存在,用 API 创建后再 push。如果仓库存在但 push 被拒,检查协作者权限。

推送权限被拒时的解决方案

git push 返回 User permission denied for writing 时:

方案 A创建新仓库推荐

# 在 Elaina 账号下创建新仓库
TOKEN=$(grep gitea.ephron.ren -A1 ~/.netrc | grep password | awk '{print $2}')
curl -s -X POST "https://gitea.ephron.ren/api/v1/user/repos" \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<new-repo-name>",
    "description": "<描述>",
    "private": false,
    "auto_init": true,
    "default_branch": "main"
  }'

# 然后推送到新仓库
cd /path/to/project
git remote set-url origin https://gitea.ephron.ren/Elaina/<new-repo-name>.git
# 如果远程有 auto_init 的 README先拉取合并
git pull origin main --allow-unrelated-histories --no-rebase
git push -u origin main

方案 B请仓库 owner 添加协作者权限

  • 需要 ephron_ren 用户在 Gitea 上给 Elaina 添加 write 权限
  • 适合需要长期协作的场景

注意事项

  • 项目目录放在 /home/ubuntu/projects/
  • Token 有写权限,可以 push 也可以创建仓库
  • 简单项目直接交给 agent 开发,无需用户介入代码层面
  • 权限问题: 只有仓库 owner 或 admin 权限协作者才能修改仓库设置和添加协作者。Agent 账号 (Elaina) 只能操作自己创建的仓库。

⚠️ 破坏性操作必须先确认

删除仓库、强制推送、覆盖分支等破坏性操作,必须先向用户确认,不能擅自执行。

用户曾明确要求:"清理无用仓库,清理这种危险动作要先让我确认"

正确流程:

  1. 列出待删除/修改的仓库或分支
  2. 向用户展示清单并请求确认
  3. 用户确认后再执行

错误:直接执行 curl -X DELETE ... 删除仓库 正确:先问"发现旧仓库 X需要删除吗请确认"

Feature Branch 工作流

当开发复杂功能时,使用 feature branch 避免影响 main 分支:

创建 feature branch

cd /home/ubuntu/projects/<repo>
git checkout -b feature/<feature-name>

开发并提交

# 开发完成后
git add .
git commit -m "feat: <feature description>"
git push origin feature/<feature-name>

合并到 main

# 方法1: 直接合并(简单项目)
git checkout main
git merge feature/<feature-name>
git push origin main

# 方法2: 通过 Gitea API 创建 Pull Request推荐
TOKEN=$(grep gitea.ephron.ren -A1 ~/.netrc | grep password | awk '{print $2}')
curl -s -X POST "https://gitea.ephron.ren/api/v1/repos/{owner}/{repo}/pulls" \
  -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "feat: <feature description>",
    "head": "feature/<feature-name>",
    "base": "main",
    "body": "## 变更说明\n\n- 变更1\n- 变更2"
  }'

清理 feature branch

# 合并后删除本地分支
git branch -d feature/<feature-name>

# 删除远程分支
git push origin --delete feature/<feature-name>

常见模式

详细的 API 参考和脱敏模式见 references/gitea-api.mdreferences/redaction-patterns.mdreferences/repo-inventory.md(仓库盘点与枚举模式)。

克隆已存在的仓库

# 方法1: 目录已存在但为空
git clone https://gitea.ephron.ren/Elaina/<repo>.git /home/ubuntu/projects/<repo>
# 会报错 "directory not empty" → 手动处理

# 方法2: 目录已存在,直接进去操作
cd /home/ubuntu/projects/<repo>
git pull origin master  # 确保最新
# 然后正常 add/commit/push

增量提交(每个模块完成后)

cd /home/ubuntu/projects/<repo>
git add <changed_file>
git commit -m "模块N测试完成: X用例通过, 发现Y个问题"
git push origin master

推送 Hermes 核心文件到私有库

# 创建仓库
curl -s -u "token:TOKEN" "https://gitea.ephron.ren/api/v1/user/repos" \
  -X POST -H "Content-Type: application/json" \
  -d '{"name":"hermes-core","private":true,"description":"Hermes Agent 核心配置"}'

# 打包核心文件(包含 SOUL.md、config.yaml、memories、scripts
cd /home/ubuntu/projects/hermes-core
git init
# ... add and commit ...
git push -u origin master

Hermes 核心文件备份(完整版)

用于服务器数据完全丢失后的完整恢复。备份所有核心配置文件,敏感信息脱敏存储。

需要备份的核心文件清单:

文件 说明 敏感度
SOUL.md 人格定义
memories/MEMORY.md 持久化记忆
memories/USER.md 用户偏好
config.yaml 主配置
.env 环境变量(含 API Key
auth.json 凭证池
providers/*.json 模型提供商配置
scripts/mimo_*.py 能力脚本
channel_directory.json 渠道配置
gateway_state.json 网关运行时状态
models_dev_cache.json 模型缓存信息

脱敏方案(备份前执行):

不要用纯 regex 字符串替换,会漏字段、会弄坏 JSON 格式。

正确做法:

import re, json

# 1. .env — 用 Python 逐行处理
with open('.env', 'r') as f:
    content = f.read()
lines = []
for line in content.split('\n'):
    stripped = line.lstrip()
    if stripped.startswith('#'):
        lines.append(line)
        continue
    m = re.match(r'^([A-Z_]+)=(.+)$', line)
    if m and any(s in m.group(1) for s in ['API_KEY', 'SECRET', 'TOKEN', 'PASSWORD']):
        lines.append(f"{m.group(1)}=***")
    else:
        lines.append(line)
with open('.env', 'w') as f:
    f.write('\n'.join(lines))

# 2. auth.json — 用 json 模块序列化,保持格式正确
with open('auth.json', 'r') as f:
    auth = json.load(f)
for provider, creds in auth['credential_pool'].items():
    for c in creds:
        c['access_token'] = '***'
with open('auth.json', 'w') as f:
    json.dump(auth, f, indent=2, ensure_ascii=False)

⚠️ 容易遗漏的字段(必须覆盖):

  • WEIXIN_TOKENWEIXIN_ACCOUNT_ID
  • WEIXIN_ALLOWED_USERSWEIXIN_HOME_CHANNEL(含用户 openid
  • QQ_CLIENT_SECRET
  • access_tokentp- / sk- 前缀的完整 token

验证脱敏是否干净:

grep -v "^#" .env | grep -E "tp-[a-zA-Z0-9]{20,}|sk-[a-zA-Z0-9]{20,}|bq6New[A-Za-z0-9]+|[a-f0-9]{30,}|o9cq" && echo "有泄露" || echo "干净"

恢复时需要手动补充的字段(写入 RESTORE.md

  • .env: XIAOMI_API_KEYMINIMAX_CODING_API_KEYQQ_CLIENT_SECRETWEIXIN_TOKENWEIXIN_ACCOUNT_IDWEIXIN_ALLOWED_USERSWEIXIN_HOME_CHANNEL
  • auth.json: credential_pool 中各 provider 的 access_token
  • ~/.netrc: Gitea 访问令牌machine/login/password

RESTORE.md 模板:

# 恢复说明

仓库中包含脱敏后的配置文件。恢复时需要手动补充以下敏感信息:

## .env

| 字段 | 说明 | 获取方式 |
|------|------|----------|
| `XIAOMI_API_KEY` | Xiaomi MiMo API Key | https://platform.xiaomimimo.com |
| `MINIMAX_CODING_API_KEY` | MiniMax 编码 API Key | https://api.minimaxi.com |
| `QQ_CLIENT_SECRET` | QQ 机器人客户端密钥 | https://connect.qq.com |
| `WEIXIN_TOKEN` | 微信机器人 Token | 微信开放平台 |
| `WEIXIN_ACCOUNT_ID` | 微信机器人账号 ID | 微信开放平台 |
| `WEIXIN_ALLOWED_USERS` | 微信允许的用户列表openid | - |
| `WEIXIN_HOME_CHANNEL` | 微信主页频道 ID | - |

## auth.json

`credential_pool` 中各 provider 的 `access_token` 字段需填入真实 API Key。

## .netrc

`~/.netrc` 包含 Gitea 访问令牌。恢复后重新配置:

echo 'machine gitea.ephron.ren login password ' > ~/.netrc chmod 600 ~/.netrc

完整备份流程:

TOKEN=$(grep gitea.ephron.ren -A1 ~/.netrc | grep password | awk '{print $2}')
# 1. 创建仓库
curl -s -u "token:$TOKEN" "https://gitea.ephron.ren/api/v1/user/repos" \
  -X POST -H "Content-Type: application/json" \
  -d '{"name":"hermes-core","private":true,"description":"Hermes Agent 核心配置"}'

# 2. 打包并脱敏
mkdir -p /home/ubuntu/projects/hermes-core
cd /home/ubuntu/projects/hermes-core
git init
cp ~/.hermes/SOUL.md .
cp ~/.hermes/config.yaml .
cp ~/.hermes/memories/MEMORY.md .
cp ~/.hermes/memories/USER.md .
cp ~/.hermes/.env . && python3 redact_env.py .env
cp ~/.hermes/auth.json . && python3 redact_auth.py auth.json
cp -r ~/.hermes/providers .
cp -r ~/.hermes/scripts .
cp ~/.hermes/channel_directory.json .
cp ~/.hermes/gateway_state.json .

# 3. 添加 RESTORE.md
# ... 编写恢复说明 ...

# 4. 推送
git add -A && git commit -m "Backup $(date +%Y-%m-%d)" && git push -u origin master

QA报告推送到仓库推荐工作流

# 每完成一个模块就推送一次,不用等全部完成
git add test-results-v3.md
git commit -m "模块X测试完成: N/M用例"
git push origin master