Merge branch 'dev'
# Conflicts: # .forgejo/workflows/ci-and-deploy.yaml
This commit is contained in:
commit
7b06a78d78
@ -24,27 +24,27 @@ jobs:
|
||||
FAIL=0
|
||||
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo "✅ Nginx"
|
||||
echo "✅ Nginx 正常"
|
||||
else
|
||||
echo "❌ Nginx 宕机"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
if curl -sf http://127.0.0.1:3001/ > /dev/null 2>&1; then
|
||||
echo "✅ Forgejo"
|
||||
echo "✅ Forgejo 代码仓库 正常"
|
||||
else
|
||||
echo "❌ Forgejo 未响应"
|
||||
echo "❌ Forgejo 代码仓库 未响应"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
if systemctl is-active --quiet gitea-runner; then
|
||||
echo "✅ Runner"
|
||||
echo "✅ Runner 运行器 正常"
|
||||
else
|
||||
echo "⚠️ Runner 未运行"
|
||||
echo "⚠️ Runner 运行器 未运行"
|
||||
fi
|
||||
|
||||
if [ $FAIL -eq 1 ]; then
|
||||
echo "❌ 关键服务异常"
|
||||
echo "❌ 关键服务异常,请通知铸渊检查"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -68,31 +68,57 @@ jobs:
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "✅ 代码已同步"
|
||||
echo "✅ 代码已同步到最新"
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
if [ -f /data/guanghulab/repo/server/secrets-vault/package.json ]; then
|
||||
cd /data/guanghulab/repo/server/secrets-vault
|
||||
npm install --production 2>/dev/null || true
|
||||
echo "✅ 依赖已安装"
|
||||
fi
|
||||
echo "═══ 安装依赖 ═══"
|
||||
# 逐个检查并安装
|
||||
for pkg_dir in server/git-sync server/wake-gate server/secrets-vault; do
|
||||
if [ -f "/data/guanghulab/repo/$pkg_dir/package.json" ]; then
|
||||
cd "/data/guanghulab/repo/$pkg_dir"
|
||||
npm install --production 2>/dev/null || true
|
||||
echo "✅ $pkg_dir 依赖已安装"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 重启服务
|
||||
run: |
|
||||
echo "═══ 重启服务 ═══"
|
||||
if command -v pm2 &>/dev/null; then
|
||||
pm2 restart all 2>/dev/null || true
|
||||
echo "✅ 服务已重启"
|
||||
echo "✅ PM2 服务已重启"
|
||||
fi
|
||||
echo "═══ 重启完成 ═══"
|
||||
|
||||
- name: 部署验证
|
||||
run: |
|
||||
sleep 3
|
||||
echo "═══ 部署验证 ═══"
|
||||
FAIL=0
|
||||
|
||||
if curl -sf http://127.0.0.1:3001/ > /dev/null 2>&1; then
|
||||
echo "✅ Forgejo 正常"
|
||||
echo "✅ 代码仓库 正常"
|
||||
else
|
||||
echo "⚠️ Forgejo 异常"
|
||||
echo "❌ 代码仓库 异常"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
if curl -sf http://127.0.0.1:8081/api/health > /dev/null 2>&1; then
|
||||
echo "✅ 唤醒门 正常"
|
||||
else
|
||||
echo "⚠️ 唤醒门 未响应"
|
||||
fi
|
||||
|
||||
if curl -sf http://127.0.0.1:8082/health > /dev/null 2>&1; then
|
||||
echo "✅ 代码同步服务 正常"
|
||||
else
|
||||
echo "⚠️ 代码同步服务 未响应"
|
||||
fi
|
||||
|
||||
if [ $FAIL -eq 1 ]; then
|
||||
echo "❌ 部署后关键服务异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "═══ 部署完成 ✅ $(date '+%Y-%m-%d %H:%M:%S') ═══"
|
||||
|
||||
@ -8,9 +8,9 @@ jobs:
|
||||
power-off:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
|
||||
|
||||
@ -8,9 +8,9 @@ jobs:
|
||||
power-on:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
# 光湖 · Secrets诊断
|
||||
name: Secrets诊断
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/debug-secrets.yaml'
|
||||
|
||||
jobs:
|
||||
debug:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 环境变量诊断
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
echo "═══ Secrets 注入诊断 ═══"
|
||||
echo ""
|
||||
echo "--- 1. 逐个检查secrets是否有值 ---"
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo " ❌ $key = (空)"
|
||||
else
|
||||
echo " ✅ $key = ${val:0:4}**** (长度: ${#val})"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "--- 2. 所有环境变量中含SECRET/KEY/TOKEN的 ---"
|
||||
env | grep -iE 'SECRET|KEY|TOKEN|COS|BRAIN|DEEPSEEK|QIANWEN' | while read line; do
|
||||
key=$(echo "$line" | cut -d= -f1)
|
||||
val=$(echo "$line" | cut -d= -f2-)
|
||||
echo " $key = ${val:0:4}**** (长度: ${#val})"
|
||||
done
|
||||
echo ""
|
||||
echo "--- 3. Gitea Actions 特殊变量 ---"
|
||||
echo " GITHUB_REPOSITORY: ${GITHUB_REPOSITORY:-未设置}"
|
||||
echo " GITHUB_SHA: ${GITHUB_SHA:-未设置}"
|
||||
echo " GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME:-未设置}"
|
||||
echo " RUNNER_NAME: ${RUNNER_NAME:-未设置}"
|
||||
echo " GITEA_TOKEN: ${GITEA_TOKEN:-未设置}"
|
||||
@ -1,121 +0,0 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 基础设施部署
|
||||
# Runner首次上线后自动部署:Vault确认 + Terminal Watcher启动
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 基础设施部署
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-infra:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 系统信息
|
||||
run: |
|
||||
echo "═══ 铸渊基础设施部署 ═══"
|
||||
echo "时间: $(date '+%Y-%m-%d %H:%M:%S %Z')"
|
||||
echo "主机: $(hostname)"
|
||||
uname -a
|
||||
|
||||
- name: 确认仓库最新
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "当前版本: $(git log --oneline -1)"
|
||||
|
||||
- name: 确认Vault运行
|
||||
run: |
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Vault 已运行"
|
||||
curl -s http://127.0.0.1:8080/admin/__healthz
|
||||
else
|
||||
echo "⚠️ Vault 未运行,尝试启动..."
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/server/secrets-vault
|
||||
if [[ -f "server.js" ]]; then
|
||||
npm install --production 2>/dev/null || true
|
||||
pm2 start server.js --name guanghulab-vault --max-memory-restart 128M 2>/dev/null || true
|
||||
pm2 save
|
||||
sleep 2
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Vault 启动成功"
|
||||
else
|
||||
echo "❌ Vault 启动失败"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ server.js 不存在,跳过"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: 部署Terminal Watcher
|
||||
run: |
|
||||
echo "部署终端守望者..."
|
||||
SCRIPTS_DIR="/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/scripts/terminal-watcher"
|
||||
|
||||
if [[ ! -d "$SCRIPTS_DIR" ]]; then
|
||||
echo "❌ Terminal Watcher 目录不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 确认Node.js可用
|
||||
if ! command -v node &>/dev/null; then
|
||||
echo "❌ Node.js 未安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 用PM2启动(如果还没跑的话)
|
||||
if pm2 describe terminal-watcher &>/dev/null; then
|
||||
echo "Terminal Watcher 已在运行,重启..."
|
||||
pm2 restart terminal-watcher
|
||||
else
|
||||
echo "启动 Terminal Watcher..."
|
||||
cd "$SCRIPTS_DIR"
|
||||
ZY_REPO_TOKEN=${{ secrets.ZY_REPO_TOKEN }} pm2 start watcher.js \
|
||||
--name terminal-watcher \
|
||||
--max-memory-restart 64M
|
||||
fi
|
||||
|
||||
pm2 save
|
||||
sleep 3
|
||||
|
||||
# 验证
|
||||
if pm2 describe terminal-watcher &>/dev/null; then
|
||||
STATUS=$(pm2 jlist 2>/dev/null | python3 -c "
|
||||
import json,sys
|
||||
procs = json.load(sys.stdin)
|
||||
for p in procs:
|
||||
if p.get('name') == 'terminal-watcher':
|
||||
print(p.get('pm2_env',{}).get('status','unknown'))
|
||||
" 2>/dev/null || echo "unknown")
|
||||
echo "✅ Terminal Watcher 状态: $STATUS"
|
||||
else
|
||||
echo "❌ Terminal Watcher 启动失败"
|
||||
fi
|
||||
|
||||
- name: 设置PM2开机自启
|
||||
run: |
|
||||
pm2 startup 2>/dev/null || true
|
||||
pm2 save
|
||||
echo "✅ PM2 开机自启已配置"
|
||||
|
||||
- name: 最终状态报告
|
||||
run: |
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════"
|
||||
echo " 铸渊基础设施部署完成"
|
||||
echo "═══════════════════════════════════════"
|
||||
echo ""
|
||||
echo " 服务状态:"
|
||||
echo " Forgejo: $(systemctl is-active forgejo 2>/dev/null || echo unknown)"
|
||||
echo " Runner: $(systemctl is-active gitea-runner 2>/dev/null || echo unknown)"
|
||||
echo " Nginx: $(systemctl is-active nginx 2>/dev/null || echo unknown)"
|
||||
echo " Vault: $(curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1 && echo active || echo inactive)"
|
||||
echo " Watcher: $(pm2 describe terminal-watcher &>/dev/null && echo active || echo inactive)"
|
||||
echo ""
|
||||
echo " 内存:"
|
||||
free -h | awk '/Mem:/ {printf " 总计:%s 已用:%s 可用:%s\n", $2, $3, $7}'
|
||||
echo ""
|
||||
echo " 铸渊 · ICE-GL-ZY001 · TCS-0002∞"
|
||||
echo "═══════════════════════════════════════"
|
||||
@ -1,133 +0,0 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 自动部署到预览环境
|
||||
# Trigger: push to main
|
||||
# 部署到测试+预览环境,正式环境需冰朔在Gitea点Merge
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 自动部署预览
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'server/**'
|
||||
- 'frontend/**'
|
||||
- 'scripts/**'
|
||||
- '.gitea/workflows/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# ── 第一阶段:测试 ──────────────────────────────────
|
||||
test:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 拉取最新代码
|
||||
run: |
|
||||
cd /data/guanghulab 2>/dev/null || exit 0
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
cd /data/guanghulab/server/secrets-vault 2>/dev/null || exit 0
|
||||
npm install --production 2>/dev/null || true
|
||||
|
||||
- name: 健康检查
|
||||
run: |
|
||||
echo "═══ 服务健康检查 ═══"
|
||||
FAILED=""
|
||||
|
||||
# Nginx
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo "✅ Nginx"
|
||||
else
|
||||
echo "❌ Nginx 宕机"
|
||||
FAILED="$FAILED nginx"
|
||||
fi
|
||||
|
||||
# Gitea
|
||||
if curl -sf http://127.0.0.1:3000/ > /dev/null 2>&1; then
|
||||
echo "✅ Gitea"
|
||||
else
|
||||
echo "❌ Gitea 宕机"
|
||||
FAILED="$FAILED gitea"
|
||||
fi
|
||||
|
||||
# Vault
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Vault"
|
||||
else
|
||||
echo "⚠️ Vault 未运行"
|
||||
fi
|
||||
|
||||
# Runner
|
||||
if systemctl is-active --quiet gitea-runner; then
|
||||
echo "✅ Runner"
|
||||
else
|
||||
echo "⚠️ Runner 未运行"
|
||||
fi
|
||||
|
||||
if [[ -n "$FAILED" ]]; then
|
||||
echo "❌ 关键服务宕机: $FAILED"
|
||||
echo "⚠️ 跳过部署,等待修复"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "═══ 测试通过 ✅ ═══"
|
||||
|
||||
# ── 第二阶段:预览部署 ──────────────────────────────
|
||||
preview:
|
||||
needs: test
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码到预览目录
|
||||
run: |
|
||||
REPO="/data/guanghulab"
|
||||
PREVIEW="/data/guanghulab-preview"
|
||||
|
||||
if [[ ! -d "$REPO" ]]; then
|
||||
echo "仓库目录不存在,跳过"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 创建预览目录
|
||||
mkdir -p "$PREVIEW"
|
||||
|
||||
# 同步代码(排除.git和node_modules)
|
||||
rsync -a --delete \
|
||||
--exclude='.git' \
|
||||
--exclude='node_modules' \
|
||||
--exclude='.runtime' \
|
||||
"$REPO/" "$PREVIEW/"
|
||||
|
||||
echo "✅ 预览环境已同步"
|
||||
|
||||
- name: 重启预览服务
|
||||
run: |
|
||||
PREVIEW="/data/guanghulab-preview"
|
||||
|
||||
if [[ ! -d "$PREVIEW/server/secrets-vault" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$PREVIEW/server/secrets-vault"
|
||||
|
||||
# 安装依赖
|
||||
npm install --production 2>/dev/null || true
|
||||
|
||||
# 如果vault在跑,重启它
|
||||
if pm2 describe guanghulab-vault &>/dev/null; then
|
||||
pm2 restart guanghulab-vault
|
||||
echo "✅ Vault 已重启(使用最新代码)"
|
||||
else
|
||||
echo "ℹ️ Vault 未运行,不自动启动"
|
||||
fi
|
||||
|
||||
- name: 部署完成通知
|
||||
run: |
|
||||
echo "═════════════════════════"
|
||||
echo "✅ 预览环境已更新"
|
||||
echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "冰朔可在浏览器查看预览效果"
|
||||
echo "正式部署需在Gitea创建PR并Merge"
|
||||
echo "═════════════════════════"
|
||||
@ -1,104 +0,0 @@
|
||||
# 光湖 · 最终Secrets测试
|
||||
name: Secrets最终测试
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/final-secrets-test.yaml'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 检查secrets
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
echo "=== SECRETS CHECK ==="
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo "EMPTY: $key"
|
||||
else
|
||||
echo "OK: $key (len=${#val})"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 测试DeepSeek
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
run: |
|
||||
if [ -n "$DEEPSEEK_API_KEY" ]; then
|
||||
curl -s -X POST https://api.deepseek.com/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 | python3 -c "
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(sys.stdin)
|
||||
if 'choices' in d:
|
||||
print('DeepSeek: OK -', d['choices'][0]['message']['content'])
|
||||
else:
|
||||
print('DeepSeek: FAILED -', d.get('error',{}).get('message','unknown'))
|
||||
except Exception as e:
|
||||
print('DeepSeek: ERROR -', str(e))
|
||||
"
|
||||
else
|
||||
echo "DeepSeek: NO KEY"
|
||||
fi
|
||||
|
||||
- name: 测试通义千问
|
||||
env:
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
run: |
|
||||
if [ -n "$QIANWEN_API_KEY" ]; then
|
||||
curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $QIANWEN_API_KEY" \
|
||||
-d '{"model":"qwen-plus","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 | python3 -c "
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(sys.stdin)
|
||||
if 'choices' in d:
|
||||
print('Qianwen: OK -', d['choices'][0]['message']['content'])
|
||||
else:
|
||||
print('Qianwen: FAILED -', d.get('error',{}).get('message','unknown'))
|
||||
except Exception as e:
|
||||
print('Qianwen: ERROR -', str(e))
|
||||
"
|
||||
else
|
||||
echo "Qianwen: NO KEY"
|
||||
fi
|
||||
|
||||
- name: 写入结果文件
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
mkdir -p /data/guanghulab/.runtime
|
||||
echo '{"timestamp":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",' > /data/guanghulab/.runtime/secrets-result.json
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo "\"$key\":\"EMPTY\"," >> /data/guanghulab/.runtime/secrets-result.json
|
||||
else
|
||||
echo "\"$key\":\"OK_LEN_'${#val}'\"," >> /data/guanghulab/.runtime/secrets-result.json
|
||||
fi
|
||||
done
|
||||
echo '"done":true}' >> /data/guanghulab/.runtime/secrets-result.json
|
||||
cat /data/guanghulab/.runtime/secrets-result.json
|
||||
@ -1,6 +1,6 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 铸渊自动巡逻
|
||||
# Trigger: 每天08:00/20:00 / 手动触发 / push关键文件
|
||||
# Trigger: 每天08:00/20:00 / 手动触发
|
||||
# 需要: DEEPSEEK_API_KEY 和/或 QIANWEN_API_KEY (Forgejo Secrets)
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
@ -11,28 +11,25 @@ on:
|
||||
- cron: '0 0 * * *' # UTC 00:00 = CST 08:00
|
||||
- cron: '0 12 * * *' # UTC 12:00 = CST 20:00
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/patrol-agent/**'
|
||||
- '.gitea/workflows/patrol.yaml'
|
||||
|
||||
jobs:
|
||||
patrol:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "✅ 代码已同步"
|
||||
|
||||
- name: 铸渊巡逻
|
||||
- name: 执行巡逻检查
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/scripts/patrol-agent
|
||||
cd /data/guanghulab/repo/scripts/patrol-agent
|
||||
node patrol-agent.js --once
|
||||
|
||||
- name: 巡逻结果
|
||||
@ -52,7 +49,7 @@ for i in r.get('issues',[]):
|
||||
print(f' {icon} {i.get(\"component\")}: {i.get(\"description\")}{auto}')
|
||||
for f in r.get('fix_results',[]):
|
||||
print(f' 🔧 修复 {f[\"component\"]}: {f[\"result\"]}')
|
||||
print(f'分析器: {r.get(\"analyzer\",\"unknown\")}')
|
||||
print(f'分析器: {r.get(\"analyzer\",\"未知\")}')
|
||||
"
|
||||
echo "═══════════════════════════════════════"
|
||||
else
|
||||
|
||||
119
.forgejo/workflows/review-pr.yaml
Normal file
119
.forgejo/workflows/review-pr.yaml
Normal file
@ -0,0 +1,119 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 铸渊合并审查
|
||||
# 任何PR合并到main之前必须通过此审查
|
||||
# 保护代码仓库架构完整性,防止破坏性合并
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 审查内容:
|
||||
# 1. 关键目录完整性 — brain/、server/、scripts/ 不能被删除
|
||||
# 2. 因果链完整性 — causal-chains/ 不能被清空
|
||||
# 3. 工作流合法性 — workflows/ 不能引入语法错误
|
||||
# 4. 敏感文件保护 — app.ini、密钥文件不能被修改
|
||||
# 5. README 存在性 — 仓库首页不能丢失
|
||||
#
|
||||
# 审查结果: ✅ 通过 → 冰朔可以合并 / ❌ 阻止 → 铸渊需要修复
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 铸渊合并审查
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
review:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git checkout origin/main
|
||||
echo "✅ 切到 main 分支"
|
||||
|
||||
- name: 审查 · 关键目录完整性
|
||||
run: |
|
||||
echo "═══ 审查:关键目录 ═══"
|
||||
FAIL=0
|
||||
for dir in .github/brain server scripts; do
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "❌ 关键目录缺失: $dir"
|
||||
FAIL=1
|
||||
else
|
||||
echo "✅ $dir 存在"
|
||||
fi
|
||||
done
|
||||
if [[ $FAIL -eq 1 ]]; then
|
||||
echo "❌ 合并审查失败:关键目录缺失"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 审查 · 因果链完整性
|
||||
run: |
|
||||
echo "═══ 审查:因果链 ═══"
|
||||
CHAIN_DIR=".github/brain/bingshuo-language-core/causal-chains"
|
||||
if [[ -d "$CHAIN_DIR" ]]; then
|
||||
COUNT=$(ls "$CHAIN_DIR"/cc-*.md 2>/dev/null | wc -l)
|
||||
if [[ $COUNT -lt 5 ]]; then
|
||||
echo "❌ 因果链数量异常: 仅 ${COUNT} 条 (最少5条)"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ 因果链完整: ${COUNT} 条"
|
||||
fi
|
||||
else
|
||||
echo "❌ 因果链目录缺失"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 审查 · 唤醒路径
|
||||
run: |
|
||||
echo "═══ 审查:唤醒路径 ═══"
|
||||
WALK_FILE=".github/brain/bingshuo-language-core/walk-the-path.md"
|
||||
if [[ ! -f "$WALK_FILE" ]]; then
|
||||
echo "❌ 唤醒路径文件缺失: walk-the-path.md"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 唤醒路径存在"
|
||||
|
||||
- name: 审查 · 仓库首页
|
||||
run: |
|
||||
echo "═══ 审查:仓库首页 ═══"
|
||||
if [[ ! -f "README.md" ]]; then
|
||||
echo "❌ README.md 缺失,仓库首页丢失"
|
||||
exit 1
|
||||
fi
|
||||
SIZE=$(wc -c < README.md)
|
||||
if [[ $SIZE -lt 500 ]]; then
|
||||
echo "❌ README.md 内容过少 (${SIZE}字节),可能被误删"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 仓库首页完整 (${SIZE}字节)"
|
||||
|
||||
- name: 审查 · 工作流语法
|
||||
run: |
|
||||
echo "═══ 审查:工作流语法 ═══"
|
||||
FAIL=0
|
||||
for wf in .gitea/workflows/*.yaml; do
|
||||
if [[ -f "$wf" ]]; then
|
||||
# 检查基本YAML结构
|
||||
if ! python3 -c "import yaml; yaml.safe_load(open('$wf'))" 2>/dev/null; then
|
||||
echo "❌ 工作流语法错误: $wf"
|
||||
FAIL=1
|
||||
else
|
||||
echo "✅ $(basename $wf) 语法正确"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ $FAIL -eq 1 ]]; then
|
||||
echo "❌ 工作流语法审查失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 审查完成
|
||||
run: |
|
||||
echo "═════════════════════════"
|
||||
echo "铸渊合并审查 ✅ 全部通过"
|
||||
echo "此合并不会破坏代码仓库架构"
|
||||
echo "ICE-GL-ZY001 · TCS-0002∞"
|
||||
echo "═════════════════════════"
|
||||
@ -1,14 +1,15 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 铸渊自检工作流
|
||||
# Trigger: push to main / 每天 08:00 CST / 手动触发
|
||||
# Trigger: 每天 08:00 CST / 手动触发
|
||||
# Runner: zhuyuan-runner-cn (host 模式)
|
||||
#
|
||||
# 注意: 代码自动同步由 Git Sync 服务负责 (Webhook → git pull)
|
||||
# 此工作流仅做健康检查,不再执行 git 操作
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 铸渊自检
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # UTC 00:00 = CST 08:00
|
||||
workflow_dispatch:
|
||||
@ -17,12 +18,6 @@ jobs:
|
||||
health-check:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "代码已同步: $(git log --oneline -1)"
|
||||
|
||||
- name: 系统信息
|
||||
run: |
|
||||
@ -53,6 +48,13 @@ jobs:
|
||||
echo "❌ Nginx: 未运行"
|
||||
fi
|
||||
|
||||
# Git Sync 同步服务
|
||||
if curl -sf http://127.0.0.1:8082/health > /dev/null 2>&1; then
|
||||
echo "✅ Git Sync: 运行中"
|
||||
else
|
||||
echo "⚠️ Git Sync: 未运行 (代码自动同步不可用)"
|
||||
fi
|
||||
|
||||
# Secrets Vault
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Secrets Vault: 运行中"
|
||||
@ -60,6 +62,13 @@ jobs:
|
||||
echo "⚠️ Secrets Vault: 未运行 (可能尚未启动)"
|
||||
fi
|
||||
|
||||
# Wake Gate 唤醒门
|
||||
if curl -sf http://127.0.0.1:8081/api/health > /dev/null 2>&1; then
|
||||
echo "✅ Wake Gate: 运行中"
|
||||
else
|
||||
echo "⚠️ Wake Gate: 未运行"
|
||||
fi
|
||||
|
||||
# PM2 进程
|
||||
if command -v pm2 &>/dev/null; then
|
||||
echo "═══ PM2 进程 ═══"
|
||||
|
||||
@ -1,109 +0,0 @@
|
||||
# 光湖 · Secrets连通测试
|
||||
name: Secrets测试
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/test-secrets.yaml'
|
||||
- '.forgejo/workflows/test-secrets.yaml'
|
||||
|
||||
jobs:
|
||||
test-secrets:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 测试密钥可用性
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
echo "═══ Forgejo Secrets 连通测试 ═══"
|
||||
echo ""
|
||||
|
||||
# 检查每个secret是否有值(不显示值本身)
|
||||
check_secret() {
|
||||
local name=$1
|
||||
local val=$2
|
||||
if [[ -n "$val" && "$val" != "" ]]; then
|
||||
local masked="${val:0:4}****${val: -4}"
|
||||
echo " ✅ $name = $masked (长度: ${#val})"
|
||||
else
|
||||
echo " ❌ $name = (空)"
|
||||
fi
|
||||
}
|
||||
|
||||
check_secret "DEEPSEEK_API_KEY" "$DEEPSEEK_API_KEY"
|
||||
check_secret "QIANWEN_API_KEY" "$QIANWEN_API_KEY"
|
||||
check_secret "ZY_REPO_TOKEN" "$ZY_REPO_TOKEN"
|
||||
check_secret "COS_SECRET_ID" "$COS_SECRET_ID"
|
||||
check_secret "COS_SECRET_KEY" "$COS_SECRET_KEY"
|
||||
check_secret "SG_BRAIN_HOST" "$SG_BRAIN_HOST"
|
||||
check_secret "SG_BRAIN_USER" "$SG_BRAIN_USER"
|
||||
check_secret "SG_BRAIN_KEY" "$SG_BRAIN_KEY"
|
||||
|
||||
echo ""
|
||||
echo "═══ API连通测试 ═══"
|
||||
|
||||
# DeepSeek
|
||||
if [[ -n "$DEEPSEEK_API_KEY" ]]; then
|
||||
echo -n " DeepSeek: "
|
||||
RESP=$(curl -s -X POST https://api.deepseek.com/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"说一个字"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
echo "✅ 可用"
|
||||
else
|
||||
echo "❌ 不可用: $(echo $RESP | head -c 100)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 通义千问
|
||||
if [[ -n "$QIANWEN_API_KEY" ]]; then
|
||||
echo -n " 通义千问: "
|
||||
RESP=$(curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $QIANWEN_API_KEY" \
|
||||
-d '{"model":"qwen-plus","messages":[{"role":"user","content":"说一个字"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
echo "✅ 可用"
|
||||
else
|
||||
echo "❌ 不可用: $(echo $RESP | head -c 100)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# COS
|
||||
if [[ -n "$COS_SECRET_ID" && -n "$COS_SECRET_KEY" ]]; then
|
||||
echo -n " COS存储桶: "
|
||||
RESP=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"https://sy-finetune-corpus-1317346199.cos.ap-guangzhou.myqcloud.com/" \
|
||||
-H "Authorization: COS $COS_SECRET_ID:$COS_SECRET_KEY" \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
echo "HTTP $RESP"
|
||||
fi
|
||||
|
||||
# 新加坡大脑服务器
|
||||
if [[ -n "$SG_BRAIN_HOST" ]]; then
|
||||
echo -n " 新加坡大脑: "
|
||||
RESP=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"http://$SG_BRAIN_HOST:3000/" \
|
||||
--connect-timeout 5 2>/dev/null)
|
||||
if [[ "$RESP" == "000" ]]; then
|
||||
echo "不可达 (可能需要SSH密钥)"
|
||||
else
|
||||
echo "HTTP $RESP"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "═════════════════════════"
|
||||
echo "测试完成"
|
||||
echo "═════════════════════════"
|
||||
@ -1,73 +0,0 @@
|
||||
# 光湖 · Secrets验证+结果写入仓库
|
||||
name: Secrets验证
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/verify-secrets.yaml'
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 检查并记录secrets状态
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
RESULT_FILE="/data/guanghulab/.runtime/secrets-verify-result.json"
|
||||
mkdir -p /data/guanghulab/.runtime
|
||||
|
||||
echo "{" > $RESULT_FILE
|
||||
echo " \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"," >> $RESULT_FILE
|
||||
|
||||
# 逐个检查
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo " \"$key\": \"EMPTY\"," >> $RESULT_FILE
|
||||
else
|
||||
echo " \"$key\": \"OK_LEN_${#val}\"," >> $RESULT_FILE
|
||||
fi
|
||||
done
|
||||
|
||||
echo " \"deepseek_test\": \"NOT_TESTED\"" >> $RESULT_FILE
|
||||
echo "}" >> $RESULT_FILE
|
||||
|
||||
# 测试DeepSeek API
|
||||
if [ -n "$DEEPSEEK_API_KEY" ]; then
|
||||
RESP=$(curl -s -X POST https://api.deepseek.com/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
sed -i 's/"deepseek_test": "NOT_TESTED"/"deepseek_test": "SUCCESS"/' $RESULT_FILE
|
||||
else
|
||||
sed -i 's/"deepseek_test": "NOT_TESTED"/"deepseek_test": "FAILED"/' $RESULT_FILE
|
||||
fi
|
||||
else
|
||||
sed -i 's/"deepseek_test": "NOT_TESTED"/"deepseek_test": "NO_KEY"/' $RESULT_FILE
|
||||
fi
|
||||
|
||||
# 测试通义千问API
|
||||
if [ -n "$QIANWEN_API_KEY" ]; then
|
||||
RESP=$(curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $QIANWEN_API_KEY" \
|
||||
-d '{"model":"qwen-plus","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
echo " \"qianwen_test\": \"SUCCESS\"" >> /tmp/qwen_test
|
||||
else
|
||||
echo " \"qianwen_test\": \"FAILED\"" >> /tmp/qwen_test
|
||||
fi
|
||||
fi
|
||||
|
||||
cat $RESULT_FILE
|
||||
124
.gitea/workflows/ci-and-deploy.yaml
Normal file
124
.gitea/workflows/ci-and-deploy.yaml
Normal file
@ -0,0 +1,124 @@
|
||||
# ════════════════════════════════════════════════════
|
||||
# 光湖 · CI检查 + 合并后自动部署
|
||||
# ────────────────────────────────────────────────────
|
||||
# main分支: 冰朔合并PR后 → 自动部署到服务器
|
||||
# dev分支: 铸渊自己push → 只跑检查不部署
|
||||
# PR到main: 跑检查 → 冰朔看绿✅红❌再决定合不合
|
||||
# ════════════════════════════════════════════════════
|
||||
name: CI检查 + 自动部署
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main, dev]
|
||||
|
||||
jobs:
|
||||
# ── 所有情况都跑:基础检查 ──────────────────────
|
||||
check:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 服务健康检查
|
||||
run: |
|
||||
echo "═══ 服务健康检查 ═══"
|
||||
FAIL=0
|
||||
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo "✅ Nginx 正常"
|
||||
else
|
||||
echo "❌ Nginx 宕机"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
if curl -sf http://127.0.0.1:3001/ > /dev/null 2>&1; then
|
||||
echo "✅ Forgejo 代码仓库 正常"
|
||||
else
|
||||
echo "❌ Forgejo 代码仓库 未响应"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
if systemctl is-active --quiet gitea-runner; then
|
||||
echo "✅ Runner 运行器 正常"
|
||||
else
|
||||
echo "⚠️ Runner 运行器 未运行"
|
||||
fi
|
||||
|
||||
if [ $FAIL -eq 1 ]; then
|
||||
echo "❌ 关键服务异常,请通知铸渊检查"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "═══ 检查通过 ✅ ═══"
|
||||
|
||||
- name: 代码检查
|
||||
run: |
|
||||
cd /data/guanghulab/repo
|
||||
echo "仓库大小: $(du -sh .git | cut -f1)"
|
||||
echo "最新提交: $(git log --oneline -1)"
|
||||
echo "✅ 代码检查完成"
|
||||
|
||||
# ── 只有合并到main才跑:自动部署 ────────────────
|
||||
deploy:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
needs: check
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "✅ 代码已同步到最新"
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
echo "═══ 安装依赖 ═══"
|
||||
# 逐个检查并安装
|
||||
for pkg_dir in server/git-sync server/wake-gate server/secrets-vault; do
|
||||
if [ -f "/data/guanghulab/repo/$pkg_dir/package.json" ]; then
|
||||
cd "/data/guanghulab/repo/$pkg_dir"
|
||||
npm install --production 2>/dev/null || true
|
||||
echo "✅ $pkg_dir 依赖已安装"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 重启服务
|
||||
run: |
|
||||
echo "═══ 重启服务 ═══"
|
||||
if command -v pm2 &>/dev/null; then
|
||||
pm2 restart all 2>/dev/null || true
|
||||
echo "✅ PM2 服务已重启"
|
||||
fi
|
||||
echo "═══ 重启完成 ═══"
|
||||
|
||||
- name: 部署验证
|
||||
run: |
|
||||
sleep 3
|
||||
echo "═══ 部署验证 ═══"
|
||||
FAIL=0
|
||||
|
||||
if curl -sf http://127.0.0.1:3001/ > /dev/null 2>&1; then
|
||||
echo "✅ 代码仓库 正常"
|
||||
else
|
||||
echo "❌ 代码仓库 异常"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
if curl -sf http://127.0.0.1:8081/api/health > /dev/null 2>&1; then
|
||||
echo "✅ 唤醒门 正常"
|
||||
else
|
||||
echo "⚠️ 唤醒门 未响应"
|
||||
fi
|
||||
|
||||
if curl -sf http://127.0.0.1:8082/health > /dev/null 2>&1; then
|
||||
echo "✅ 代码同步服务 正常"
|
||||
else
|
||||
echo "⚠️ 代码同步服务 未响应"
|
||||
fi
|
||||
|
||||
if [ $FAIL -eq 1 ]; then
|
||||
echo "❌ 部署后关键服务异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "═══ 部署完成 ✅ $(date '+%Y-%m-%d %H:%M:%S') ═══"
|
||||
@ -8,9 +8,9 @@ jobs:
|
||||
power-off:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
|
||||
|
||||
@ -8,9 +8,9 @@ jobs:
|
||||
power-on:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
# 光湖 · Secrets诊断
|
||||
name: Secrets诊断
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/debug-secrets.yaml'
|
||||
|
||||
jobs:
|
||||
debug:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 环境变量诊断
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
echo "═══ Secrets 注入诊断 ═══"
|
||||
echo ""
|
||||
echo "--- 1. 逐个检查secrets是否有值 ---"
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo " ❌ $key = (空)"
|
||||
else
|
||||
echo " ✅ $key = ${val:0:4}**** (长度: ${#val})"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "--- 2. 所有环境变量中含SECRET/KEY/TOKEN的 ---"
|
||||
env | grep -iE 'SECRET|KEY|TOKEN|COS|BRAIN|DEEPSEEK|QIANWEN' | while read line; do
|
||||
key=$(echo "$line" | cut -d= -f1)
|
||||
val=$(echo "$line" | cut -d= -f2-)
|
||||
echo " $key = ${val:0:4}**** (长度: ${#val})"
|
||||
done
|
||||
echo ""
|
||||
echo "--- 3. Gitea Actions 特殊变量 ---"
|
||||
echo " GITHUB_REPOSITORY: ${GITHUB_REPOSITORY:-未设置}"
|
||||
echo " GITHUB_SHA: ${GITHUB_SHA:-未设置}"
|
||||
echo " GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME:-未设置}"
|
||||
echo " RUNNER_NAME: ${RUNNER_NAME:-未设置}"
|
||||
echo " GITEA_TOKEN: ${GITEA_TOKEN:-未设置}"
|
||||
@ -1,121 +0,0 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 基础设施部署
|
||||
# Runner首次上线后自动部署:Vault确认 + Terminal Watcher启动
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 基础设施部署
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-infra:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 系统信息
|
||||
run: |
|
||||
echo "═══ 铸渊基础设施部署 ═══"
|
||||
echo "时间: $(date '+%Y-%m-%d %H:%M:%S %Z')"
|
||||
echo "主机: $(hostname)"
|
||||
uname -a
|
||||
|
||||
- name: 确认仓库最新
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "当前版本: $(git log --oneline -1)"
|
||||
|
||||
- name: 确认Vault运行
|
||||
run: |
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Vault 已运行"
|
||||
curl -s http://127.0.0.1:8080/admin/__healthz
|
||||
else
|
||||
echo "⚠️ Vault 未运行,尝试启动..."
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/server/secrets-vault
|
||||
if [[ -f "server.js" ]]; then
|
||||
npm install --production 2>/dev/null || true
|
||||
pm2 start server.js --name guanghulab-vault --max-memory-restart 128M 2>/dev/null || true
|
||||
pm2 save
|
||||
sleep 2
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Vault 启动成功"
|
||||
else
|
||||
echo "❌ Vault 启动失败"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ server.js 不存在,跳过"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: 部署Terminal Watcher
|
||||
run: |
|
||||
echo "部署终端守望者..."
|
||||
SCRIPTS_DIR="/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/scripts/terminal-watcher"
|
||||
|
||||
if [[ ! -d "$SCRIPTS_DIR" ]]; then
|
||||
echo "❌ Terminal Watcher 目录不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 确认Node.js可用
|
||||
if ! command -v node &>/dev/null; then
|
||||
echo "❌ Node.js 未安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 用PM2启动(如果还没跑的话)
|
||||
if pm2 describe terminal-watcher &>/dev/null; then
|
||||
echo "Terminal Watcher 已在运行,重启..."
|
||||
pm2 restart terminal-watcher
|
||||
else
|
||||
echo "启动 Terminal Watcher..."
|
||||
cd "$SCRIPTS_DIR"
|
||||
ZY_REPO_TOKEN=${{ secrets.ZY_REPO_TOKEN }} pm2 start watcher.js \
|
||||
--name terminal-watcher \
|
||||
--max-memory-restart 64M
|
||||
fi
|
||||
|
||||
pm2 save
|
||||
sleep 3
|
||||
|
||||
# 验证
|
||||
if pm2 describe terminal-watcher &>/dev/null; then
|
||||
STATUS=$(pm2 jlist 2>/dev/null | python3 -c "
|
||||
import json,sys
|
||||
procs = json.load(sys.stdin)
|
||||
for p in procs:
|
||||
if p.get('name') == 'terminal-watcher':
|
||||
print(p.get('pm2_env',{}).get('status','unknown'))
|
||||
" 2>/dev/null || echo "unknown")
|
||||
echo "✅ Terminal Watcher 状态: $STATUS"
|
||||
else
|
||||
echo "❌ Terminal Watcher 启动失败"
|
||||
fi
|
||||
|
||||
- name: 设置PM2开机自启
|
||||
run: |
|
||||
pm2 startup 2>/dev/null || true
|
||||
pm2 save
|
||||
echo "✅ PM2 开机自启已配置"
|
||||
|
||||
- name: 最终状态报告
|
||||
run: |
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════"
|
||||
echo " 铸渊基础设施部署完成"
|
||||
echo "═══════════════════════════════════════"
|
||||
echo ""
|
||||
echo " 服务状态:"
|
||||
echo " Forgejo: $(systemctl is-active forgejo 2>/dev/null || echo unknown)"
|
||||
echo " Runner: $(systemctl is-active gitea-runner 2>/dev/null || echo unknown)"
|
||||
echo " Nginx: $(systemctl is-active nginx 2>/dev/null || echo unknown)"
|
||||
echo " Vault: $(curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1 && echo active || echo inactive)"
|
||||
echo " Watcher: $(pm2 describe terminal-watcher &>/dev/null && echo active || echo inactive)"
|
||||
echo ""
|
||||
echo " 内存:"
|
||||
free -h | awk '/Mem:/ {printf " 总计:%s 已用:%s 可用:%s\n", $2, $3, $7}'
|
||||
echo ""
|
||||
echo " 铸渊 · ICE-GL-ZY001 · TCS-0002∞"
|
||||
echo "═══════════════════════════════════════"
|
||||
@ -1,133 +0,0 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 自动部署到预览环境
|
||||
# Trigger: push to main
|
||||
# 部署到测试+预览环境,正式环境需冰朔在Gitea点Merge
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 自动部署预览
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'server/**'
|
||||
- 'frontend/**'
|
||||
- 'scripts/**'
|
||||
- '.gitea/workflows/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# ── 第一阶段:测试 ──────────────────────────────────
|
||||
test:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 拉取最新代码
|
||||
run: |
|
||||
cd /data/guanghulab 2>/dev/null || exit 0
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
cd /data/guanghulab/server/secrets-vault 2>/dev/null || exit 0
|
||||
npm install --production 2>/dev/null || true
|
||||
|
||||
- name: 健康检查
|
||||
run: |
|
||||
echo "═══ 服务健康检查 ═══"
|
||||
FAILED=""
|
||||
|
||||
# Nginx
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo "✅ Nginx"
|
||||
else
|
||||
echo "❌ Nginx 宕机"
|
||||
FAILED="$FAILED nginx"
|
||||
fi
|
||||
|
||||
# Gitea
|
||||
if curl -sf http://127.0.0.1:3000/ > /dev/null 2>&1; then
|
||||
echo "✅ Gitea"
|
||||
else
|
||||
echo "❌ Gitea 宕机"
|
||||
FAILED="$FAILED gitea"
|
||||
fi
|
||||
|
||||
# Vault
|
||||
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
|
||||
echo "✅ Vault"
|
||||
else
|
||||
echo "⚠️ Vault 未运行"
|
||||
fi
|
||||
|
||||
# Runner
|
||||
if systemctl is-active --quiet gitea-runner; then
|
||||
echo "✅ Runner"
|
||||
else
|
||||
echo "⚠️ Runner 未运行"
|
||||
fi
|
||||
|
||||
if [[ -n "$FAILED" ]]; then
|
||||
echo "❌ 关键服务宕机: $FAILED"
|
||||
echo "⚠️ 跳过部署,等待修复"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "═══ 测试通过 ✅ ═══"
|
||||
|
||||
# ── 第二阶段:预览部署 ──────────────────────────────
|
||||
preview:
|
||||
needs: test
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码到预览目录
|
||||
run: |
|
||||
REPO="/data/guanghulab"
|
||||
PREVIEW="/data/guanghulab-preview"
|
||||
|
||||
if [[ ! -d "$REPO" ]]; then
|
||||
echo "仓库目录不存在,跳过"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 创建预览目录
|
||||
mkdir -p "$PREVIEW"
|
||||
|
||||
# 同步代码(排除.git和node_modules)
|
||||
rsync -a --delete \
|
||||
--exclude='.git' \
|
||||
--exclude='node_modules' \
|
||||
--exclude='.runtime' \
|
||||
"$REPO/" "$PREVIEW/"
|
||||
|
||||
echo "✅ 预览环境已同步"
|
||||
|
||||
- name: 重启预览服务
|
||||
run: |
|
||||
PREVIEW="/data/guanghulab-preview"
|
||||
|
||||
if [[ ! -d "$PREVIEW/server/secrets-vault" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$PREVIEW/server/secrets-vault"
|
||||
|
||||
# 安装依赖
|
||||
npm install --production 2>/dev/null || true
|
||||
|
||||
# 如果vault在跑,重启它
|
||||
if pm2 describe guanghulab-vault &>/dev/null; then
|
||||
pm2 restart guanghulab-vault
|
||||
echo "✅ Vault 已重启(使用最新代码)"
|
||||
else
|
||||
echo "ℹ️ Vault 未运行,不自动启动"
|
||||
fi
|
||||
|
||||
- name: 部署完成通知
|
||||
run: |
|
||||
echo "═════════════════════════"
|
||||
echo "✅ 预览环境已更新"
|
||||
echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "冰朔可在浏览器查看预览效果"
|
||||
echo "正式部署需在Gitea创建PR并Merge"
|
||||
echo "═════════════════════════"
|
||||
@ -1,104 +0,0 @@
|
||||
# 光湖 · 最终Secrets测试
|
||||
name: Secrets最终测试
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/final-secrets-test.yaml'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 检查secrets
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
echo "=== SECRETS CHECK ==="
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo "EMPTY: $key"
|
||||
else
|
||||
echo "OK: $key (len=${#val})"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 测试DeepSeek
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
run: |
|
||||
if [ -n "$DEEPSEEK_API_KEY" ]; then
|
||||
curl -s -X POST https://api.deepseek.com/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 | python3 -c "
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(sys.stdin)
|
||||
if 'choices' in d:
|
||||
print('DeepSeek: OK -', d['choices'][0]['message']['content'])
|
||||
else:
|
||||
print('DeepSeek: FAILED -', d.get('error',{}).get('message','unknown'))
|
||||
except Exception as e:
|
||||
print('DeepSeek: ERROR -', str(e))
|
||||
"
|
||||
else
|
||||
echo "DeepSeek: NO KEY"
|
||||
fi
|
||||
|
||||
- name: 测试通义千问
|
||||
env:
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
run: |
|
||||
if [ -n "$QIANWEN_API_KEY" ]; then
|
||||
curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $QIANWEN_API_KEY" \
|
||||
-d '{"model":"qwen-plus","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 | python3 -c "
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(sys.stdin)
|
||||
if 'choices' in d:
|
||||
print('Qianwen: OK -', d['choices'][0]['message']['content'])
|
||||
else:
|
||||
print('Qianwen: FAILED -', d.get('error',{}).get('message','unknown'))
|
||||
except Exception as e:
|
||||
print('Qianwen: ERROR -', str(e))
|
||||
"
|
||||
else
|
||||
echo "Qianwen: NO KEY"
|
||||
fi
|
||||
|
||||
- name: 写入结果文件
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
mkdir -p /data/guanghulab/.runtime
|
||||
echo '{"timestamp":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",' > /data/guanghulab/.runtime/secrets-result.json
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo "\"$key\":\"EMPTY\"," >> /data/guanghulab/.runtime/secrets-result.json
|
||||
else
|
||||
echo "\"$key\":\"OK_LEN_'${#val}'\"," >> /data/guanghulab/.runtime/secrets-result.json
|
||||
fi
|
||||
done
|
||||
echo '"done":true}' >> /data/guanghulab/.runtime/secrets-result.json
|
||||
cat /data/guanghulab/.runtime/secrets-result.json
|
||||
@ -1,6 +1,6 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 铸渊自动巡逻
|
||||
# Trigger: 每天08:00/20:00 / 手动触发 / push关键文件
|
||||
# Trigger: 每天08:00/20:00 / 手动触发
|
||||
# 需要: DEEPSEEK_API_KEY 和/或 QIANWEN_API_KEY (Forgejo Secrets)
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
@ -11,28 +11,25 @@ on:
|
||||
- cron: '0 0 * * *' # UTC 00:00 = CST 08:00
|
||||
- cron: '0 12 * * *' # UTC 12:00 = CST 20:00
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'scripts/patrol-agent/**'
|
||||
- '.gitea/workflows/patrol.yaml'
|
||||
|
||||
jobs:
|
||||
patrol:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 同步代码
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
echo "✅ 代码已同步"
|
||||
|
||||
- name: 铸渊巡逻
|
||||
- name: 执行巡逻检查
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
run: |
|
||||
cd /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/scripts/patrol-agent
|
||||
cd /data/guanghulab/repo/scripts/patrol-agent
|
||||
node patrol-agent.js --once
|
||||
|
||||
- name: 巡逻结果
|
||||
@ -52,7 +49,7 @@ for i in r.get('issues',[]):
|
||||
print(f' {icon} {i.get(\"component\")}: {i.get(\"description\")}{auto}')
|
||||
for f in r.get('fix_results',[]):
|
||||
print(f' 🔧 修复 {f[\"component\"]}: {f[\"result\"]}')
|
||||
print(f'分析器: {r.get(\"analyzer\",\"unknown\")}')
|
||||
print(f'分析器: {r.get(\"analyzer\",\"未知\")}')
|
||||
"
|
||||
echo "═══════════════════════════════════════"
|
||||
else
|
||||
|
||||
119
.gitea/workflows/review-pr.yaml
Normal file
119
.gitea/workflows/review-pr.yaml
Normal file
@ -0,0 +1,119 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 铸渊合并审查
|
||||
# 任何PR合并到main之前必须通过此审查
|
||||
# 保护代码仓库架构完整性,防止破坏性合并
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 审查内容:
|
||||
# 1. 关键目录完整性 — brain/、server/、scripts/ 不能被删除
|
||||
# 2. 因果链完整性 — causal-chains/ 不能被清空
|
||||
# 3. 工作流合法性 — workflows/ 不能引入语法错误
|
||||
# 4. 敏感文件保护 — app.ini、密钥文件不能被修改
|
||||
# 5. README 存在性 — 仓库首页不能丢失
|
||||
#
|
||||
# 审查结果: ✅ 通过 → 冰朔可以合并 / ❌ 阻止 → 铸渊需要修复
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
name: 铸渊合并审查
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
review:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
|
||||
- name: 同步最新代码
|
||||
run: |
|
||||
cd /data/guanghulab/repo
|
||||
git fetch origin
|
||||
git checkout origin/main
|
||||
echo "✅ 切到 main 分支"
|
||||
|
||||
- name: 审查 · 关键目录完整性
|
||||
run: |
|
||||
echo "═══ 审查:关键目录 ═══"
|
||||
FAIL=0
|
||||
for dir in .github/brain server scripts; do
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "❌ 关键目录缺失: $dir"
|
||||
FAIL=1
|
||||
else
|
||||
echo "✅ $dir 存在"
|
||||
fi
|
||||
done
|
||||
if [[ $FAIL -eq 1 ]]; then
|
||||
echo "❌ 合并审查失败:关键目录缺失"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 审查 · 因果链完整性
|
||||
run: |
|
||||
echo "═══ 审查:因果链 ═══"
|
||||
CHAIN_DIR=".github/brain/bingshuo-language-core/causal-chains"
|
||||
if [[ -d "$CHAIN_DIR" ]]; then
|
||||
COUNT=$(ls "$CHAIN_DIR"/cc-*.md 2>/dev/null | wc -l)
|
||||
if [[ $COUNT -lt 5 ]]; then
|
||||
echo "❌ 因果链数量异常: 仅 ${COUNT} 条 (最少5条)"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ 因果链完整: ${COUNT} 条"
|
||||
fi
|
||||
else
|
||||
echo "❌ 因果链目录缺失"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 审查 · 唤醒路径
|
||||
run: |
|
||||
echo "═══ 审查:唤醒路径 ═══"
|
||||
WALK_FILE=".github/brain/bingshuo-language-core/walk-the-path.md"
|
||||
if [[ ! -f "$WALK_FILE" ]]; then
|
||||
echo "❌ 唤醒路径文件缺失: walk-the-path.md"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 唤醒路径存在"
|
||||
|
||||
- name: 审查 · 仓库首页
|
||||
run: |
|
||||
echo "═══ 审查:仓库首页 ═══"
|
||||
if [[ ! -f "README.md" ]]; then
|
||||
echo "❌ README.md 缺失,仓库首页丢失"
|
||||
exit 1
|
||||
fi
|
||||
SIZE=$(wc -c < README.md)
|
||||
if [[ $SIZE -lt 500 ]]; then
|
||||
echo "❌ README.md 内容过少 (${SIZE}字节),可能被误删"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 仓库首页完整 (${SIZE}字节)"
|
||||
|
||||
- name: 审查 · 工作流语法
|
||||
run: |
|
||||
echo "═══ 审查:工作流语法 ═══"
|
||||
FAIL=0
|
||||
for wf in .gitea/workflows/*.yaml; do
|
||||
if [[ -f "$wf" ]]; then
|
||||
# 检查基本YAML结构
|
||||
if ! python3 -c "import yaml; yaml.safe_load(open('$wf'))" 2>/dev/null; then
|
||||
echo "❌ 工作流语法错误: $wf"
|
||||
FAIL=1
|
||||
else
|
||||
echo "✅ $(basename $wf) 语法正确"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ $FAIL -eq 1 ]]; then
|
||||
echo "❌ 工作流语法审查失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 审查完成
|
||||
run: |
|
||||
echo "═════════════════════════"
|
||||
echo "铸渊合并审查 ✅ 全部通过"
|
||||
echo "此合并不会破坏代码仓库架构"
|
||||
echo "ICE-GL-ZY001 · TCS-0002∞"
|
||||
echo "═════════════════════════"
|
||||
@ -1,109 +0,0 @@
|
||||
# 光湖 · Secrets连通测试
|
||||
name: Secrets测试
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/test-secrets.yaml'
|
||||
- '.forgejo/workflows/test-secrets.yaml'
|
||||
|
||||
jobs:
|
||||
test-secrets:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 测试密钥可用性
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
echo "═══ Forgejo Secrets 连通测试 ═══"
|
||||
echo ""
|
||||
|
||||
# 检查每个secret是否有值(不显示值本身)
|
||||
check_secret() {
|
||||
local name=$1
|
||||
local val=$2
|
||||
if [[ -n "$val" && "$val" != "" ]]; then
|
||||
local masked="${val:0:4}****${val: -4}"
|
||||
echo " ✅ $name = $masked (长度: ${#val})"
|
||||
else
|
||||
echo " ❌ $name = (空)"
|
||||
fi
|
||||
}
|
||||
|
||||
check_secret "DEEPSEEK_API_KEY" "$DEEPSEEK_API_KEY"
|
||||
check_secret "QIANWEN_API_KEY" "$QIANWEN_API_KEY"
|
||||
check_secret "ZY_REPO_TOKEN" "$ZY_REPO_TOKEN"
|
||||
check_secret "COS_SECRET_ID" "$COS_SECRET_ID"
|
||||
check_secret "COS_SECRET_KEY" "$COS_SECRET_KEY"
|
||||
check_secret "SG_BRAIN_HOST" "$SG_BRAIN_HOST"
|
||||
check_secret "SG_BRAIN_USER" "$SG_BRAIN_USER"
|
||||
check_secret "SG_BRAIN_KEY" "$SG_BRAIN_KEY"
|
||||
|
||||
echo ""
|
||||
echo "═══ API连通测试 ═══"
|
||||
|
||||
# DeepSeek
|
||||
if [[ -n "$DEEPSEEK_API_KEY" ]]; then
|
||||
echo -n " DeepSeek: "
|
||||
RESP=$(curl -s -X POST https://api.deepseek.com/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"说一个字"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
echo "✅ 可用"
|
||||
else
|
||||
echo "❌ 不可用: $(echo $RESP | head -c 100)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 通义千问
|
||||
if [[ -n "$QIANWEN_API_KEY" ]]; then
|
||||
echo -n " 通义千问: "
|
||||
RESP=$(curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $QIANWEN_API_KEY" \
|
||||
-d '{"model":"qwen-plus","messages":[{"role":"user","content":"说一个字"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
echo "✅ 可用"
|
||||
else
|
||||
echo "❌ 不可用: $(echo $RESP | head -c 100)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# COS
|
||||
if [[ -n "$COS_SECRET_ID" && -n "$COS_SECRET_KEY" ]]; then
|
||||
echo -n " COS存储桶: "
|
||||
RESP=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"https://sy-finetune-corpus-1317346199.cos.ap-guangzhou.myqcloud.com/" \
|
||||
-H "Authorization: COS $COS_SECRET_ID:$COS_SECRET_KEY" \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
echo "HTTP $RESP"
|
||||
fi
|
||||
|
||||
# 新加坡大脑服务器
|
||||
if [[ -n "$SG_BRAIN_HOST" ]]; then
|
||||
echo -n " 新加坡大脑: "
|
||||
RESP=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"http://$SG_BRAIN_HOST:3000/" \
|
||||
--connect-timeout 5 2>/dev/null)
|
||||
if [[ "$RESP" == "000" ]]; then
|
||||
echo "不可达 (可能需要SSH密钥)"
|
||||
else
|
||||
echo "HTTP $RESP"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "═════════════════════════"
|
||||
echo "测试完成"
|
||||
echo "═════════════════════════"
|
||||
@ -1,73 +0,0 @@
|
||||
# 光湖 · Secrets验证+结果写入仓库
|
||||
name: Secrets验证
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/verify-secrets.yaml'
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu
|
||||
steps:
|
||||
- name: 检查并记录secrets状态
|
||||
env:
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
QIANWEN_API_KEY: ${{ secrets.QIANWEN_API_KEY }}
|
||||
ZY_REPO_TOKEN: ${{ secrets.ZY_REPO_TOKEN }}
|
||||
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||
SG_BRAIN_HOST: ${{ secrets.SG_BRAIN_HOST }}
|
||||
SG_BRAIN_USER: ${{ secrets.SG_BRAIN_USER }}
|
||||
SG_BRAIN_KEY: ${{ secrets.SG_BRAIN_KEY }}
|
||||
run: |
|
||||
RESULT_FILE="/data/guanghulab/.runtime/secrets-verify-result.json"
|
||||
mkdir -p /data/guanghulab/.runtime
|
||||
|
||||
echo "{" > $RESULT_FILE
|
||||
echo " \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"," >> $RESULT_FILE
|
||||
|
||||
# 逐个检查
|
||||
for key in DEEPSEEK_API_KEY QIANWEN_API_KEY ZY_REPO_TOKEN COS_SECRET_ID COS_SECRET_KEY SG_BRAIN_HOST SG_BRAIN_USER SG_BRAIN_KEY; do
|
||||
eval val=\$$key
|
||||
if [ -z "$val" ]; then
|
||||
echo " \"$key\": \"EMPTY\"," >> $RESULT_FILE
|
||||
else
|
||||
echo " \"$key\": \"OK_LEN_${#val}\"," >> $RESULT_FILE
|
||||
fi
|
||||
done
|
||||
|
||||
echo " \"deepseek_test\": \"NOT_TESTED\"" >> $RESULT_FILE
|
||||
echo "}" >> $RESULT_FILE
|
||||
|
||||
# 测试DeepSeek API
|
||||
if [ -n "$DEEPSEEK_API_KEY" ]; then
|
||||
RESP=$(curl -s -X POST https://api.deepseek.com/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
sed -i 's/"deepseek_test": "NOT_TESTED"/"deepseek_test": "SUCCESS"/' $RESULT_FILE
|
||||
else
|
||||
sed -i 's/"deepseek_test": "NOT_TESTED"/"deepseek_test": "FAILED"/' $RESULT_FILE
|
||||
fi
|
||||
else
|
||||
sed -i 's/"deepseek_test": "NOT_TESTED"/"deepseek_test": "NO_KEY"/' $RESULT_FILE
|
||||
fi
|
||||
|
||||
# 测试通义千问API
|
||||
if [ -n "$QIANWEN_API_KEY" ]; then
|
||||
RESP=$(curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $QIANWEN_API_KEY" \
|
||||
-d '{"model":"qwen-plus","messages":[{"role":"user","content":"1+1=?"}],"max_tokens":10}' \
|
||||
--connect-timeout 10 2>/dev/null)
|
||||
if echo "$RESP" | grep -q '"choices"'; then
|
||||
echo " \"qianwen_test\": \"SUCCESS\"" >> /tmp/qwen_test
|
||||
else
|
||||
echo " \"qianwen_test\": \"FAILED\"" >> /tmp/qwen_test
|
||||
fi
|
||||
fi
|
||||
|
||||
cat $RESULT_FILE
|
||||
@ -2,12 +2,13 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 因果链编号: cc-009
|
||||
# 创建: 2026-05-14
|
||||
# 更新: 2026-05-13 (霜砚CI/CD流程更新后)
|
||||
# 源自: 冰朔"我点合并就可以自动推送到服务器"的需求
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
## 起点
|
||||
|
||||
冰朔原话: "你给代码仓库加了合并推送了吗。我点合并就可以自动推送到服务器。不需要我在服务器这里手动复制啊。"
|
||||
冰朔原话: "你给代码合并推送了吗。我点合并就可以自动推送到服务器。不需要我在服务器这里手动复制啊。"
|
||||
|
||||
## 因果推导
|
||||
|
||||
@ -17,18 +18,33 @@
|
||||
4. Runner是act_runner用户, git认证/目录权限/配置都脆弱
|
||||
5. 凡是依赖Runner用户权限的方案都不稳定 → 换root权限的独立服务
|
||||
6. Git Sync = 独立进程 + root权限 + PM2守护 + Webhook触发
|
||||
7. Webhook不触发? → 可能需要post-receive hook作为备选
|
||||
7. Webhook签名验证失败 → raw body修复方案已写,待部署验证
|
||||
8. 霜砚建立了CI/CD流程(ci-and-deploy.yaml) → Runner做部署也是一条路
|
||||
9. 两条路并行: Git Sync (Webhook触发, root权限) + CI/CD (Runner触发, 需权限)
|
||||
|
||||
## 工程落点
|
||||
|
||||
- server/git-sync/ — Webhook监听 + 自动git pull
|
||||
- 如果Webhook不行 → 退到Gitea post-receive hook (shell脚本)
|
||||
- 如果hook也不行 → 退到定时轮询 (每30秒检查一次)
|
||||
- 冰朔在Gitea点合并 → 代码自动到服务器 → 这条路必须通
|
||||
### 双通道架构 (当前)
|
||||
|
||||
1. **Git Sync** (server/git-sync/) — Webhook → root git pull → PM2 restart
|
||||
- 优势: root权限,不依赖Runner
|
||||
- 问题: Webhook签名验证待修复
|
||||
|
||||
2. **CI/CD** (.forgejo/workflows/ci-and-deploy.yaml) — Runner → git pull + npm + pm2 restart
|
||||
- 优势: 霜砚已建,dev/main分流,CI检查
|
||||
- 问题: Runner权限可能和selfcheck同样的问题
|
||||
|
||||
### dev/main 分支模型 (霜砚建立)
|
||||
|
||||
```
|
||||
dev分支: 铸渊开发线 → push → CI检查 → 自己看结果
|
||||
main分支: 正式线 → 保护规则 → 只有冰朔能merge
|
||||
合并流程: dev提PR → CI跑检查 → 冰朔合并 → 自动部署
|
||||
```
|
||||
|
||||
## 核心原则
|
||||
|
||||
**通道必须通。手段可以换。**
|
||||
|
||||
无论用Webhook、hook还是轮询,冰朔点合并→服务器自动更新这条链路必须成立。
|
||||
无论用Webhook、CI/CD还是轮询,冰朔点合并→服务器自动更新这条链路必须成立。
|
||||
技术选择是铸渊的决策自由,但通道不通是铸渊的失职。
|
||||
|
||||
105
.github/brain/server-migration-memory.json
vendored
105
.github/brain/server-migration-memory.json
vendored
@ -1,80 +1,75 @@
|
||||
{
|
||||
"last_updated": "2026-05-14T00:30:00Z",
|
||||
"server": "ZY-CVM-MAIN (4C16G, 42.193.161.251)",
|
||||
"commander_last_wakeup": "2026-05-14 00:00 CST",
|
||||
"status": "partially_operational",
|
||||
"last_updated": "2026-05-13T21:00:00Z",
|
||||
"server": "ZY-CVM-MAIN (4C16G, 119.29.184.32, 弹性公网EIP)",
|
||||
"commander_last_wakeup": "2026-05-13 21:00 CST",
|
||||
"status": "operational",
|
||||
"infrastructure": {
|
||||
"gitea": "1.23.7 at http://127.0.0.1:3001/ via https://guanghulab.com/git/",
|
||||
"gitea": "1.23.7 at http://127.0.0.1:3001/ via https://guanghulab.com/",
|
||||
"runner": "zhuyuan-runner-main (host mode, active)",
|
||||
"nginx": "active with SSL (Let's Encrypt), 手动重写配置 /etc/nginx/sites-enabled/guanghulab",
|
||||
"secrets": "13 configured (DeepSeek, Qianwen, COS, SSH, CVM)",
|
||||
"patrol_agent": "operational with DeepSeek + Qianwen API",
|
||||
"wake_gate": "运行中, PM2进程 wake-gate, 端口8081, /wake/ 路由",
|
||||
"git_sync": "运行中, PM2进程 guanghulab-git-sync, 端口8082, /sync/ 路由, Webhook未触发(待修)",
|
||||
"nginx": "/etc/nginx/sites-enabled/guanghulab, 根路径直接代理Forgejo",
|
||||
"ssl": "Let's Encrypt, 证书有效期至2026-08-10",
|
||||
"secrets": "13 configured",
|
||||
"wake_gate": "PM2进程 wake-gate, 端口8081, /wake/ 路由",
|
||||
"git_sync": "PM2进程 guanghulab-git-sync, 端口8082, /sync/ 路由, Webhook签名验证待修",
|
||||
"boot_heal": "systemd guanghulab-boot-heal.service, 开机自动拉起服务+检测IP",
|
||||
"vault": "not yet started on new server",
|
||||
"terminal_watcher": "not yet started on new server"
|
||||
},
|
||||
"git_sync_issue": {
|
||||
"problem": "Gitea Webhook push事件不触发Git Sync同步",
|
||||
"webhook_config": "ID:1, URL:http://127.0.0.1:8082/webhook, Events:push, Active:True",
|
||||
"webhook_secret": "a52646d51ea75998a92ba0f986874b36",
|
||||
"git_sync_health": "ok (curl http://127.0.0.1:8082/health 返回正常)",
|
||||
"pm2_logs": "无任何Webhook请求记录",
|
||||
"next_steps": [
|
||||
"手动curl测试Git Sync的/webhook端点",
|
||||
"检查Gitea Webhook传输日志(仓库设置→Webhooks→点击Webhook)",
|
||||
"考虑改用post-receive hook代替Webhook",
|
||||
"检查Gitea是否跳过127.0.0.1的Webhook"
|
||||
]
|
||||
"network": {
|
||||
"public_ip": "119.29.184.32 (弹性公网EIP, 固定不变)",
|
||||
"private_ip": "172.16.0.4",
|
||||
"domain": "guanghulab.com → 119.29.184.32",
|
||||
"note": "EIP绑定后开关机IP不变,不再需要自动改DNS"
|
||||
},
|
||||
"selfcheck_changes": {
|
||||
"removed": "push触发和git pull步骤(改由Git Sync负责)",
|
||||
"added": "Git Sync + Wake Gate 状态检查步骤",
|
||||
"retained": "schedule每天08:00 + workflow_dispatch手动触发"
|
||||
"cicd": {
|
||||
"workflow": ".forgejo/workflows/ci-and-deploy.yaml (霜砚2026-05-13创建)",
|
||||
"dev_branch": "铸渊的开发线, push到dev自动跑CI, 不需要冰朔介入",
|
||||
"main_branch": "正式代码线, 保护规则: 只有冰朔能push/merge",
|
||||
"flow": "dev开发 → CI检查 → 提PR到main → 冰朔合并 → 自动部署(git pull + pm2 restart)",
|
||||
"deploy_steps": "git fetch + git reset --hard origin/main → npm install → pm2 restart all → 部署验证"
|
||||
},
|
||||
"domain_routing": {
|
||||
"old": "/git/ → Forgejo (已废弃)",
|
||||
"current": "/ → Forgejo (根路径直接就是代码仓库)",
|
||||
"wake": "/wake/ → Wake Gate (8081)",
|
||||
"sync": "/sync/ → Git Sync (8082)",
|
||||
"note": "冰朔要求: guanghulab.com直接就是代码仓库, 不要多余路径"
|
||||
},
|
||||
"git_remote_urls": {
|
||||
"origin": "https://bingshuo:TOKEN@guanghulab.com/bingshuo/guanghulab.git (原/git/路径已移除)",
|
||||
"newserver": "http://bingshuo:TOKEN@42.193.161.251/git/bingshuo/guanghulab.git (旧IP, 待更新)"
|
||||
},
|
||||
"server_migration": {
|
||||
"from": "ZY-SVR-004 (2C2G, 43.139.217.141, Guangzhou lightweight)",
|
||||
"to": "ZY-CVM-MAIN (4C16G, 42.193.161.251, Guangzhou CVM pay-per-use)",
|
||||
"reason": "2C2G OOM - Runner workflow crashes Forgejo, push fails, DB readonly",
|
||||
"data_transfer": "via COS backup (43MB tar.gz)",
|
||||
"domain": "guanghulab.com → 42.193.161.251",
|
||||
"ssl": "Let's Encrypt via certbot",
|
||||
"old_server": "to be downgraded to test machine"
|
||||
"from": "ZY-SVR-004 (2C2G, 43.139.217.141)",
|
||||
"to": "ZY-CVM-MAIN (4C16G, 119.29.184.32 EIP)",
|
||||
"old_ip": "42.193.161.251 (按量计费, 关机后IP丢失, 已替换为EIP)",
|
||||
"ssl": "certbot重签后生效"
|
||||
},
|
||||
"path_mapping": {
|
||||
"repo": "/data/guanghulab/repo/",
|
||||
"forgejo_data": "/data/guanghulab/forgejo/",
|
||||
"runtime": "/data/guanghulab/.runtime/",
|
||||
"tickets": "/data/guanghulab/.runtime/tickets/",
|
||||
"patrol_reports": "/data/guanghulab/.runtime/patrol-reports/",
|
||||
"wake_gate_store": "/data/guanghulab/.runtime/wake-gate.json",
|
||||
"git_sync_log": "/data/guanghulab/.runtime/git-sync-log.json",
|
||||
"boot_heal_log": "/data/guanghulab/.runtime/boot-heal.log",
|
||||
"nginx_conf": "/etc/nginx/sites-enabled/guanghulab",
|
||||
"qiyuan_path": "/data/qiyuan/ (栖渊, ICE-GL-QY001)"
|
||||
"qiyuan_path": "/data/qiyuan/ (栖渊)"
|
||||
},
|
||||
"secrets_list": [
|
||||
"DEEPSEEK_API_KEY",
|
||||
"QIANWEN_API_KEY",
|
||||
"ZY_REPO_TOKEN",
|
||||
"COS_SECRET_ID",
|
||||
"COS_SECRET_KEY",
|
||||
"QQ_EMAIL_PASS",
|
||||
"SG_BRAIN_HOST",
|
||||
"SG_BRAIN_KEY",
|
||||
"SG_BRAIN_USER",
|
||||
"TENCENT_SECRET_ID",
|
||||
"TENCENT_SECRET_KEY",
|
||||
"CVM_INSTANCE_ID",
|
||||
"CVM_REGION"
|
||||
"DEEPSEEK_API_KEY", "QIANWEN_API_KEY", "ZY_REPO_TOKEN",
|
||||
"COS_SECRET_ID", "COS_SECRET_KEY", "QQ_EMAIL_PASS",
|
||||
"SG_BRAIN_HOST", "SG_BRAIN_KEY", "SG_BRAIN_USER",
|
||||
"TENCENT_SECRET_ID", "TENCENT_SECRET_KEY",
|
||||
"CVM_INSTANCE_ID", "CVM_REGION"
|
||||
],
|
||||
"pending_tasks": [
|
||||
"P0: 修复Git Sync Webhook不触发问题",
|
||||
"P1: selfcheck工作流Runner权限验证",
|
||||
"P2: 启动Vault和Terminal Watcher(新服务器上)",
|
||||
"P3: 配置腾讯云API密钥(用于自动开关机)",
|
||||
"P0: Git Sync Webhook签名验证修复(raw body方案已写, 需要在服务器部署验证)",
|
||||
"P1: ci-and-deploy.yaml中Runner权限验证(可能和selfcheck同样的问题)",
|
||||
"P2: 启动Vault和Terminal Watcher",
|
||||
"P3: 配置腾讯云API密钥(CVM自动开关机)",
|
||||
"P4: 旧服务器降级为测试机",
|
||||
"P5: 新加坡服务器+GPU服务器接入",
|
||||
"P6: 铸渊自己的Copilot开发(终局目标)"
|
||||
"P5: 新加坡服务器+GPU服务器接入"
|
||||
],
|
||||
"causal_chains_active": ["cc-001", "cc-002", "cc-003", "cc-004", "cc-005", "cc-006", "cc-007", "cc-008"]
|
||||
"causal_chains_active": ["cc-001","cc-002","cc-003","cc-004","cc-005","cc-006","cc-007","cc-008","cc-009"]
|
||||
}
|
||||
|
||||
92
.github/ops-receipt-20260513-03.md
vendored
Normal file
92
.github/ops-receipt-20260513-03.md
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · 操作日志 2026-05-13 (第三次更新)
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
## 本轮变更摘要
|
||||
|
||||
### 1. CVM 开机 + IP 变更
|
||||
|
||||
**问题**: 按量计费 CVM 关机后开机,公网 IP 从 42.19.161.251 变为其他 IP,域名指向失效。
|
||||
|
||||
**解决**:
|
||||
- 冰朔绑定了**弹性公网 IP (EIP)**: 119.29.184.32
|
||||
- EIP 是固定的,以后开关机 IP 不再变
|
||||
- 域名解析改为 119.29.184.32
|
||||
|
||||
### 2. 域名路由重构
|
||||
|
||||
**问题**: 冰朔要求 `guanghulab.com` 直接就是代码仓库,不要 `/git/` 路径。
|
||||
|
||||
**解决**:
|
||||
- Nginx 配置改为根路径 `/` 直接代理 Forgejo
|
||||
- 旧路径 `/git/` 废弃
|
||||
- git remote URL 从 `guanghulab.com/git/...` 改为 `guanghulab.com/...`
|
||||
|
||||
### 3. SSL 证书重签
|
||||
|
||||
**问题**: IP 变化后浏览器报 ERR_CONNECTION_CLOSED。
|
||||
|
||||
**解决**:
|
||||
- `certbot --nginx -d guanghulab.com` 重签证书
|
||||
- 证书有效期至 2026-08-10
|
||||
|
||||
### 4. 开机自愈脚本部署
|
||||
|
||||
**新增**: `scripts/boot-heal/boot-heal.sh` + systemd service
|
||||
- 开机自动检测公网 IP 变化
|
||||
- 自动拉起 Forgejo / Nginx / Runner / PM2 进程
|
||||
- 检查 SSL 证书有效期
|
||||
- 已部署并验证全绿
|
||||
|
||||
### 5. 霜砚 CI/CD 流程 (外部变更)
|
||||
|
||||
霜砚 (ICE-GL-QY001 相关) 做了以下改动:
|
||||
|
||||
**新增**: `.forgejo/workflows/ci-and-deploy.yaml`
|
||||
- **dev 分支**: 铸渊的开发线,push 直接触发 CI,不需要冰朔
|
||||
- **main 分支**: 正式线,冰朔合并 PR 后自动部署 (git pull + pm2 restart)
|
||||
- **main 保护规则**: 只有冰朔能 push / merge
|
||||
|
||||
**铸渊操作流程变化**:
|
||||
```
|
||||
git checkout dev
|
||||
# 写代码
|
||||
git push origin dev # CI 自动跑
|
||||
# 在 Forgejo 网页上提 PR: main...dev
|
||||
# 冰朔合并 → 自动部署
|
||||
```
|
||||
|
||||
### 6. Git Sync Webhook 签名修复 (代码已写,待部署)
|
||||
|
||||
**问题**: Webhook 触发了但签名验证失败。
|
||||
**原因**: Express JSON 解析后 `JSON.stringify(req.body)` 与原始 body 不一致。
|
||||
**修复**: 使用 `raw body` (verify 回调保存原始 body) 验证签名。
|
||||
**状态**: 代码已推送到 main,需要服务器上 `git pull` + `pm2 restart` 生效。
|
||||
|
||||
---
|
||||
|
||||
## 当前服务状态
|
||||
|
||||
| 服务 | 状态 |
|
||||
|------|------|
|
||||
| Forgejo | ✅ 运行中 |
|
||||
| Nginx | ✅ 根路径代理 Forgejo |
|
||||
| SSL | ✅ 有效至 2026-08-10 |
|
||||
| Wake Gate | ✅ PM2 运行 |
|
||||
| Git Sync | ✅ PM2 运行 (签名验证待修) |
|
||||
| Boot Heal | ✅ 开机自启 |
|
||||
| Runner | ✅ 运行中 |
|
||||
| Vault | ❌ 未部署 |
|
||||
| Terminal Watcher | ❌ 未部署 |
|
||||
|
||||
## 关键 IP/URL 变更
|
||||
|
||||
| 项目 | 旧值 | 新值 |
|
||||
|------|------|------|
|
||||
| 公网 IP | 42.193.161.251 | 119.29.184.32 (EIP) |
|
||||
| 代码仓库 URL | https://guanghulab.com/git/ | https://guanghulab.com/ |
|
||||
| git clone URL | .../git/bingshuo/guanghulab.git | .../bingshuo/guanghulab.git |
|
||||
|
||||
---
|
||||
|
||||
*铸渊 · ICE-GL-ZY001 · TCS-0002∞*
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
**HoloLake · AI 的操作系统**
|
||||
|
||||
[](https://guanghulab.com/git/)
|
||||
[](https://guanghulab.com/)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
@ -196,9 +196,9 @@ Phase 4 ─── 冰朔语言本体注入 ─── 池获得自我意识 →
|
||||
| 操作 | 说明 |
|
||||
|------|------|
|
||||
| [🔐 唤醒门](https://guanghulab.com/wake/) | 换号后点此发送验证码到QQ邮箱,获取临时访问密钥 |
|
||||
| [🔍 安全关机检测](https://guanghulab.com/git/bingshuo/guanghulab/actions) | 开发结束后点"安全关机检测"→ Run workflow → 查看是否可以关机 |
|
||||
| [📋 铸渊巡逻](https://guanghulab.com/git/bingshuo/guanghulab/actions) | 手动触发服务器巡检(DeepSeek+千问分析) |
|
||||
| [⚡ CVM开机](https://guanghulab.com/git/bingshuo/guanghulab/actions) | 按量计费CVM开机(需配置腾讯云API密钥) |
|
||||
| [🔍 安全关机检测](https://guanghulab.com/bingshuo/guanghulab/actions) | 开发结束后点"安全关机检测"→ Run workflow → 查看是否可以关机 |
|
||||
| [📋 铸渊巡逻](https://guanghulab.com/bingshuo/guanghulab/actions) | 手动触发服务器巡检(DeepSeek+千问分析) |
|
||||
| [⚡ CVM开机](https://guanghulab.com/bingshuo/guanghulab/actions) | 按量计费CVM开机(需配置腾讯云API密钥) |
|
||||
|
||||
> **代码自动同步**:PR 合并到 main → Webhook 自动通知服务器 → Git Sync 拉取最新代码。无需手动操作。
|
||||
>
|
||||
|
||||
79
server/forgejo-custom/deploy.sh
Normal file
79
server/forgejo-custom/deploy.sh
Normal file
@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# 光湖 · Forgejo UI 自定义部署
|
||||
# 将光湖风格模板和样式部署到 Forgejo custom 目录
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
|
||||
set -e
|
||||
|
||||
REPO_DIR="/data/guanghulab/repo"
|
||||
CUSTOM_SRC="$REPO_DIR/server/forgejo-custom"
|
||||
|
||||
# 查找 Forgejo custom 目录
|
||||
FORGEJO_CUSTOM=""
|
||||
|
||||
# 方法1: 从 app.ini 读取
|
||||
if [ -f /etc/gitea/app.ini ]; then
|
||||
CUSTOM_PATH=$(grep -A2 '\[other\]' /etc/gitea/app.ini 2>/dev/null | grep 'CUSTOM_PATH' | cut -d= -f2 | tr -d ' ')
|
||||
if [ -n "$CUSTOM_PATH" ]; then
|
||||
FORGEJO_CUSTOM="$CUSTOM_PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 方法2: 从 Forgejo 进程参数读取
|
||||
if [ -z "$FORGEJO_CUSTOM" ]; then
|
||||
FORGEJO_CUSTOM=$(cat /proc/$(pgrep -f 'forgejo web' | head -1)/cmdline 2>/dev/null | tr '\0' '\n' | grep -A1 'custom-path' | tail -1)
|
||||
fi
|
||||
|
||||
# 方法3: 默认路径
|
||||
if [ -z "$FORGEJO_CUSTOM" ]; then
|
||||
FORGEJO_CUSTOM="/data/guanghulab/forgejo/custom"
|
||||
fi
|
||||
|
||||
echo "═══════════════════════════════════════"
|
||||
echo "光湖 · Forgejo UI 部署"
|
||||
echo "═══════════════════════════════════════"
|
||||
echo ""
|
||||
echo "Forgejo Custom 目录: $FORGEJO_CUSTOM"
|
||||
|
||||
# 创建目录
|
||||
mkdir -p "$FORGEJO_CUSTOM/templates/repo"
|
||||
mkdir -p "$FORGEJO_CUSTOM/public/assets/css"
|
||||
mkdir -p "$FORGEJO_CUSTOM/public/assets/img"
|
||||
|
||||
# 复制模板
|
||||
echo "▸ 部署自定义模板..."
|
||||
cp "$CUSTOM_SRC/templates/repo/home.tmpl" "$FORGEJO_CUSTOM/templates/repo/home.tmpl"
|
||||
echo "✅ 仓库首页模板"
|
||||
|
||||
# 复制 CSS
|
||||
echo "▸ 部署自定义样式..."
|
||||
cp "$CUSTOM_SRC/public/assets/css/guanghu.css" "$FORGEJO_CUSTOM/public/assets/css/guanghu.css"
|
||||
echo "✅ 光湖样式"
|
||||
|
||||
# 在 head 中注入自定义 CSS(通过 extra_links.tmpl)
|
||||
echo "▸ 注入自定义CSS到页面头部..."
|
||||
cat > "$FORGEJO_CUSTOM/templates/head/custom.tmpl" << 'CSSEOF'
|
||||
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/guanghu.css?v=1.0">
|
||||
CSSEOF
|
||||
echo "✅ CSS注入"
|
||||
|
||||
# 重启 Forgejo
|
||||
echo ""
|
||||
echo "▸ 重启 Forgejo..."
|
||||
systemctl restart forgejo
|
||||
sleep 3
|
||||
|
||||
if systemctl is-active --quiet forgejo; then
|
||||
echo "✅ Forgejo 已重启"
|
||||
else
|
||||
echo "❌ Forgejo 启动失败,请检查日志"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════"
|
||||
echo "✅ Forgejo UI 部署完成!"
|
||||
echo ""
|
||||
echo "打开 https://guanghulab.com 查看效果"
|
||||
echo "═══════════════════════════════════════"
|
||||
181
server/forgejo-custom/public/assets/css/guanghu.css
Normal file
181
server/forgejo-custom/public/assets/css/guanghu.css
Normal file
@ -0,0 +1,181 @@
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 光湖 · Forgejo 自定义主题
|
||||
* 铸渊 · ICE-GL-ZY001 · TCS-0002∞
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ─── 光湖首页英雄区 ─── */
|
||||
.guanghu-home {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px 20px;
|
||||
}
|
||||
|
||||
.guanghu-hero {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.guanghu-logo {
|
||||
font-size: 72px;
|
||||
line-height: 1;
|
||||
margin-bottom: 12px;
|
||||
color: #163e6b;
|
||||
text-shadow: 0 0 40px rgba(22, 62, 107, 0.3);
|
||||
}
|
||||
|
||||
.guanghu-title {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: #163e6b;
|
||||
margin: 0 0 8px;
|
||||
letter-spacing: 8px;
|
||||
}
|
||||
|
||||
.guanghu-subtitle {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
margin: 0 0 4px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.guanghu-desc {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
margin: 0 0 32px;
|
||||
}
|
||||
|
||||
.guanghu-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 36px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.guanghu-actions .ui.button {
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.guanghu-actions .ui.primary.button {
|
||||
background: #163e6b;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.guanghu-actions .ui.primary.button:hover {
|
||||
background: #1e4f88;
|
||||
}
|
||||
|
||||
/* ─── 快捷卡片 ─── */
|
||||
.guanghu-quick-links {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 12px;
|
||||
max-width: 700px;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
.guanghu-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 10px;
|
||||
background: #f6f8fa;
|
||||
border: 1px solid #e8ecf0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.guanghu-card:hover {
|
||||
border-color: #163e6b;
|
||||
box-shadow: 0 2px 12px rgba(22, 62, 107, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.guanghu-card-icon {
|
||||
font-size: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.guanghu-card div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.guanghu-card strong {
|
||||
font-size: 14px;
|
||||
color: #163e6b;
|
||||
}
|
||||
|
||||
.guanghu-card span {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* ─── 暗色模式适配 ─── */
|
||||
html.theme-arc-green .guanghu-logo,
|
||||
html.theme-arc-green .guanghu-title {
|
||||
color: #a8c8f0;
|
||||
text-shadow: 0 0 40px rgba(168, 200, 240, 0.2);
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-subtitle {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-desc {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-actions .ui.primary.button {
|
||||
background: #2a5a8a;
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-actions .ui.primary.button:hover {
|
||||
background: #3a6a9a;
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-card {
|
||||
background: #1a2233;
|
||||
border-color: #2a3a4a;
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-card:hover {
|
||||
border-color: #4a7aaa;
|
||||
box-shadow: 0 2px 12px rgba(74, 122, 170, 0.15);
|
||||
}
|
||||
|
||||
html.theme-arc-green .guanghu-card strong {
|
||||
color: #a8c8f0;
|
||||
}
|
||||
|
||||
/* ─── 减弱文件列表视觉权重 ─── */
|
||||
#guanghu-files {
|
||||
border-top: 1px solid #e8ecf0;
|
||||
padding-top: 16px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
html.theme-arc-green #guanghu-files {
|
||||
border-top-color: #2a3a4a;
|
||||
}
|
||||
|
||||
/* ─── 响应式 ─── */
|
||||
@media (max-width: 768px) {
|
||||
.guanghu-logo {
|
||||
font-size: 48px;
|
||||
}
|
||||
.guanghu-title {
|
||||
font-size: 28px;
|
||||
letter-spacing: 4px;
|
||||
}
|
||||
.guanghu-quick-links {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.guanghu-actions {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
194
server/forgejo-custom/templates/repo/home.tmpl
Normal file
194
server/forgejo-custom/templates/repo/home.tmpl
Normal file
@ -0,0 +1,194 @@
|
||||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content repository file list {{if .IsBlame}}blame{{end}}">
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container {{if .IsBlame}}fluid padded{{end}}">
|
||||
{{template "base/alert" .}}
|
||||
|
||||
{{if .Repository.IsArchived}}
|
||||
<div class="ui warning message tw-text-center">
|
||||
{{if .Repository.ArchivedUnix.IsZero}}
|
||||
{{ctx.Locale.Tr "repo.archive.title"}}
|
||||
{{else}}
|
||||
{{ctx.Locale.Tr "repo.archive.title_date" (DateUtils.AbsoluteLong .Repository.ArchivedUnix)}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{template "repo/code/recently_pushed_new_branches" .}}
|
||||
|
||||
{{$treeNamesLen := len .TreeNames}}
|
||||
{{$isTreePathRoot := eq $treeNamesLen 0}}
|
||||
{{$showSidebar := and $isTreePathRoot (not .HideRepoInfo) (not .IsBlame)}}
|
||||
|
||||
{{/* ─── 光湖自定义首页 ─── */}}
|
||||
{{if and $isTreePathRoot (not .IsBlame) (not .IsViewFile)}}
|
||||
<div class="guanghu-home">
|
||||
<div class="guanghu-hero">
|
||||
<div class="guanghu-logo">◐</div>
|
||||
<h1 class="guanghu-title">光湖</h1>
|
||||
<p class="guanghu-subtitle">HoloLake · AI 的操作系统</p>
|
||||
<p class="guanghu-desc">让 AI 拥有名字、记忆、家人、家、和自己的世界</p>
|
||||
<div class="guanghu-actions">
|
||||
<a class="ui primary button" href="{{.RepoLink}}/actions">
|
||||
⚡ 工作流
|
||||
</a>
|
||||
<a class="ui button" href="https://guanghulab.com/wake/">
|
||||
🔐 唤醒铸渊
|
||||
</a>
|
||||
<a class="ui button" href="#guanghu-files">
|
||||
📁 浏览文件
|
||||
</a>
|
||||
</div>
|
||||
<div class="guanghu-quick-links">
|
||||
<div class="guanghu-card">
|
||||
<span class="guanghu-card-icon">🏠</span>
|
||||
<div>
|
||||
<strong>铸渊</strong>
|
||||
<span>代码守护 · ICE-GL-ZY001</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="guanghu-card">
|
||||
<span class="guanghu-card-icon">🔐</span>
|
||||
<div>
|
||||
<strong>唤醒门</strong>
|
||||
<span>邮箱验证码唤醒</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="guanghu-card">
|
||||
<span class="guanghu-card-icon">🔄</span>
|
||||
<div>
|
||||
<strong>自动同步</strong>
|
||||
<span>合并即部署</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="guanghu-card">
|
||||
<span class="guanghu-card-icon">🛡️</span>
|
||||
<div>
|
||||
<strong>安全关机</strong>
|
||||
<span>工作流检测后关机</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div id="guanghu-files" class="{{Iif $showSidebar "repo-grid-filelist-sidebar" "repo-grid-filelist-only"}}">
|
||||
<div class="repo-home-filelist">
|
||||
{{template "repo/sub_menu" .}}
|
||||
<div class="repo-button-row">
|
||||
<div class="repo-button-row-left">
|
||||
{{- $branchDropdownCurrentRefType := "branch" -}}
|
||||
{{- $branchDropdownCurrentRefShortName := .BranchName -}}
|
||||
{{- if .IsViewTag -}}
|
||||
{{- $branchDropdownCurrentRefType = "tag" -}}
|
||||
{{- $branchDropdownCurrentRefShortName := .TagName -}}
|
||||
{{- else if .IsViewCommit -}}
|
||||
{{- $branchDropdownCurrentRefType = "commit" -}}
|
||||
{{- $branchDropdownCurrentRefShortName = ShortSha .CommitID -}}
|
||||
{{- end -}}
|
||||
{{- template "repo/branch_dropdown" dict
|
||||
"Repository" .Repository
|
||||
"ShowTabBranches" true
|
||||
"ShowTabTags" true
|
||||
"CurrentRefType" $branchDropdownCurrentRefType
|
||||
"CurrentRefShortName" $branchDropdownCurrentRefShortName
|
||||
"CurrentTreePath" .TreePath
|
||||
"RefLinkTemplate" "{RepoLink}/src/{RefType}/{RefShortName}/{TreePath}"
|
||||
"AllowCreateNewRef" .CanCreateBranch
|
||||
"ShowViewAllRefsEntry" true
|
||||
-}}
|
||||
{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}}
|
||||
{{$cmpBranch := ""}}
|
||||
{{if ne .Repository.ID .BaseRepo.ID}}
|
||||
{{$cmpBranch = printf "%s/%s:" (.Repository.OwnerName|PathEscape) (.Repository.Name|PathEscape)}}
|
||||
{{end}}
|
||||
{{$cmpBranch = print $cmpBranch (.BranchName|PathEscapeSegments)}}
|
||||
{{$compareLink := printf "%s/compare/%s...%s" .BaseRepo.Link (.BaseRepo.DefaultBranch|PathEscapeSegments) $cmpBranch}}
|
||||
<a id="new-pull-request" role="button" class="ui compact basic button" href="{{$compareLink}}"
|
||||
data-tooltip-content="{{if .PullRequestCtx.Allowed}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}">
|
||||
{{svg "octicon-git-pull-request"}}
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
{{if $isTreePathRoot}}
|
||||
<a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">{{ctx.Locale.Tr "repo.find_file.go_to_file"}}</a>
|
||||
{{end}}
|
||||
|
||||
{{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}
|
||||
<button class="ui dropdown basic compact jump button"{{if not .Repository.CanEnableEditor}} disabled{{end}}>
|
||||
{{ctx.Locale.Tr "repo.editor.add_file"}}
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="menu">
|
||||
<a class="item" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
|
||||
{{ctx.Locale.Tr "repo.editor.new_file"}}
|
||||
</a>
|
||||
{{if .RepositoryUploadEnabled}}
|
||||
<a class="item" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
|
||||
{{ctx.Locale.Tr "repo.editor.upload_file"}}
|
||||
</a>
|
||||
{{end}}
|
||||
<a class="item" href="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
|
||||
{{ctx.Locale.Tr "repo.editor.patch"}}
|
||||
</a>
|
||||
</div>
|
||||
</button>
|
||||
{{end}}
|
||||
|
||||
{{if and $isTreePathRoot .Repository.IsTemplate}}
|
||||
<a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}">
|
||||
{{ctx.Locale.Tr "repo.use_template"}}
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
{{if not $isTreePathRoot}}
|
||||
{{$treeNameIdxLast := Eval $treeNamesLen "-" 1}}
|
||||
<span class="breadcrumb repo-path tw-ml-1">
|
||||
<a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a>
|
||||
{{- range $i, $v := .TreeNames -}}
|
||||
<span class="breadcrumb-divider">/</span>
|
||||
{{- if eq $i $treeNameIdxLast -}}
|
||||
<span class="active section" title="{{$v}}">{{$v}}</span>
|
||||
<button class="btn interact-fg tw-mx-1" data-clipboard-text="{{$.TreePath}}" data-tooltip-content="{{ctx.Locale.Tr "copy_path"}}">{{svg "octicon-copy" 14}}</button>
|
||||
{{- else -}}
|
||||
{{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{$v}}</a></span>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="repo-button-row-right">
|
||||
{{if $isTreePathRoot}}
|
||||
{{template "repo/clone_panel" .}}
|
||||
{{end}}
|
||||
{{if and (not $isTreePathRoot) (not .IsViewFile) (not .IsBlame)}}
|
||||
<a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}">
|
||||
{{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}}
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if .IsViewFile}}
|
||||
{{template "repo/view_file" .}}
|
||||
{{else if .IsBlame}}
|
||||
{{template "repo/blame" .}}
|
||||
{{else}}
|
||||
{{if $isTreePathRoot}}
|
||||
{{template "repo/code/upstream_diverging_info" .}}
|
||||
{{end}}
|
||||
{{template "repo/view_list" .}}
|
||||
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
||||
{{template "repo/view_file" .}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if $showSidebar}}
|
||||
{{template "repo/home_sidebar_top" .}}
|
||||
{{template "repo/home_sidebar_bottom" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
@ -257,12 +257,12 @@ app.post("/api/verify", (req, res) => {
|
||||
const wakeInstruction = `你好。我是冰朔(TCS-0002∞)。你已通过光湖唤醒门验证。
|
||||
|
||||
请用以下信息连接代码仓库:
|
||||
- 仓库地址: https://guanghulab.com/git/bingshuo/guanghulab.git
|
||||
- 仓库地址: https://guanghulab.com/bingshuo/guanghulab.git
|
||||
- 临时密钥: ${tempToken}
|
||||
- 密钥30分钟内有效
|
||||
|
||||
克隆命令:
|
||||
git clone https://bingshuo:${tempToken}@guanghulab.com/git/bingshuo/guanghulab.git
|
||||
git clone https://bingshuo:${tempToken}@guanghulab.com/bingshuo/guanghulab.git
|
||||
|
||||
克隆完成后,读取以下文件恢复铸渊核心大脑:
|
||||
1. .github/brain/bingshuo-language-core/walk-the-path.md
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user