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

410 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: gitea-code-sync
description: 通过 Gitea 仓库进行代码同步的工作流 — agent 在云端写代码推送到仓库,用户在本地拉取
version: 1.0.0
author: Hermes Agent
license: MIT
metadata:
hermes:
tags: [git, gitea, workflow, deployment]
platforms: [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如果还没有
```bash
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 创建仓库
```bash
# 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": "项目描述"}'
```
### 用户端(本地)
```bash
# 克隆仓库
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 操作
### 盘点所有仓库(含私有)
```bash
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`。
### 修改仓库可见性
```bash
# 改为私有
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}"
```
### 添加协作者
```bash
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 时,先确认远程仓库是否存在:
```bash
# 检查仓库是否存在
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创建新仓库推荐**
```bash
# 在 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
```bash
cd /home/ubuntu/projects/<repo>
git checkout -b feature/<feature-name>
```
### 开发并提交
```bash
# 开发完成后
git add .
git commit -m "feat: <feature description>"
git push origin feature/<feature-name>
```
### 合并到 main
```bash
# 方法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
```bash
# 合并后删除本地分支
git branch -d feature/<feature-name>
# 删除远程分支
git push origin --delete feature/<feature-name>
```
## 常见模式
详细的 API 参考和脱敏模式见 `references/gitea-api.md`、`references/redaction-patterns.md`、`references/repo-inventory.md`(仓库盘点与枚举模式)。
### 克隆已存在的仓库
```bash
# 方法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
```
### 增量提交(每个模块完成后)
```bash
cd /home/ubuntu/projects/<repo>
git add <changed_file>
git commit -m "模块N测试完成: X用例通过, 发现Y个问题"
git push origin master
```
### 推送 Hermes 核心文件到私有库
```bash
# 创建仓库
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 格式。
✅ 正确做法:
```python
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_TOKEN`、`WEIXIN_ACCOUNT_ID`
- `WEIXIN_ALLOWED_USERS`、`WEIXIN_HOME_CHANNEL`(含用户 openid
- `QQ_CLIENT_SECRET`
- `access_token` 中 `tp-` / `sk-` 前缀的完整 token
**验证脱敏是否干净:**
```bash
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_KEY`、`MINIMAX_CODING_API_KEY`、`QQ_CLIENT_SECRET`、`WEIXIN_TOKEN`、`WEIXIN_ACCOUNT_ID`、`WEIXIN_ALLOWED_USERS`、`WEIXIN_HOME_CHANNEL`
- `auth.json`: `credential_pool` 中各 provider 的 `access_token`
- `~/.netrc`: Gitea 访问令牌machine/login/password
**RESTORE.md 模板:**
```markdown
# 恢复说明
仓库中包含脱敏后的配置文件。恢复时需要手动补充以下敏感信息:
## .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 <token>
password <token>' > ~/.netrc
chmod 600 ~/.netrc
```
```
**完整备份流程:**
```bash
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报告推送到仓库推荐工作流
```bash
# 每完成一个模块就推送一次,不用等全部完成
git add test-results-v3.md
git commit -m "模块X测试完成: N/M用例"
git push origin master
```