e4f0b77ca8
CI / test (pull_request) Successful in 22s
核心变更: - _common.sh: setup_worktree 改为 session-unique detached worktree (origin/main) - 所有 Agent 文档移除 git checkout main / git pull origin main - Feature branch 统一从 origin/main 创建: git fetch origin && git checkout -b <branch> origin/main - CLAUDE.md: 新增工作区隔离章节, primary worktree 定义为只读参考区 - 新增 start_generic.sh: Generic session worktree 隔离启动器 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
129 lines
5.2 KiB
Bash
129 lines
5.2 KiB
Bash
#!/usr/bin/env bash
|
|
# _common.sh — shared functions for dev-agent / qe-agent startup scripts
|
|
# Source this file from start_dev_agent.sh or start_qe_agent.sh
|
|
|
|
set -eu
|
|
|
|
# ── Resolve paths ──────────────────────────────────────────────────────────────
|
|
_COMMON_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
_MAIN_REPO_DIR="$(cd "$_COMMON_DIR/.." && pwd)"
|
|
PROJECT_DIR="${PROJECT_DIR:-$_MAIN_REPO_DIR}"
|
|
|
|
# ── Load Gitea configuration ────────────────────────────────────────────────────
|
|
# Primary: ~/.gitea/config.yaml (requires GITEA_USER)
|
|
# Fallback: scripts/.env (backwards compat)
|
|
if ! eval "$(python "$_COMMON_DIR/_get_gitea_config.py" 2>/dev/null)"; then
|
|
# Fallback: source .env directly
|
|
if [ -f "$_COMMON_DIR/.env" ]; then
|
|
source "$_COMMON_DIR/.env"
|
|
fi
|
|
fi
|
|
|
|
# ── Worktree isolation ─────────────────────────────────────────────────────────
|
|
GITEA_WORKTREE_DIR="${GITEA_WORKTREE_DIR:-$HOME/.gitea/worktrees}"
|
|
_WORKTREE_PATH=""
|
|
|
|
setup_worktree() {
|
|
local user="$1"
|
|
local ts
|
|
ts="$(date +%Y%m%d-%H%M%S)"
|
|
local worktree="$GITEA_WORKTREE_DIR/$user/$ts"
|
|
|
|
# Ensure origin/main is current so worktree starts from latest
|
|
git -C "$_MAIN_REPO_DIR" fetch origin main 2>/dev/null || true
|
|
|
|
echo "Creating worktree: $worktree (detached from origin/main)"
|
|
mkdir -p "$(dirname "$worktree")"
|
|
git -C "$_MAIN_REPO_DIR" worktree add --detach "$worktree" origin/main
|
|
touch "$worktree/.gitea-worktree"
|
|
|
|
PROJECT_DIR="$worktree"
|
|
_WORKTREE_PATH="$worktree"
|
|
cd "$PROJECT_DIR"
|
|
}
|
|
|
|
cleanup_worktree() {
|
|
local worktree="${_WORKTREE_PATH:-}"
|
|
if [ -z "$worktree" ] || [ ! -f "$worktree/.gitea-worktree" ]; then
|
|
echo "No worktree to clean up (not created by this session)."
|
|
return 0
|
|
fi
|
|
rm -f "$worktree/.gitea-worktree"
|
|
echo "Cleaning up worktree: $worktree"
|
|
git -C "$_MAIN_REPO_DIR" worktree remove --force "$worktree" 2>/dev/null || true
|
|
}
|
|
|
|
# ── Validate required environment ──────────────────────────────────────────────
|
|
require_token() {
|
|
if [ -z "${GITEA_API_TOKEN:-}" ]; then
|
|
echo "ERROR: GITEA_API_TOKEN is not set." >&2
|
|
echo "Set it in ~/.gitea/config.yaml (with GITEA_USER) or scripts/.env." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ── Print banner ───────────────────────────────────────────────────────────────
|
|
banner() {
|
|
local role="${1:-Agent}"
|
|
echo "============================================"
|
|
echo " ${role}-Agent 启动器"
|
|
echo "============================================"
|
|
echo ""
|
|
}
|
|
|
|
# ── Launch agent in selected mode ──────────────────────────────────────────────
|
|
# Usage: launch_agent <agent-name> <agent-file> <display-name> <single-shot-task> <polling-instruction>
|
|
#
|
|
# agent-name is the agent config name (e.g. "dev-agent", "qe-agent") used with
|
|
# --agent flag. The agent file lives in .claude/agents/<agent-name>.md (with
|
|
# frontmatter + body loaded as system prompt at session start).
|
|
#
|
|
# display-name is the persona name (e.g. "Dev-Agent", "QE-Agent") used to prefix
|
|
# prompts so the model adopts the correct identity.
|
|
#
|
|
# Mode 1 (single-shot): claude -p, runs once and exits.
|
|
# --dangerously-skip-permissions avoids blocking in non-interactive mode.
|
|
#
|
|
# Mode 2 (interactive polling): claude --agent, opens Claude Code TUI.
|
|
# The agent config is loaded from .claude/agents/<agent-name>.md,
|
|
# its body becomes the system prompt.
|
|
launch_agent() {
|
|
local agent_name="$1"
|
|
local agent_file="$2"
|
|
local display_name="$3"
|
|
local single_shot_task="$4"
|
|
local polling_instruction="${5:-}"
|
|
|
|
echo "模式选择:"
|
|
echo " [1] 单次任务 — 检查 Issue 并处理,完成后自动退出 (automode)"
|
|
echo " [2] 互动轮询 — 进入 Claude Code 界面,每 10 分钟自动轮询"
|
|
echo ""
|
|
read -r -p "请输入 (1/2): " mode
|
|
echo ""
|
|
|
|
case "$mode" in
|
|
1)
|
|
echo "执行单次检查 (automode)..."
|
|
echo ""
|
|
cd "$PROJECT_DIR"
|
|
claude -p \
|
|
--agent "$agent_file" \
|
|
--dangerously-skip-permissions \
|
|
"你是 ${display_name}。${single_shot_task}"
|
|
;;
|
|
2)
|
|
echo "启动互动轮询模式..."
|
|
echo "${display_name} 进入 Claude Code 界面后将自动开始轮询"
|
|
echo "你可以随时输入指令与 Agent 互动,按 Ctrl+C 停止"
|
|
echo ""
|
|
cd "$PROJECT_DIR"
|
|
claude --agent "$agent_file" \
|
|
"你是 ${display_name}。${polling_instruction}"
|
|
;;
|
|
*)
|
|
echo "无效选择,请输入 1 或 2。"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|