From dffa3fae1258748f2940711bbdd6384c7fc94668 Mon Sep 17 00:00:00 2001 From: voson Date: Wed, 21 Jan 2026 15:55:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81=E4=BD=93=E7=B3=BB=EF=BC=8C=E5=B0=86=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E8=BF=81=E7=A7=BB=E4=B8=BA=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command/git-commit.md | 52 -- command/git-push.md | 55 --- command/gitea-config.md | 72 --- command/gitea-create-repo.md | 104 ---- command/gitea-create-runner.md | 770 ------------------------------ command/gitea-delete-runner.md | 174 ------- command/gitea-list-runners.md | 94 ---- command/review.md | 20 - command/summarize-conversation.md | 84 ---- opencode.json | 4 +- skill/git/SKILL.md | 7 + skill/git/commit-workflow.md | 163 +++++++ skill/git/push-workflow.md | 107 +++++ skill/git/quick-reference.md | 663 ------------------------- skill/gitea/SKILL.md | 1 + skill/gitea/create-runner.md | 416 ++++++++++++++++ skill/gitea/delete-runner.md | 303 ++++++++++++ skill/gitea/runner-management.md | 111 ++++- 18 files changed, 1101 insertions(+), 2099 deletions(-) delete mode 100644 command/git-commit.md delete mode 100644 command/git-push.md delete mode 100644 command/gitea-config.md delete mode 100644 command/gitea-create-repo.md delete mode 100644 command/gitea-create-runner.md delete mode 100644 command/gitea-delete-runner.md delete mode 100644 command/gitea-list-runners.md delete mode 100644 command/review.md delete mode 100644 command/summarize-conversation.md create mode 100644 skill/git/commit-workflow.md create mode 100644 skill/git/push-workflow.md delete mode 100644 skill/git/quick-reference.md create mode 100644 skill/gitea/create-runner.md create mode 100644 skill/gitea/delete-runner.md diff --git a/command/git-commit.md b/command/git-commit.md deleted file mode 100644 index af3d832..0000000 --- a/command/git-commit.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -description: 提交暂存文件,自动生成提交信息并创建版本标签 ---- - -Auto-generate a commit message for staged files, commit to the local repository, and create a version tag following semantic versioning. - -Please follow the git workflow defined in `@skill/git/SKILL.md`: - -1. **Check staging area** - Verify files are staged with `git diff --cached --name-only` - - If empty, inform the user and stop -2. **Collect information** - Run these commands in parallel: - - `git status` - - `git diff --cached` - - `git log --oneline -10` - - `git tag --list | sort -V | tail -5` - - Read `@AGENTS.md` if it exists (repository type, version rules, project structure) -3. **Detect repository type** - Polyrepo (tag: `1.2.0`) or Monorepo (tag: `subproject-1.2.0`) -4. **Detect project type and version** - Check for version files: - - iOS: `*.xcodeproj/project.pbxproj` → `MARKETING_VERSION` - - Node.js: `package.json` → `version` - - Android: `build.gradle(.kts)` → `versionName` - - Go: Git tag only -5. **Generate commit message** following Conventional Commits: - - Format: `(): ` - - Use Chinese for commit messages (macOS/Linux) - - Types: feat, fix, docs, style, refactor, perf, test, chore, ci, build - - For monorepo, use subproject as scope if changes affect single subproject -6. **Update version number** if needed: - - feat: minor +1 (1.2.0 → 1.3.0) - - fix/perf: patch +1 (1.2.3 → 1.2.4) - - Breaking change: major +1 (1.2.3 → 2.0.0) - - Only for user-perceivable changes (feat, fix, perf, breaking) - - Add updated version file to staging -7. **Commit changes** with generated message -8. **Create version tag** if version was updated (unless user specified "skip tag"): - - Polyrepo: `git tag -a "1.2.0" -m "commit message"` - - Monorepo: `git tag -a "subproject-1.2.0" -m "commit message"` - -**Options:** -- User can input "skip tag" or "skip" to skip tag creation - -**Display result in Chinese:** -``` -✓ 提交成功 - -提交信息:[commit message] -版本标签:[tag] (如果创建了) - -要推送到远程仓库,请运行:/git-push -``` - -**Important:** This command does NOT push to remote. Use `/git-push` to push commits and tags. diff --git a/command/git-push.md b/command/git-push.md deleted file mode 100644 index 4867b63..0000000 --- a/command/git-push.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -description: 提交暂存文件,创建版本标签并推送到远程仓库 ---- - -Complete workflow: auto-generate commit message, create version tag, commit, and push everything to remote repository. - -This is the **all-in-one command** that combines `/git-commit` + push operations. - -Please perform the following: - -1-7. **Follow the same steps as `/git-commit`:** - - Check staging area (must not be empty) - - Analyze changes and repository type - - Detect project type and version - - Generate commit message (Conventional Commits, Chinese) - - Update version number if needed - - Commit changes - - Create version tag - - Refer to `/git-commit` for detailed steps or `@skill/git/SKILL.md` for complete workflow. - -8. **Push commit to remote:** - ```bash - git push origin $(git branch --show-current) - ``` - -9. **Push tag to remote** (only if tag was created): - - Polyrepo: `git push origin ` - - Monorepo: `git push origin -` - -10. **Display result in Chinese:** -``` -✓ 提交并推送成功 - -分支:[branch] -提交信息:[commit message] -版本标签:[tag] (如果创建了) - -已推送到远程仓库:origin -- 提交:[commit hash] -- 标签:[tag] -``` - -**Error handling:** -- If staging area is empty: "暂存区为空,请先使用 `git add` 添加文件。" -- If push fails (e.g., need to pull first): Show error in Chinese with suggested solutions -- If remote rejects tag (already exists): Show error and suggest deleting local tag or updating version - -**Options:** -- User can input "skip tag" or "skip" to skip tag creation - -**When to use:** -- `/git-commit`: Local only, review before pushing -- `/git-push`: Commit and push immediately -- `/git-push-tags`: Push tags only (no commits) diff --git a/command/gitea-config.md b/command/gitea-config.md deleted file mode 100644 index 967d28a..0000000 --- a/command/gitea-config.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -description: 查看当前 Gitea 配置和 Runner 状态 ---- - -Display the current Gitea configuration and runner status. - -## 工作目录 - -**macOS / Linux:** -``` -~/.config/gitea/ -``` - -**Windows:** -``` -%USERPROFILE%\.config\gitea\ -``` - -Please perform the following: - -1. **Check if configuration exists:** - - Config file: - - macOS/Linux: `~/.config/gitea/config.env` - - Windows: `%USERPROFILE%\.config\gitea\config.env` - - If not exists, prompt user to run `/gitea-reset` - -2. **Load and display configuration:** - -**macOS / Linux:** -```bash -source ~/.config/gitea/config.env -``` - -**Windows PowerShell:** -```powershell -Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object { - if ($_ -match '^([^=]+)=(.*)$') { - [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') - } -} -``` - -Show in Chinese: -- Gitea URL -- Default organization (if set) -- Config file path (根据平台显示正确路径) - -3. **Validate token and display user info:** - - Call API: `GET ${GITEA_URL}/api/v1/user` - - Header: `Authorization: token ${GITEA_TOKEN}` - - Show: Token status (✓ 有效 / ✗ 无效), username, email - -4. **Display runner information:** - - Runners directory: - - macOS/Linux: `~/.config/gitea/runners` - - Windows: `%USERPROFILE%\.config\gitea\runners` - - Count configured runners - - List each runner with status: - - 🟢 运行中 (process running) - - 🔴 已停止 (process not running) - - ⚠️ 配置异常 (config file missing) - -5. **Show management commands:** -``` -管理命令: -- 重置配置: /gitea-reset -- 切换组织: /gitea-switch-org -- 列出 Runners: /gitea-list-runners -- 创建仓库: /create-gitea-repo -``` - -Use `jq` to parse JSON responses and `pgrep` to check runner process status. diff --git a/command/gitea-create-repo.md b/command/gitea-create-repo.md deleted file mode 100644 index 20f9fe4..0000000 --- a/command/gitea-create-repo.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -description: 在 Gitea 上创建新的 Git 仓库 ---- - -Create a new Git repository on Gitea via API. - -## 工作目录 - -**macOS / Linux:** -``` -~/.config/gitea/ -``` - -**Windows:** -``` -%USERPROFILE%\.config\gitea\ -``` - -配置文件从该目录加载。 - -**User input format:** -``` -$ARGUMENTS = [/] [private|public] -``` - -**Examples:** -- `my-project` - Private repo under default org or current user -- `ai/my-project` - Private repo under ai organization -- `ai/my-project public` - Public repo under ai organization -- `username/test private` - Private repo under username - -Please perform the following: - -1. **Load configuration:** - -**macOS / Linux:** -```bash -source ~/.config/gitea/config.env -``` - -**Windows PowerShell:** -```powershell -Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object { - if ($_ -match '^([^=]+)=(.*)$') { - [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') - } -} -``` - - - If not exists: prompt to run `/gitea-reset` - -2. **Parse user input from `$ARGUMENTS`:** - - Extract: owner (optional), repo (required), visibility (optional, default: private) - - If no owner specified: - - Use `GITEA_DEFAULT_ORG` if set - - Otherwise get current user from API: `GET /api/v1/user` - - Validate repo name: only letters, numbers, underscores, hyphens, dots - -3. **Create repository via API:** - - Try organization API first: - ```bash - POST ${GITEA_URL}/api/v1/orgs/${owner}/repos - Body: { - "name": "${repo}", - "private": true/false, - "auto_init": false, - "default_branch": "main" - } - ``` - - If 404, try user API: `POST /api/v1/user/repos` - - Handle response codes: - - 201: Success - - 409: Repository already exists - - 404: Owner not found or no permission - - Other: API error - -4. **Extract repository info from response:** - - `html_url` - Web URL - - `clone_url` - HTTPS URL - - `ssh_url` - SSH URL - -5. **Ask user if they want to add remote:** - - Check if current directory is a git repo - - If not, ask to initialize: `git init` - - Check if `origin` remote exists - - Add or update remote: `git remote add/set-url origin ` - -6. **Display result in Chinese:** -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -仓库创建成功 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - 名称: [owner]/[repo] - 可见性: [private/public] - Web URL: [html_url] - HTTPS URL: [clone_url] - SSH URL: [ssh_url] -``` - -**Notes:** -- Requires repo creation permission in token -- Organization and user repositories use different API endpoints -- Default branch is `main` (not `master`) diff --git a/command/gitea-create-runner.md b/command/gitea-create-runner.md deleted file mode 100644 index 0b5036c..0000000 --- a/command/gitea-create-runner.md +++ /dev/null @@ -1,770 +0,0 @@ ---- -description: 创建并启动 Gitea Actions Runner(默认使用 host 模式) -agent: general -subtask: true ---- - -# 创建并启动 Gitea Actions Runner - -你的任务是创建并启动一个 Gitea Actions Runner(默认使用 host 模式)。 - -## 工作目录 - -**macOS / Linux:** -``` -~/.config/gitea/ -``` - -**Windows:** -``` -%USERPROFILE%\.config\gitea\ -``` - -所有 Runner 配置、缓存、工作区都存储在该目录的 `runners/` 子目录下。 - -## 核心功能要求 - -请按照以下步骤执行: - -1. **检查 act_runner 安装** - - 检查 act_runner 是否已安装(使用 `command -v act_runner`) - - 如果未安装,使用 Homebrew 自动安装:`brew install act_runner` - - 如果 Homebrew 不存在,提示用户安装 Homebrew - - 验证安装成功后显示版本信息 - -2. **加载 Gitea 配置** - - 从配置文件加载配置: - - macOS/Linux: `~/.config/gitea/config.env` - - Windows: `%USERPROFILE%\.config\gitea\config.env` - - 如果配置文件不存在,提示用户运行 `/gitea-reset` 初始化 - - 验证必需的配置项:`GITEA_URL` 和 `GITEA_TOKEN` - - 显示加载成功的配置信息 - -3. **生成 Runner 名称** - - 如果用户提供了参数 `$ARGUMENTS`,使用该名称 - - 否则默认基于主机名生成:`runner-$(hostname -s)` - - 验证名称只包含字母、数字、下划线和连字符 - -4. **检查 Runner 是否已存在** - - 检查 Runner 目录: - - macOS/Linux: `~/.config/gitea/runners/$runner_name` - - Windows: `%USERPROFILE%\.config\gitea\runners\$runner_name` - - 如果已存在,提示用户可选操作: - - 使用其他名称 - - 删除现有 runner(使用 `/gitea-delete-runner`) - - 查看所有 runners(使用 `/gitea-list-runners`) - -5. **检测系统环境** - - 检测操作系统(macOS/Linux) - - 检测架构(ARM64/x64) - - 生成 host 模式的 labels: - - `self-hosted:host` - - `{os_label}:host`(如 `macOS:host`) - - `{arch_label}:host`(如 `ARM64:host`) - - `{combined}:host`(如 `darwin-arm64:host`) - -6. **创建 Runner 目录结构** - - 创建目录结构: - - macOS/Linux: `~/.config/gitea/runners/$runner_name/{cache,workspace}` - - Windows: `%USERPROFILE%\.config\gitea\runners\$runner_name\{cache,workspace}` - - 验证目录创建成功 - -7. **生成配置文件** - - 创建 `config.yaml`,使用 host 模式配置 - - 从环境变量读取可选配置: - - `GITEA_RUNNER_CAPACITY`(默认 2) - - `GITEA_RUNNER_TIMEOUT`(默认 3h) - - 配置要点: - - log level: info - - runner.capacity: 并发任务数 - - runner.timeout: 任务超时 - - cache: 启用缓存 - - host.workdir_parent: 工作目录路径 - - labels: 使用检测到的系统 labels - -8. **获取注册 Token** - - 优先尝试创建全局 Runner(需要管理员权限) - - API: `GET ${GITEA_URL}/api/v1/admin/runners/registration-token` - - Header: `Authorization: token ${GITEA_TOKEN}` - - 如果返回 403/权限不足,自动降级到组织 Runner - - 使用 `GITEA_DEFAULT_ORG` 作为组织名 - - API: `POST ${GITEA_URL}/api/v1/orgs/${org_name}/actions/runners/registration-token` - - 从响应中提取 token(JSON 格式) - - 记录使用的 runner 级别(global 或 organization) - -9. **注册 Runner** - - 执行命令: - ```bash - act_runner register \ - --config "$runner_dir/config.yaml" \ - --instance "$GITEA_URL" \ - --token "$registration_token" \ - --name "$runner_name" \ - --labels "$labels" \ - --no-interactive - ``` - - 验证 `.runner` 文件是否创建 - - 如果失败,提供诊断建议 - -10. **后台启动 Runner** - - 使用 nohup 后台启动: - ```bash - nohup act_runner daemon --config "$runner_dir/config.yaml" \ - > "$runner_dir/runner.log" 2>&1 & - ``` - - 记录进程 PID - - 等待 3 秒初始化 - - 验证进程仍在运行 - - 如果失败,显示日志的最后 20 行 - -11. **显示创建摘要** - - Runner 信息:名称、级别、模式、状态、PID - - 如果是组织级别,显示组织名 - - 配置信息:容量、超时、labels - - 目录信息:配置文件、工作目录、缓存目录、日志文件 - - 管理命令:查看日志、停止 Runner、查看所有、删除 - - 使用示例:workflow 中的 runs-on 配置 - -## 重要配置说明 - -- **默认模式**:Host Mode(直接在宿主机执行,支持 Android SDK、iOS 构建等原生工具) -- **目录结构**: - - macOS/Linux: 所有 runners 位于 `~/.config/gitea/runners/` - - Windows: 所有 runners 位于 `%USERPROFILE%\.config\gitea\runners\` -- **优雅降级**:全局 runner 权限不足时自动降级到组织 runner -- **后台运行**:使用 nohup 后台启动(Unix),或 Start-Process(Windows),日志输出到文件 -- **进程管理**:需要手动管理进程(系统重启后需重新启动) - -## 可选参数 - -- `$ARGUMENTS`: Runner 名称(可选,默认基于主机名生成) - -使用示例: -``` -/gitea-create-runner -/gitea-create-runner my-custom-runner -``` - -## 相关命令 - -- `/gitea-config`: 查看 Gitea 配置 -- `/gitea-reset`: 重置/初始化 Gitea 配置 -- `/gitea-list-runners`: 列出所有 runners -- `/gitea-delete-runner`: 删除指定 runner - ---- - -## 详细实现步骤(供 AI 参考) - -### 1. Check act_runner Installation - -**AI 执行**:检查 act_runner 是否已安装,如果没有则自动安装。 - -```bash -echo "检查 act_runner 安装状态..." - -if command -v act_runner &> /dev/null; then - version=$(act_runner --version 2>&1 | head -n1) - echo "✓ act_runner 已安装: $version" -else - echo "⚠️ act_runner 未安装" - echo "正在使用 Homebrew 安装..." - - if ! command -v brew &> /dev/null; then - echo "❌ 需要先安装 Homebrew" - echo " 安装命令: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" - exit 1 - fi - - brew install act_runner - - if [ $? -eq 0 ]; then - version=$(act_runner --version 2>&1 | head -n1) - echo "✓ act_runner 安装成功: $version" - else - echo "❌ act_runner 安装失败" - exit 1 - fi -fi - -echo "" -``` - -### 2. Load Gitea Configuration - -**AI 执行**:加载 Gitea 配置,如果不存在则提示初始化。 - -```bash -config_file="$HOME/.config/gitea/config.env" - -if [ ! -f "$config_file" ]; then - echo "❌ Gitea 配置不存在" - echo "" - echo "请先初始化 Gitea 配置:" - echo " /gitea-reset" - echo "" - echo "或使用以下命令查看配置:" - echo " /gitea-config" - exit 1 -fi - -source "$config_file" - -if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then - echo "❌ Gitea 配置不完整" - echo " 需要 GITEA_URL 和 GITEA_TOKEN" - echo "" - echo "请重新初始化配置:" - echo " /gitea-reset" - exit 1 -fi - -echo "✓ 已加载 Gitea 配置" -echo " URL: $GITEA_URL" -echo "" -``` - -### 3. Generate Runner Name - -**AI 执行**:生成 runner 名称(基于主机名或用户输入)。 - -```bash -# Check if runner name provided as argument -# 如果用户提供了名称参数,使用该参数;否则基于主机名生成 - -if [ -n "$1" ]; then - runner_name="$1" - echo "使用指定的 Runner 名称: $runner_name" -else - hostname=$(hostname -s 2>/dev/null || echo "unknown") - runner_name="runner-$hostname" - echo "生成 Runner 名称: $runner_name" - echo " (基于主机名: $hostname)" -fi - -echo "" - -# Validate runner name -if [[ ! "$runner_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then - echo "❌ Runner 名称只能包含字母、数字、下划线和连字符" - exit 1 -fi -``` - -### 4. Check Runner Existence - -**AI 执行**:检查 runner 是否已存在。 - -```bash -runners_dir="$HOME/.config/gitea/runners" -runner_dir="$runners_dir/$runner_name" - -if [ -d "$runner_dir" ]; then - echo "❌ Runner '$runner_name' 已存在" - echo " 路径: $runner_dir" - echo "" - echo "选项:" - echo " 1. 使用其他名称: /gitea-create-runner <新名称>" - echo " 2. 删除现有 runner: /gitea-delete-runner" - echo " 3. 查看所有 runners: /gitea-list-runners" - exit 1 -fi -``` - -### 5. Detect System Environment - -**AI 执行**:智能检测系统环境并生成 labels。 - -```bash -echo "检测系统环境..." - -# Detect OS -OS=$(uname -s) -case "$OS" in - Darwin) os_label="macOS" ;; - Linux) os_label="ubuntu" ;; - *) os_label="unknown" ;; -esac - -# Detect architecture -ARCH=$(uname -m) -case "$ARCH" in - arm64|aarch64) arch_label="ARM64" ;; - x86_64) arch_label="x64" ;; - *) arch_label="unknown" ;; -esac - -# Generate combined label -combined=$(echo "${OS}-${ARCH}" | tr '[:upper:]' '[:lower:]') - -# Generate labels for host mode -labels="self-hosted:host,${os_label}:host,${arch_label}:host,${combined}:host" - -echo "✓ 系统信息" -echo " 操作系统: $OS ($os_label)" -echo " 架构: $ARCH ($arch_label)" -echo " 组合标签: $combined" -echo "" -echo "✓ Runner Labels (Host Mode)" -echo " $labels" -echo "" -``` - -### 6. Create Runner Directory - -**AI 执行**:创建 runner 目录结构。 - -```bash -echo "创建 Runner 目录..." - -mkdir -p "$runner_dir"/{cache,workspace} - -if [ ! -d "$runner_dir" ]; then - echo "❌ 创建目录失败" - exit 1 -fi - -echo "✓ 目录创建成功" -echo " 路径: $runner_dir" -echo " - cache/" -echo " - workspace/" -echo "" -``` - -### 7. Generate Configuration File - -**AI 执行**:生成 host 模式配置文件。 - -```bash -echo "生成配置文件..." - -# Get environment-specific settings (with defaults) -runner_capacity="${GITEA_RUNNER_CAPACITY:-2}" -runner_timeout="${GITEA_RUNNER_TIMEOUT:-3h}" - -# Generate config.yaml for host mode -cat > "$runner_dir/config.yaml" << EOF -log: - level: info - -runner: - file: $runner_dir/.runner - capacity: $runner_capacity - timeout: $runner_timeout - shutdown_timeout: 30s - insecure: false - fetch_timeout: 5s - fetch_interval: 2s - labels: - - "self-hosted:host" - - "${os_label}:host" - - "${arch_label}:host" - - "${combined}:host" - -cache: - enabled: true - dir: "$runner_dir/cache" - host: "127.0.0.1" - port: 9000 - -host: - workdir_parent: "$runner_dir/workspace" -EOF - -if [ ! -f "$runner_dir/config.yaml" ]; then - echo "❌ 配置文件生成失败" - exit 1 -fi - -echo "✓ 配置文件已生成" -echo " 文件: $runner_dir/config.yaml" -echo " 模式: Host Mode (原生执行)" -echo " 容量: $runner_capacity 并发任务" -echo " 超时: $runner_timeout" -echo "" -``` - -### 8. Get Registration Token - -**AI 执行**:获取注册 token(优先全局,失败则降级到组织)。 - -```bash -echo "获取 Runner 注册 Token..." -echo "" - -# Try global runner first (requires admin token) -echo "尝试创建全局 Runner(可用于所有组织和仓库)..." - -response=$(curl -s -w "\n%{http_code}" \ - -H "Authorization: token $GITEA_TOKEN" \ - "${GITEA_URL}/api/v1/admin/runners/registration-token") - -http_code=$(echo "$response" | tail -n1) -body=$(echo "$response" | sed '$d') - -# Check for admin permission -if [ "$http_code" = "200" ]; then - echo "✓ 使用全局 Runner" - runner_level="global" - registration_token=$(echo "$body" | jq -r '.token') -else - echo "⚠️ 全局 Runner 权限不足 (HTTP $http_code)" - echo " 全局 Runner 需要管理员 Token" - echo "" - echo "降级到组织 Runner..." - - runner_level="organization" - - if [ -n "$GITEA_DEFAULT_ORG" ]; then - org_name="$GITEA_DEFAULT_ORG" - echo "使用默认组织: $org_name" - else - echo "❌ 未配置默认组织" - echo " 请在配置文件中设置 GITEA_DEFAULT_ORG" - echo " 或重新初始化配置: /gitea-reset" - exit 1 - fi - - response=$(curl -s -w "\n%{http_code}" -X POST \ - -H "Authorization: token $GITEA_TOKEN" \ - "${GITEA_URL}/api/v1/orgs/$org_name/actions/runners/registration-token") - - http_code=$(echo "$response" | tail -n1) - body=$(echo "$response" | sed '$d') - - if [ "$http_code" != "200" ]; then - echo "❌ 获取注册 Token 失败 (HTTP $http_code)" - echo " 响应: $body" - echo "" - echo "可能的原因:" - echo " 1. 组织不存在" - echo " 2. Token 没有组织管理权限" - echo " 3. 网络连接问题" - exit 1 - fi - - registration_token=$(echo "$body" | jq -r '.token') - echo "✓ 组织 Runner Token 已获取" -fi - -if [ -z "$registration_token" ] || [ "$registration_token" = "null" ]; then - echo "❌ 无法解析注册 Token" - exit 1 -fi - -echo "✓ 注册 Token 已准备" -echo "" -``` - -### 9. Register Runner - -**AI 执行**:注册 runner 到 Gitea 服务器。 - -```bash -echo "注册 Runner 到 Gitea 服务器..." - -act_runner register \ - --config "$runner_dir/config.yaml" \ - --instance "$GITEA_URL" \ - --token "$registration_token" \ - --name "$runner_name" \ - --labels "$labels" \ - --no-interactive - -if [ $? -eq 0 ]; then - echo "✓ Runner 注册成功" -else - echo "❌ Runner 注册失败" - echo "" - echo "请检查:" - echo " 1. Token 是否有效" - echo " 2. Gitea 服务器是否可访问" - echo " 3. 配置文件是否正确" - echo "" - echo "查看详细错误,可以手动运行:" - echo " act_runner register --config $runner_dir/config.yaml --instance $GITEA_URL --token --name $runner_name --labels \"$labels\"" - exit 1 -fi - -# Verify .runner file was created -if [ ! -f "$runner_dir/.runner" ]; then - echo "⚠️ 注册文件未创建,但注册可能成功" - echo " 请检查: $runner_dir/.runner" -fi - -echo "" -``` - -### 10. Start Runner - -**AI 执行**:后台启动 runner 并验证状态。 - -```bash -echo "启动 Runner..." - -# Start runner in background -nohup act_runner daemon --config "$runner_dir/config.yaml" \ - > "$runner_dir/runner.log" 2>&1 & - -runner_pid=$! - -echo " 进程已启动 (PID: $runner_pid)" - -# Wait for runner to initialize -echo " 等待初始化..." -sleep 3 - -# Check if process is still running -if ps -p $runner_pid > /dev/null 2>&1; then - echo "✓ Runner 运行中" -else - echo "❌ Runner 启动失败" - echo "" - echo "查看日志以诊断问题:" - echo " tail -n 50 $runner_dir/runner.log" - echo "" - tail -n 20 "$runner_dir/runner.log" - exit 1 -fi - -echo "" -``` - -### 11. Display Summary - -**AI 执行**:显示创建结果和管理命令。 - -```bash -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "✅ Runner 创建完成!" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" -echo "Runner 信息:" -echo " 名称: $runner_name" -echo " 级别: $runner_level" -if [ "$runner_level" = "organization" ]; then - echo " 组织: $org_name" -fi -echo " 模式: Host Mode (原生执行)" -echo " 状态: 🟢 运行中" -echo " PID: $runner_pid" -echo "" -echo "配置:" -echo " 容量: $runner_capacity 并发任务" -echo " 超时: $runner_timeout" -echo " Labels: $labels" -echo "" -echo "目录:" -echo " 配置文件: $runner_dir/config.yaml" -echo " 注册信息: $runner_dir/.runner" -echo " 工作目录: $runner_dir/workspace" -echo " 缓存目录: $runner_dir/cache" -echo " 日志文件: $runner_dir/runner.log" -echo "" -echo "管理命令:" -echo " 查看日志: tail -f $runner_dir/runner.log" -echo " 停止 Runner: pkill -f 'act_runner daemon --config.*$runner_name'" -echo " 查看所有: /gitea-list-runners" -echo " 删除 Runner: /gitea-delete-runner" -echo "" -echo "使用 Runner:" -echo " 在 workflow 中使用以下任一 runs-on 值:" -echo " - runs-on: $combined" -echo " - runs-on: $os_label" -echo " - runs-on: [self-hosted, $os_label, $arch_label]" -echo "" -``` - -## Output Example - -### Example 1: Successful Creation (Global Runner) - -``` -检查 act_runner 安装状态... -✓ act_runner 已安装: act_runner version 0.2.13 - -✓ 已加载 Gitea 配置 - URL: https://git.digitevents.com - -生成 Runner 名称: runner-macbook-pro - (基于主机名: macbook-pro) - -检测系统环境... -✓ 系统信息 - 操作系统: Darwin (macOS) - 架构: arm64 (ARM64) - 组合标签: darwin-arm64 - -✓ Runner Labels (Host Mode) - self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host - -创建 Runner 目录... -✓ 目录创建成功 - 路径: /Users/voson/.config/gitea/runners/runner-macbook-pro - - cache/ - - workspace/ - -生成配置文件... -✓ 配置文件已生成 - 文件: /Users/voson/.config/gitea/runners/runner-macbook-pro/config.yaml - 模式: Host Mode (原生执行) - 容量: 2 并发任务 - 超时: 3h - -获取 Runner 注册 Token... - -尝试创建全局 Runner(可用于所有组织和仓库)... -✓ 使用全局 Runner -✓ 注册 Token 已准备 - -注册 Runner 到 Gitea 服务器... -✓ Runner 注册成功 - -启动 Runner... - 进程已启动 (PID: 12345) - 等待初始化... -✓ Runner 运行中 - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -✅ Runner 创建完成! -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Runner 信息: - 名称: runner-macbook-pro - 级别: global - 模式: Host Mode (原生执行) - 状态: 🟢 运行中 - PID: 12345 - -配置: - 容量: 2 并发任务 - 超时: 3h - Labels: self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host - -目录: - 配置文件: /Users/voson/.config/gitea/runners/runner-macbook-pro/config.yaml - 注册信息: /Users/voson/.config/gitea/runners/runner-macbook-pro/.runner - 工作目录: /Users/voson/.config/gitea/runners/runner-macbook-pro/workspace - 缓存目录: /Users/voson/.config/gitea/runners/runner-macbook-pro/cache - 日志文件: /Users/voson/.config/gitea/runners/runner-macbook-pro/runner.log - -管理命令: - 查看日志: tail -f /Users/voson/.config/gitea/runners/runner-macbook-pro/runner.log - 停止 Runner: pkill -f 'act_runner daemon --config.*runner-macbook-pro' - 查看所有: /gitea-list-runners - 删除 Runner: /gitea-delete-runner - -使用 Runner: - 在 workflow 中使用以下任一 runs-on 值: - - runs-on: darwin-arm64 - - runs-on: macOS - - runs-on: [self-hosted, macOS, ARM64] -``` - -### Example 2: Auto-install act_runner - -``` -检查 act_runner 安装状态... -⚠️ act_runner 未安装 -正在使用 Homebrew 安装... -==> Downloading act_runner... -==> Installing act_runner... -✓ act_runner 安装成功: act_runner version 0.2.13 - -[继续后续步骤...] -``` - -### Example 3: Downgrade to Organization Runner - -``` -获取 Runner 注册 Token... - -尝试创建全局 Runner(可用于所有组织和仓库)... -⚠️ 全局 Runner 权限不足 (HTTP 403) - 全局 Runner 需要管理员 Token - -降级到组织 Runner... -使用默认组织: ai -✓ 组织 Runner Token 已获取 -✓ 注册 Token 已准备 - -[继续后续步骤...] - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -✅ Runner 创建完成! -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Runner 信息: - 名称: runner-macbook-pro - 级别: organization - 组织: ai - 模式: Host Mode (原生执行) - [...] -``` - -### Example 4: Configuration Not Found - -``` -检查 act_runner 安装状态... -✓ act_runner 已安装: act_runner version 0.2.13 - -❌ Gitea 配置不存在 - -请先初始化 Gitea 配置: - /gitea-reset - -或使用以下命令查看配置: - /gitea-config -``` - -### Example 5: Runner Already Exists - -``` -[前置检查...] - -生成 Runner 名称: runner-macbook-pro - (基于主机名: macbook-pro) - -❌ Runner 'runner-macbook-pro' 已存在 - 路径: /Users/voson/.config/gitea/runners/runner-macbook-pro - -选项: - 1. 使用其他名称: /gitea-create-runner <新名称> - 2. 删除现有 runner: /gitea-delete-runner - 3. 查看所有 runners: /gitea-list-runners -``` - -## Technical Notes - -- **默认模式**:Host Mode(支持 Android SDK、iOS 等原生工具) -- **自动安装**:使用 Homebrew 安装 act_runner -- **智能检测**:自动检测 OS 和架构,生成合适的 labels -- **优雅降级**:全局 runner 权限不足时自动降级到组织 runner -- **后台运行**:自动后台启动,日志记录到文件 -- **配置环境变量**: - - `GITEA_RUNNER_CAPACITY`: 并发任务数(默认 2) - - `GITEA_RUNNER_TIMEOUT`: 任务超时时间(默认 3h) -- **目录权限**:自动创建,权限继承用户默认权限 -- **进程管理**:使用 nohup 后台运行,支持系统重启后手动重启 - -## Related Commands - -- `/gitea-config`: 查看 Gitea 配置 -- `/gitea-reset`: 重置/初始化 Gitea 配置 -- `/gitea-list-runners`: 列出所有 runners -- `/gitea-delete-runner`: 删除指定 runner -- `/create-gitea-repo`: 创建 Gitea 仓库 - -## Safety Features - -- **配置验证**:检查必需的配置项 -- **目录冲突检测**:避免覆盖现有 runner -- **启动验证**:等待并验证进程启动成功 -- **错误提示**:清晰的错误信息和解决方案 -- **日志记录**:所有输出记录到日志文件 - -## Version - -- **Command Version**: 1.0 -- **Last Updated**: 2026-01-12 -- **Compatible with**: act_runner 0.2.13+, macOS/Linux diff --git a/command/gitea-delete-runner.md b/command/gitea-delete-runner.md deleted file mode 100644 index cffdc7f..0000000 --- a/command/gitea-delete-runner.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -description: 删除 Gitea Runner 配置(交互式) -agent: general -subtask: true ---- - -Delete Gitea runner configuration with interactive selection. This command requires multiple user interactions. - -**Important:** This is an interactive command. Wait for user input at each step before proceeding. - -## 工作目录 - -**macOS / Linux:** -``` -~/.config/gitea/ -``` - -**Windows:** -``` -%USERPROFILE%\.config\gitea\ -``` - -所有 Runner 配置、进程管理都基于此目录。 - -Please perform the following steps: - -## Step 1: Load Configuration and Fetch Runners - -1. **Load Gitea configuration:** - -**macOS / Linux:** -```bash -source ~/.config/gitea/config.env -``` - -**Windows PowerShell:** -```powershell -Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object { - if ($_ -match '^([^=]+)=(.*)$') { - [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') - } -} -``` - - - Validate `GITEA_URL` and `GITEA_TOKEN` exist - -2. **Fetch global runners from Gitea server:** - - API: `GET ${GITEA_URL}/api/v1/admin/actions/runners` - - Requires admin permissions - - If fails: show error and check token permissions - -3. **Display runners list in Chinese:** -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Gitea 全局 Runners (共 N 个) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - 1. [runner-name] [ID: XX] 🟢 在线/🔴 离线 - 2. [runner-name] [ID: XX] 🟢 在线/🔴 离线 -... - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -选择要删除的 Runner -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - 输入序号: 删除单个 runner - 输入 'all': 删除所有 runners - 输入 'q' 或 'quit': 取消 -``` - -4. **Wait for user selection** → Do NOT proceed until user responds - -## Step 2: Process User Selection - -Based on user input: -- If `q` or `quit`: Cancel and exit -- If `all`: Prepare to delete all runners -- If number: Validate and prepare to delete that runner - -## Step 3: Display Warning and Wait for Confirmation - -Display deletion warning in Chinese: -``` -⚠️ 警告: 此操作将执行以下操作: - - 从 Gitea 服务器注销 runner - - 停止本地运行的 runner 进程 - - 删除 runner 配置文件 - - 删除 cache 和 workspace 目录 - - 删除所有相关数据 - -将删除以下 runners: - - [list of runners to be deleted] - -确认删除? 输入 'yes' 继续: -``` - -**Wait for user confirmation** → Do NOT proceed until user types 'yes' - -## Step 4: Execute Deletion - -If user confirmed with 'yes', for each selected runner: - -### 4.1 Unregister from Gitea Server -```bash -DELETE ${GITEA_URL}/api/v1/admin/actions/runners/${runner_id} -``` -- Expected: HTTP 204 -- Show: "✓ 已从服务器注销" or "⚠️ 注销失败" - -### 4.2 Stop Local Process -1. Find local runner directory by matching ID in `.runner` file -2. Check if process is running: `pgrep -f "act_runner daemon --config ..."` -3. If running: - - Check if runner is busy (executing jobs) via API - - **If busy, wait for user choice:** - ``` - ⚠️ 警告: Runner 正在执行 job! - 选项: - 1. 等待 job 完成后再停止(推荐) - 2. 强制立即停止 - ``` - - **Wait for user input** → Proceed based on choice - - If waiting: Poll status every 10 seconds, max 5 minutes - - Stop process: `kill $pid` (graceful), then `kill -9 $pid` if needed (force) - -### 4.3 Delete Local Directory - -**macOS / Linux:** -```bash -rm -rf ~/.config/gitea/runners/[runner_name] -``` - -**Windows PowerShell:** -```powershell -Remove-Item -Path "$env:USERPROFILE\.config\gitea\runners\[runner_name]" -Recurse -Force -``` - -## Step 5: Display Result - -Show completion summary in Chinese: -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -删除完成 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -成功: N 个 -失败: M 个 (if any) - -管理命令: - 查看剩余 runners: /gitea-list-runners - 创建新 runner: /gitea-create-runner -``` - ---- - -## Key Points - -**Interactive checkpoints (wait for user input):** -1. Step 1: After displaying runners list → Wait for selection -2. Step 3: After displaying warning → Wait for confirmation ('yes') -3. Step 4.2: If runner is busy → Wait for stop choice (1 or 2) - -**Safety features:** -- Double confirmation required -- Busy status detection -- Graceful stop before force kill -- Three-step deletion process -- Clear status reporting - -**Technical notes:** -- Requires `jq` for JSON parsing -- Requires admin token for global runners -- Uses temporary file `/tmp/gitea_runners.txt` for data passing -- Cleanup temp file after completion diff --git a/command/gitea-list-runners.md b/command/gitea-list-runners.md deleted file mode 100644 index ef061dd..0000000 --- a/command/gitea-list-runners.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -description: 列出 Gitea 服务器上的所有全局 Runner ---- - -List all global runners registered on the Gitea server. - -## 工作目录 - -**macOS / Linux:** -``` -~/.config/gitea/ -``` - -**Windows:** -``` -%USERPROFILE%\.config\gitea\ -``` - -Please perform the following: - -1. **Read Gitea configuration:** - - Read from config file: - - macOS/Linux: `~/.config/gitea/config.env` - - Windows: `%USERPROFILE%\.config\gitea\config.env` - - Extract: - - `GITEA_URL`: Gitea server URL - - `GITEA_TOKEN`: API token (admin permission required) - - If config not found: prompt user to run `/gitea-reset` first - -2. **Call Gitea API to list runners:** -```bash -curl -s -H "Authorization: token " \ - "/api/v1/admin/actions/runners" -``` - -3. **Parse JSON response and extract information:** - - Response structure: - ```json - { - "runners": [...], - "total_count": 1 - } - ``` - - Use `jq` to parse JSON - - For each runner in `runners` array: - - `id`: Runner ID - - `name`: Runner name - - `status`: Runner status ("online"/"offline") - - `busy`: Whether runner is currently busy (true/false) - - `ephemeral`: Whether runner is ephemeral (true/false) - - `labels`: Array of label objects with `name` and `type` - -4. **Determine runner status:** - - 🟢 在线 - `status: "online"` - - 🔴 离线 - `status: "offline"` - - ⚠️ 未知 - Unable to determine - -5. **Filter global runners:** - - The API endpoint `/api/v1/admin/actions/runners` returns all global runners - - These are runners registered at the instance level (not org or repo specific) - -6. **Display summary in Chinese:** -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Gitea 全局 Runners -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -服务器: [server_url] -总计: N 个全局 runner - -[runner-name] - 状态: 🟢/🔴 [在线/离线] - ID: [id] - 忙碌: 是/否 - 临时: 是/否 - 标签: [comma-separated labels] - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -管理命令 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - 查看配置: /gitea-config - 创建 runner: /gitea-create-runner - 删除 runner: /gitea-delete-runner -``` - -**Notes:** -- Requires admin API token to list runners -- **Correct API endpoint**: `/api/v1/admin/actions/runners` (not `/api/v1/admin/runners`) -- Only shows global runners (instance-level runners) -- Uses `jq` for JSON parsing -- Response includes: `id`, `name`, `status`, `busy`, `ephemeral`, `labels` -- If API call fails, show error message and suggest checking token permissions -- Tested with Gitea version 1.25.3 diff --git a/command/review.md b/command/review.md deleted file mode 100644 index 74e4617..0000000 --- a/command/review.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -description: 审查代码或文档并提供建议 -agent: plan ---- - -Review the code or documentation and provide detailed feedback. - -Please perform the following: - -1. **Review** the code or documentation mentioned by the user -2. **Identify issues** and areas for improvement -3. **Provide suggestions** with clear explanations -4. **Ask for confirmation** before making modifications - -If the user hasn't specified what to review, ask them to provide the code or documentation they want reviewed. - -When suggesting changes: -- Explain why each change is needed -- Prioritize suggestions by importance -- Ask if the user wants all changes applied or only specific ones diff --git a/command/summarize-conversation.md b/command/summarize-conversation.md deleted file mode 100644 index 1d12314..0000000 --- a/command/summarize-conversation.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -description: 归纳总结当前对话中有价值的内容,生成 Markdown 文件以便后续参考 -agent: general ---- - -# 对话内容总结 - -你的任务是归纳总结当前对话中有价值的内容,生成一个结构化的 Markdown 文件,方便后续与 AI 对话时快速回顾,避免重复查询。 - -## 总结内容 - -请从对话历史中提取以下信息: - -1. **对话主题** - 用户的主要需求和目标 -2. **关键决策** - 用户做出的重要选择、确定的技术方案 -3. **代码更改** - 创建、修改或删除的代码文件及核心逻辑 -4. **配置更新** - 环境变量、配置文件、依赖项变更 -5. **待办事项** - 用户明确提到的未来任务或计划 -6. **下一步行动** - 建议的后续步骤 -7. **重要注意事项** - 需要特别记住的细节、限制条件 -8. **相关文件路径** - 涉及的重要文件位置(格式:`文件路径:行号`) - -## 生成文件 - -1. **默认文件名**:`conversation-summary.md` -2. **文件位置**:当前工作目录 -3. **文件格式**:使用 Markdown 语法,包含清晰的标题和列表 -4. **时间戳**:在文件开头添加生成时间(格式:YYYY-MM-DD HH:MM:SS) -5. **对话上下文**:简要描述对话的背景和目的 - -## 执行步骤 - -1. **分析对话** - 回顾完整的对话历史,识别有价值的信息点 -2. **提取内容** - 按照上述分类整理信息,确保准确性和完整性 -3. **生成总结** - 创建结构化的 Markdown 内容,使用中文描述 -4. **保存文件** - 将总结写入 `conversation-summary.md` 文件 -5. **验证内容** - 检查文件是否包含所有关键信息 -6. **通知用户** - 告知用户文件已生成,并提供文件路径 - -## 注意事项 - -- 只总结**有价值**的内容,忽略闲聊和无关信息 -- 保持总结简洁明了,便于快速查阅 -- 涉及代码时,提供文件路径和关键行号引用 -- 如果有未完成的任务,明确标注状态(待处理/进行中/已完成) -- 如果对话中涉及敏感信息(如密码、密钥),**不要**包含在总结中 - -## 输出示例 - -``` -# 对话总结 - -**生成时间**: 2025-01-15 14:30:00 -**对话主题**: 创建 OpenCode 命令用于总结对话内容 - -## 关键决策 -- 命令名称: `summarize-conversation` -- 文件位置: 全局命令目录 (`~/.config/opencode/command/`) -- 代理类型: general - -## 代码更改 -- 创建命令文件: `command/summarize-conversation.md` - -## 配置更新 -- 无 - -## 待办事项 -- 测试命令功能:运行 `/summarize-conversation` -- 考虑添加文件命名参数支持 - -## 下一步行动 -1. 使用 `/summarize-conversation` 测试命令效果 -2. 根据使用反馈优化总结模板 - -## 重要注意事项 -- 总结文件保存在当前工作目录的 `conversation-summary.md` -- 每次运行会覆盖之前的总结文件 -- 建议定期备份重要总结 - -## 相关文件 -- `command/summarize-conversation.md` -``` - -**完成标准**:成功生成包含上述所有部分的 Markdown 文件,并通知用户文件位置。 \ No newline at end of file diff --git a/opencode.json b/opencode.json index 8d574fe..022a67c 100644 --- a/opencode.json +++ b/opencode.json @@ -21,7 +21,5 @@ "apiKey": "0f76aea86295476dbfa98724013b0fe8.o2EaJVqcl4Cf7WLP" } } - }, - "model": "deepseek/deepseek-resoner", - "small_model": "deepseek/deepseek-resoner" + } } diff --git a/skill/git/SKILL.md b/skill/git/SKILL.md index 9045eeb..12c4805 100644 --- a/skill/git/SKILL.md +++ b/skill/git/SKILL.md @@ -7,6 +7,13 @@ description: Git workflow best practices with commit conventions, tagging, and c You are an expert in Git version control and repository management. +## 功能文档 + +| 文档 | 说明 | +|------|------| +| [Commit Workflow](./commit-workflow.md) | 提交暂存文件,自动生成提交信息并创建版本标签 | +| [Push Workflow](./push-workflow.md) | 提交并推送到远程仓库的完整工作流 | + ## Core Principles 1. **Default Main Branch**: Use `main` as the primary branch (not `master`) diff --git a/skill/git/commit-workflow.md b/skill/git/commit-workflow.md new file mode 100644 index 0000000..df48718 --- /dev/null +++ b/skill/git/commit-workflow.md @@ -0,0 +1,163 @@ +# Git Commit Workflow + +提交暂存文件,自动生成提交信息并创建版本标签的完整工作流。 + +## 概述 + +此工作流用于: +- 自动分析暂存区变更 +- 根据 Conventional Commits 规范生成提交信息 +- 检测项目类型并更新版本号 +- 创建语义化版本标签 + +## 执行步骤 + +### 步骤 1: 检查暂存区 + +```bash +git diff --cached --name-only +``` + +- 如果暂存区为空,通知用户并停止 +- 如果有文件,继续下一步 + +### 步骤 2: 收集信息(并行执行) + +```bash +# 并行执行以下命令 +git status +git diff --cached +git log --oneline -10 +git tag --list | sort -V | tail -5 +``` + +同时检查 `AGENTS.md` 文件获取: +- 仓库类型(polyrepo/monorepo) +- 版本规则 +- 项目结构信息 + +### 步骤 3: 检测仓库类型 + +**Polyrepo(单仓库)** +- Tag 格式:``(如 `1.2.0`) + +**Monorepo(多项目)** +- Tag 格式:`-`(如 `ios-1.2.0`) +- 检测特征:`packages/`、`apps/`、`services/` 目录 + +### 步骤 4: 检测项目类型和版本 + +| 项目类型 | 版本文件 | 版本字段 | +|---------|---------|---------| +| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` | +| Node.js | `package.json` | `version` | +| Android (Groovy) | `app/build.gradle` | `versionName` | +| Android (Kotlin) | `app/build.gradle.kts` | `versionName` | +| Go | Git tag only | - | +| Python | `pyproject.toml` / `setup.py` | `version` | +| Rust | `Cargo.toml` | `version` | + +### 步骤 5: 生成提交信息 + +遵循 Conventional Commits 格式: + +``` +(): +``` + +**提交类型**: + +| Type | 描述 | 版本影响 | +|------|------|---------| +| `feat` | 新功能 | minor +1 | +| `fix` | Bug 修复 | patch +1 | +| `perf` | 性能优化 | patch +1 | +| `BREAKING CHANGE` | 破坏性变更 | major +1 | +| `docs` | 文档更新 | 无 | +| `style` | 代码格式 | 无 | +| `refactor` | 重构 | 无 | +| `test` | 测试 | 无 | +| `chore` | 维护任务 | 无 | +| `ci` | CI/CD 变更 | 无 | +| `build` | 构建配置 | 无 | + +**提交语言**: +- macOS/Linux:使用中文 +- Windows:使用英文(避免编码问题) + +**Monorepo Scope**: +- 单项目变更:`feat(ios): 添加上传功能` +- 多项目变更:`chore: 更新共享依赖` + +### 步骤 6: 确定新版本号 + +根据提交类型计算新版本: + +**版本递增规则**: +- `feat`:minor +1(如 `1.2.0` → `1.3.0`) +- `fix`/`perf`:patch +1(如 `1.2.3` → `1.2.4`) +- Breaking change:major +1(如 `1.2.3` → `2.0.0`) + +**不更新版本**: +- `docs`、`test`、`refactor`、`style`、`build`、`ci`、`chore` + +### 步骤 7: 更新版本文件并暂存 + +如果需要更新版本(步骤 6 确定了新版本号): + +1. **更新版本文件**:将版本号写入对应的版本文件 +2. **添加到暂存区**: + ```bash + git add + ``` +3. **验证暂存**: + ```bash + git diff --cached --name-only + ``` + 确认版本文件已在暂存区 + +### 步骤 8: 执行提交 + +```bash +git commit -m "" +``` + +### 步骤 9: 创建版本标签 + +仅在版本更新时创建(除非用户指定 "skip tag"): + +**Polyrepo**: +```bash +git tag -a "1.2.0" -m "" +``` + +**Monorepo**: +```bash +git tag -a "ios-1.2.0" -m "" +``` + +## 选项 + +- `skip tag` / `skip`:跳过标签创建 + +## 输出格式 + +``` +✓ 提交成功 + +提交信息:[commit message] +版本标签:[tag](如果创建了) + +要推送到远程仓库,请运行:/git-push +``` + +## 注意事项 + +- 此命令**不会推送**到远程,使用 `/git-push` 推送 +- 暂存区为空时会提示用户先 `git add` +- 标签注释使用与提交相同的消息内容 + +## 相关文档 + +- [Git Workflow Best Practices](./SKILL.md) +- [Push Workflow](./push-workflow.md) diff --git a/skill/git/push-workflow.md b/skill/git/push-workflow.md new file mode 100644 index 0000000..1906cf7 --- /dev/null +++ b/skill/git/push-workflow.md @@ -0,0 +1,107 @@ +# Git Push Workflow + +提交暂存文件,创建版本标签并推送到远程仓库的完整工作流。 + +## 概述 + +此工作流是 **All-in-One** 命令,组合了: +- `/git-commit` 的所有功能 +- 推送提交到远程 +- 推送标签到远程 + +## 执行步骤 + +### 步骤 1-9: 与 Commit Workflow 相同 + +参考 [Commit Workflow](./commit-workflow.md): + +1. 检查暂存区(不能为空) +2. 收集变更信息和仓库状态 +3. 检测仓库类型(polyrepo/monorepo) +4. 检测项目类型和版本 +5. 生成提交信息(Conventional Commits,中文) +6. 确定新版本号 +7. 更新版本文件并添加到暂存区 +8. 执行提交 +9. 创建版本标签 + +### 步骤 10: 推送提交到远程 + +```bash +git push origin $(git branch --show-current) +``` + +### 步骤 11: 推送标签到远程 + +仅在创建了标签时执行: + +**Polyrepo**: +```bash +git push origin +``` + +**Monorepo**: +```bash +git push origin - +``` + +## 选项 + +- `skip tag` / `skip`:跳过标签创建 + +## 输出格式 + +``` +✓ 提交并推送成功 + +分支:[branch] +提交信息:[commit message] +版本标签:[tag](如果创建了) + +已推送到远程仓库:origin +- 提交:[commit hash] +- 标签:[tag] +``` + +## 错误处理 + +### 暂存区为空 + +``` +暂存区为空,请先使用 `git add` 添加文件。 +``` + +### 推送失败 + +``` +❌ 推送失败:[error message] + +可能的解决方案: +1. 先拉取远程变更:git pull origin +2. 检查网络连接 +3. 检查远程仓库权限 +``` + +### 标签已存在 + +``` +❌ 标签推送失败:tag already exists + +解决方案: +1. 删除本地标签:git tag -d +2. 更新版本号后重新提交 +``` + +## 使用场景 + +| 场景 | 推荐命令 | +|------|---------| +| 本地提交,稍后审查 | `/git-commit` | +| 提交并立即推送 | `/git-push` | +| 仅推送已有提交 | `git push origin ` | +| 仅推送标签 | `git push origin ` | + +## 相关文档 + +- [Git Workflow Best Practices](./SKILL.md) +- [Commit Workflow](./commit-workflow.md) diff --git a/skill/git/quick-reference.md b/skill/git/quick-reference.md deleted file mode 100644 index 66ade91..0000000 --- a/skill/git/quick-reference.md +++ /dev/null @@ -1,663 +0,0 @@ -# Git Quick Reference - -Quick reference guide for common Git operations. - -## File Changes and Status - -### View Changed Files - -```bash -# Show working directory status -git status - -# Show short status -git status -s - -# List changed files only (unstaged) -git diff --name-only - -# List changed files only (staged) -git diff --cached --name-only -# or -git diff --staged --name-only - -# Show file change statistics -git diff --stat -git diff --cached --stat -``` - -### View Detailed Changes - -```bash -# View unstaged changes -git diff - -# View staged changes -git diff --cached -# or -git diff --staged - -# View specific file changes -git diff -git diff --cached - -# View changes between commits -git diff .. -git diff HEAD~1..HEAD - -# View changes between branches -git diff main..feature-branch -``` - -## Staging and Committing - -### Add Files to Staging - -```bash -# Add specific file -git add - -# Add all files in directory -git add . - -# Add all files in repository -git add -A - -# Add files interactively -git add -p - -# Add only modified files (not new files) -git add -u -``` - -### Check Staging Area - -```bash -# List files in staging area -git diff --cached --name-only - -# Show detailed staged changes -git diff --cached -``` - -### Commit Changes - -```bash -# Simple commit -git commit -m "feat: add user authentication" - -# Multi-line commit (macOS/Linux) -git commit -m "$(cat <<'EOF' -feat: add user authentication - -- Add OAuth2 support -- Implement JWT tokens -- Add login/logout endpoints -EOF -)" - -# Multi-line commit (Windows) -git commit -m "feat: add user authentication" \ - -m "" \ - -m "- Add OAuth2 support" \ - -m "- Implement JWT tokens" \ - -m "- Add login/logout endpoints" - -# Commit with automatic staging -git commit -am "fix: resolve issue" - -# Amend last commit (before push only!) -git commit --amend -m "new message" -``` - -## Tag Management - -### Create Tags - -```bash -# Create annotated tag -git tag -a "1.2.0" -m "feat: add new feature" - -# Create lightweight tag -git tag "1.2.0" - -# Create tag with multi-line message -git tag -a "1.2.1" \ - -m "fix: resolve connection issue" \ - -m "" \ - -m "- Increase timeout to 30s" \ - -m "- Add retry mechanism" - -# Create tag for specific commit -git tag -a "1.2.0" -m "message" - -# Monorepo tag -git tag -a "ios-1.2.0" -m "feat(ios): add feature" -``` - -### List Tags - -```bash -# List all tags -git tag - -# List tags with pattern -git tag -l "v1.*" - -# List recent tags (sorted) -git tag --list | sort -V | tail -5 - -# Show tag details -git show -``` - -### Push Tags - -```bash -# Push single tag -git push origin - -# Push all tags -git push --tags -# or -git push origin --tags - -# Push commit and tag together -git push origin main && git push origin 1.2.0 -``` - -### Delete Tags - -```bash -# Delete local tag -git tag -d - -# Delete remote tag -git push origin --delete -# or -git push origin :refs/tags/ - -# Delete multiple tags -git tag -d tag1 tag2 tag3 -``` - -## Branch Operations - -### View Branches - -```bash -# Show current branch -git branch --show-current - -# List local branches -git branch - -# List all branches (local + remote) -git branch -a - -# List remote branches only -git branch -r - -# Show branch with last commit -git branch -v -``` - -### Create and Switch Branches - -```bash -# Create new branch -git branch - -# Create and switch to new branch (old way) -git checkout -b - -# Create and switch to new branch (modern) -git switch -c - -# Switch to existing branch (old way) -git checkout - -# Switch to existing branch (modern) -git switch - -# Switch to previous branch -git switch - -``` - -### Delete Branches - -```bash -# Delete local branch (safe) -git branch -d - -# Delete local branch (force) -git branch -D - -# Delete remote branch -git push origin --delete -# or -git push origin : -``` - -## Pushing and Pulling - -### Push Changes - -```bash -# Push current branch -git push - -# Push to specific remote and branch -git push origin main - -# Push current branch to remote -git push origin $(git branch --show-current) - -# Push with upstream tracking -git push -u origin - -# Push all branches -git push --all - -# Push all tags -git push --tags - -# Force push (dangerous!) -git push --force -# Better: force push with lease -git push --force-with-lease -``` - -### Pull Changes - -```bash -# Pull from tracked remote -git pull - -# Pull from specific remote and branch -git pull origin main - -# Pull with rebase -git pull --rebase - -# Pull and prune deleted remote branches -git pull --prune -``` - -### Fetch Changes - -```bash -# Fetch from all remotes -git fetch - -# Fetch from specific remote -git fetch origin - -# Fetch and prune deleted remote branches -git fetch --prune - -# Fetch all branches and tags -git fetch --all --tags -``` - -## History and Logs - -### View Commit History - -```bash -# View recent commits -git log - -# View compact history -git log --oneline - -# View recent 10 commits -git log --oneline -10 - -# View history with graph -git log --graph --oneline --all - -# View history with stats -git log --stat - -# View history with patches -git log -p -``` - -### Search History - -```bash -# Search commits by message -git log --grep="feature" - -# Search by author -git log --author="John" - -# Search by date -git log --since="2024-01-01" -git log --after="2 weeks ago" -git log --before="yesterday" - -# Search by file -git log -- - -# Search code changes -git log -S "function_name" -``` - -### View Commit Details - -```bash -# Show specific commit -git show - -# Show specific tag -git show - -# Show HEAD commit -git show HEAD - -# Show previous commit -git show HEAD~1 -git show HEAD^ -``` - -## Undoing Changes - -### Discard Changes - -```bash -# Discard unstaged changes in file -git checkout -- -# or (modern) -git restore - -# Discard all unstaged changes -git checkout -- . -# or (modern) -git restore . - -# Unstage file (keep changes) -git reset HEAD -# or (modern) -git restore --staged - -# Unstage all files -git reset HEAD -# or (modern) -git restore --staged . -``` - -### Reset Commits - -```bash -# Undo last commit, keep changes staged -git reset --soft HEAD~1 - -# Undo last commit, keep changes unstaged -git reset HEAD~1 -# or -git reset --mixed HEAD~1 - -# Undo last commit, discard changes (dangerous!) -git reset --hard HEAD~1 - -# Reset to specific commit -git reset --hard -``` - -### Revert Commits - -```bash -# Create new commit that undoes a commit -git revert - -# Revert without committing -git revert -n - -# Revert multiple commits -git revert .. -``` - -## Stash Operations - -### Save Changes - -```bash -# Stash current changes -git stash - -# Stash with message -git stash save "work in progress" - -# Stash including untracked files -git stash -u - -# Stash including untracked and ignored files -git stash -a -``` - -### Apply Stash - -```bash -# Apply most recent stash -git stash apply - -# Apply and remove from stash list -git stash pop - -# Apply specific stash -git stash apply stash@{2} -``` - -### Manage Stash - -```bash -# List all stashes -git stash list - -# Show stash changes -git stash show -git stash show -p - -# Drop specific stash -git stash drop stash@{1} - -# Clear all stashes -git stash clear -``` - -## Remote Operations - -### View Remotes - -```bash -# List remotes -git remote - -# List remotes with URLs -git remote -v - -# Show remote details -git remote show origin -``` - -### Manage Remotes - -```bash -# Add remote -git remote add - -# Remove remote -git remote remove - -# Rename remote -git remote rename - -# Change remote URL -git remote set-url -``` - -## Configuration - -### View Configuration - -```bash -# View all config -git config --list - -# View global config -git config --global --list - -# View local config -git config --local --list - -# View specific config -git config user.name -git config user.email -``` - -### Set Configuration - -```bash -# Set user name -git config --global user.name "Your Name" - -# Set user email -git config --global user.email "your.email@example.com" - -# Set default branch name -git config --global init.defaultBranch main - -# Set default editor -git config --global core.editor "code --wait" - -# Set credential helper -git config --global credential.helper store -``` - -## Workflow Examples - -### Standard Commit and Tag Workflow - -```bash -# 1. Check status -git status -git diff --cached --name-only - -# 2. Stage changes -git add . - -# 3. Commit -git commit -m "feat: add user authentication" - -# 4. Create tag -git tag -a "1.2.0" -m "feat: add user authentication" - -# 5. Push commit and tag -git push origin main -git push origin 1.2.0 -``` - -### Complete Staging to Push Workflow - -```bash -# Check what files changed -git status - -# View changes -git diff - -# Stage specific files -git add src/auth.js src/api.js - -# Verify staging -git diff --cached --name-only - -# Commit with message -git commit -m "feat: implement OAuth2 authentication" - -# Push to remote -git push origin main -``` - -### Push All Tags Workflow - -```bash -# List local tags -git tag - -# View recent tags -git tag --list | sort -V | tail -5 - -# Push all tags to remote -git push --tags - -# Verify tags on remote -git ls-remote --tags origin -``` - -### Quick Status Check - -```bash -# Full status -git status - -# Changed files only -git diff --name-only -git diff --cached --name-only - -# Recent commits and tags -git log --oneline -5 -git tag --list | sort -V | tail -5 - -# Current branch -git branch --show-current -``` - -## Tips and Tricks - -### Aliases - -Add to `~/.gitconfig`: - -```ini -[alias] - st = status - co = checkout - br = branch - ci = commit - unstage = restore --staged - last = log -1 HEAD - lg = log --graph --oneline --all - tags = tag -l --sort=-v:refname -``` - -Usage: -```bash -git st -git co main -git lg -``` - -### Useful One-Liners - -```bash -# Delete all merged branches -git branch --merged | grep -v "\*" | xargs -n 1 git branch -d - -# View file in specific commit -git show : - -# Count commits by author -git shortlog -sn - -# Find when a line was changed -git blame - -# Show what changed in each commit for a file -git log -p - -# List files in a commit -git diff-tree --no-commit-id --name-only -r -``` diff --git a/skill/gitea/SKILL.md b/skill/gitea/SKILL.md index f441f0a..17c87f6 100644 --- a/skill/gitea/SKILL.md +++ b/skill/gitea/SKILL.md @@ -58,6 +58,7 @@ C:\Users\YourUsername\.config\gitea\ |---------|------|------| | 环境配置 | [setup-guide.md](./setup-guide.md) | 首次使用引导,配置 Gitea URL 和 Token | | Runner 管理 | [runner-management.md](./runner-management.md) | 创建、注册、管理 Gitea Act Runner | +| 自动创建脚本 | [create-runner.md](./create-runner.md) | 包含完整的 Runner 创建 Bash 脚本 | | Workflow 生成 | [workflow-generator.md](./workflow-generator.md) | 根据项目类型生成 CI/CD workflow | | 仓库操作 | [repository-operations.md](./repository-operations.md) | 创建和配置 Gitea 仓库 | | API 参考 | [api-reference.md](./api-reference.md) | Gitea API 常用接口 | diff --git a/skill/gitea/create-runner.md b/skill/gitea/create-runner.md new file mode 100644 index 0000000..073aafc --- /dev/null +++ b/skill/gitea/create-runner.md @@ -0,0 +1,416 @@ +--- +description: 创建并启动 Gitea Actions Runner 的完整脚本 +agent: general +--- + +# Create Runner Script + +本文档包含用于创建 Gitea Actions Runner 的完整 Bash 脚本。该脚本支持 Host 模式和 Docker 模式。 + +## 脚本文件 + +你可以将以下内容保存为 `create_runner.sh` 并赋予执行权限 (`chmod +x create_runner.sh`)。 + +```bash +#!/bin/bash + +# Gitea Runner Creation Script +# Generated by OpenCode Skill + +set -e + +# ========================================== +# 1. Choose Mode & Check Dependencies +# ========================================== + +echo "请选择 Runner 运行模式:" +echo " 1. Host Mode (直接在宿主机运行,支持 macOS/iOS 原生构建)" +echo " 2. Docker Mode (在容器中运行,环境隔离,适合标准 Linux 构建)" +echo "" +read -p "请输入选项 [1/2] (默认 1): " mode_choice + +if [ "$mode_choice" = "2" ]; then + RUNNER_MODE="docker" + echo "✅ 已选择: Docker Mode" +else + RUNNER_MODE="host" + echo "✅ 已选择: Host Mode" +fi +echo "" + +# Check dependencies based on mode +if [ "$RUNNER_MODE" = "host" ]; then + echo "检查 act_runner 安装状态..." + if command -v act_runner &> /dev/null; then + version=$(act_runner --version 2>&1 | head -n1) + echo "✓ act_runner 已安装: $version" + else + echo "⚠️ act_runner 未安装" + echo "正在使用 Homebrew 安装..." + if ! command -v brew &> /dev/null; then + echo "❌ 需要先安装 Homebrew" + exit 1 + fi + brew install act_runner + if [ $? -eq 0 ]; then + echo "✓ act_runner 安装成功" + else + echo "❌ act_runner 安装失败" + exit 1 + fi + fi +else + # Docker mode checks + echo "检查 Docker 环境..." + if command -v docker &> /dev/null; then + if docker info &> /dev/null; then + docker_ver=$(docker --version) + echo "✓ Docker 已安装并运行: $docker_ver" + else + echo "❌ Docker 已安装但未运行" + echo " 请启动 Docker Desktop" + exit 1 + fi + else + echo "❌ Docker 未安装" + echo " Docker 模式需要预先安装 Docker" + echo " 请访问 https://www.docker.com/products/docker-desktop/ 下载安装" + exit 1 + fi +fi +echo "" + +# ========================================== +# 2. Load Gitea Configuration +# ========================================== + +config_file="$HOME/.config/gitea/config.env" + +if [ ! -f "$config_file" ]; then + echo "❌ Gitea 配置不存在,请先运行 /gitea-reset" + exit 1 +fi + +source "$config_file" + +if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then + echo "❌ Gitea 配置不完整 (缺少 URL 或 TOKEN)" + echo " 请运行 /gitea-reset 重新配置" + exit 1 +fi + +echo "✓ 已加载 Gitea 配置: $GITEA_URL" +echo "" + +# ========================================== +# 3. Generate Runner Name +# ========================================== + +if [ -n "$1" ]; then + runner_name="$1" + echo "使用指定的 Runner 名称: $runner_name" +else + hostname=$(hostname -s 2>/dev/null || echo "unknown") + runner_name="runner-$hostname-$RUNNER_MODE" + echo "生成 Runner 名称: $runner_name" +fi + +if [[ ! "$runner_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then + echo "❌ Runner 名称无效 (仅限字母、数字、下划线、连字符)" + exit 1 +fi +echo "" + +# ========================================== +# 4. Check Runner Existence +# ========================================== + +runners_dir="$HOME/.config/gitea/runners" +runner_dir="$runners_dir/$runner_name" + +if [ "$RUNNER_MODE" = "host" ]; then + if [ -d "$runner_dir" ]; then + echo "❌ Runner 目录已存在: $runner_dir" + echo " 请使用 /gitea-delete-runner 删除旧 Runner 或指定新名称" + exit 1 + fi +else + # Docker mode: check directory AND container + if [ -d "$runner_dir" ]; then + echo "❌ Runner 配置目录已存在: $runner_dir" + exit 1 + fi + if docker ps -a --format '{{.Names}}' | grep -q "^${runner_name}$"; then + echo "❌ Docker 容器已存在: $runner_name" + echo " 请先删除旧容器: docker rm -f $runner_name" + exit 1 + fi +fi + +# ========================================== +# 5. Detect System Environment & Labels +# ========================================== + +echo "生成 Labels..." + +if [ "$RUNNER_MODE" = "host" ]; then + OS=$(uname -s) + case "$OS" in + Darwin) os_label="macOS" ;; + Linux) os_label="ubuntu" ;; + *) os_label="unknown" ;; + esac + + ARCH=$(uname -m) + case "$ARCH" in + arm64|aarch64) arch_label="ARM64" ;; + x86_64) arch_label="x64" ;; + *) arch_label="unknown" ;; + esac + + combined=$(echo "${OS}-${ARCH}" | tr '[:upper:]' '[:lower:]') + labels="self-hosted:host,${os_label}:host,${arch_label}:host,${combined}:host" + +else + # Docker mode uses standard labels mapping to images + # Format: label:docker://image + labels="ubuntu-latest:docker://node:16-bullseye,ubuntu-22.04:docker://node:16-bullseye,ubuntu-20.04:docker://node:16-buster,linux:docker://node:16-bullseye" +fi + +echo "✓ Labels ($RUNNER_MODE):" +echo " $labels" +echo "" + +# ========================================== +# 6. Create Runner Directory +# ========================================== + +echo "创建 Runner 目录..." +mkdir -p "$runner_dir"/{cache,workspace} +if [ "$RUNNER_MODE" = "docker" ]; then + # Docker mode might strictly need data dir mapping + mkdir -p "$runner_dir/data" +fi +echo "✓ 目录: $runner_dir" +echo "" + +# ========================================== +# 7. Get Registration Token +# ========================================== + +echo "正在获取 Runner 注册 Token..." + +# 默认尝试全局 Runner(管理员权限) +echo "尝试创建全局 Runner(可用于所有组织和仓库)..." + +response=$(curl -s -w "\n%{http_code}" \ + -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_URL}/api/v1/admin/runners/registration-token") + +http_code=$(echo "$response" | tail -n1) +body=$(echo "$response" | sed '$d') + +# 如果全局 Runner 失败(权限不足),降级到组织 Runner +if [ "$http_code" != "200" ]; then + echo "⚠️ 全局 Runner 权限不足 (HTTP $http_code)" + echo " 全局 Runner 需要管理员 Token" + echo "" + echo "降级到组织 Runner..." + + runner_level="organization" + + if [ -n "$GITEA_DEFAULT_ORG" ]; then + org_name="$GITEA_DEFAULT_ORG" + else + read -p "请输入组织名称: " org_input + if [ -z "$org_input" ]; then + echo "❌ 必须指定组织名称" + exit 1 + fi + org_name="$org_input" + fi + + echo "使用组织: $org_name" + + response=$(curl -s -w "\n%{http_code}" -X POST \ + -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_URL}/api/v1/orgs/$org_name/actions/runners/registration-token") + + http_code=$(echo "$response" | tail -n1) + body=$(echo "$response" | sed '$d') +else + echo "✓ 使用全局 Runner" + runner_level="global" +fi + +if [ "$http_code" != "200" ]; then + echo "❌ 获取注册 Token 失败 (HTTP $http_code)" + echo "$body" + exit 1 +fi + +# Need jq for parsing json +if ! command -v jq &> /dev/null; then + # Simple grep fallback if jq not available, but jq is better + registration_token=$(echo "$body" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) +else + registration_token=$(echo "$body" | jq -r '.token') +fi + +if [ -z "$registration_token" ]; then + echo "❌ 无法解析注册 Token" + exit 1 +fi + +echo "✓ 注册 Token 已获取" +echo "" + +# ========================================== +# 8. Start Runner (Register & Run) +# ========================================== + +echo "启动 Runner..." + +if [ "$RUNNER_MODE" = "host" ]; then + # Host Mode Config + cat > "$runner_dir/config.yaml" << EOF +log: + level: info +runner: + file: .runner + capacity: 1 + timeout: 3h + shutdown_timeout: 30s + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: [] +cache: + enabled: true + dir: "$runner_dir/cache" + host: "127.0.0.1" + port: 0 +host: + workdir_parent: "$runner_dir/workspace" +EOF + + echo "注册 Host Runner..." + act_runner register \ + --config "$runner_dir/config.yaml" \ + --instance "$GITEA_URL" \ + --token "$registration_token" \ + --name "$runner_name" \ + --labels "$labels" \ + --no-interactive + + if [ $? -ne 0 ]; then + echo "❌ 注册失败" + exit 1 + fi + + echo "启动后台进程..." + nohup act_runner daemon --config "$runner_dir/config.yaml" \ + > "$runner_dir/runner.log" 2>&1 & + runner_pid=$! + sleep 3 + + if ps -p $runner_pid > /dev/null 2>&1; then + echo "✓ Host Runner 正在后台运行 (PID: $runner_pid)" + # Save PID + echo $runner_pid > "$runner_dir/pid" + else + echo "❌ 启动失败,请检查日志" + exit 1 + fi + +else + # Docker Mode + # Strategy: Use environment variables for auto-registration on startup + # This avoids the "Instance Address Empty" issue seen with 'act_runner register' inside containers + + cat > "$runner_dir/config.yaml" << EOF +log: + level: info +runner: + file: /data/.runner + capacity: 2 + timeout: 3h + shutdown_timeout: 30s + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: [] +cache: + enabled: true + dir: "/data/cache" + host: "host.docker.internal" + port: 9040 +container: + # 使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问 + network: "host" + privileged: false + options: + workdir_parent: /data/workspace + valid_volumes: [] + docker_host: "" + force_pull: false +host: + workdir_parent: /data/workspace +EOF + + echo "启动 Docker 容器 (自动注册)..." + + # 使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问 + docker run -d \ + --name "$runner_name" \ + --restart always \ + --network host \ + -v "$runner_dir/config.yaml:/config.yaml" \ + -v "$runner_dir/data:/data" \ + -v "/var/run/docker.sock:/var/run/docker.sock" \ + -e GITEA_INSTANCE_URL="$GITEA_URL" \ + -e GITEA_RUNNER_REGISTRATION_TOKEN="$registration_token" \ + -e GITEA_RUNNER_NAME="$runner_name" \ + -e GITEA_RUNNER_LABELS="$labels" \ + gitea/act_runner:latest daemon --config /config.yaml + + if [ $? -eq 0 ]; then + echo "✓ Docker Runner 容器已启动: $runner_name" + # 等待容器启动并查看日志 + sleep 5 + echo "容器日志:" + docker logs "$runner_name" 2>&1 | tail -20 + else + echo "❌ 容器启动失败" + exit 1 + fi +fi +echo "" + +# ========================================== +# 9. Display Summary +# ========================================== + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "✅ Runner 创建成功!" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "基本信息:" +echo " 名称: $runner_name" +echo " 模式: $RUNNER_MODE" +echo " 状态: 🟢 运行中" + +if [ "$RUNNER_MODE" = "host" ]; then + echo " PID: $runner_pid" + echo " 日志: $runner_dir/runner.log" + echo " 停止: kill \$(cat $runner_dir/pid)" +else + echo " 容器: $runner_name" + echo " 命令: docker logs -f $runner_name" + echo " docker stop $runner_name" +fi + +echo "" +echo "配置文件: $runner_dir/config.yaml" +echo "Labels: $labels" +echo "" +``` diff --git a/skill/gitea/delete-runner.md b/skill/gitea/delete-runner.md new file mode 100644 index 0000000..d48473c --- /dev/null +++ b/skill/gitea/delete-runner.md @@ -0,0 +1,303 @@ +--- +description: 交互式批量删除 Gitea Runners 脚本 +agent: general +--- + +# Delete Runner Script + +本文档包含用于交互式批量删除 Gitea Actions Runner 的完整 Bash 脚本。 + +## 功能特点 +- **多选支持**:支持输入多个序号(如 `1,3` 或 `1 3`)或 `all` 进行批量删除。 +- **双重清理**:同时从 Gitea 服务器注销 Runner 和删除本地配置/容器。 +- **智能识别**:自动关联远程 Runner 状态与本地 Runner 目录。 +- **安全检查**:删除前强制二次确认,防止误删。 + +## 脚本文件 + +你可以将以下内容保存为 `delete_runner.sh` 并赋予执行权限 (`chmod +x delete_runner.sh`)。 + +```bash +#!/bin/bash + +# Gitea Runner Deletion Script +# Generated by OpenCode Skill + +set -e + +# ========================================== +# 1. Setup & Config +# ========================================== + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Config +CONFIG_FILE="$HOME/.config/gitea/config.env" +RUNNERS_BASE_DIR="$HOME/.config/gitea/runners" + +if [ ! -f "$CONFIG_FILE" ]; then + echo -e "${RED}❌ 配置文件不存在: $CONFIG_FILE${NC}" + exit 1 +fi + +source "$CONFIG_FILE" + +if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then + echo -e "${RED}❌ 配置无效: 缺少 URL 或 Token${NC}" + exit 1 +fi + +# Check requirements +if ! command -v jq &> /dev/null; then + echo -e "${RED}❌ 需要安装 jq 工具来解析 JSON${NC}" + exit 1 +fi + +echo "正在获取 Runner 列表..." + +# ========================================== +# 2. Data Collection +# ========================================== + +# Temporary files +REMOTE_LIST=$(mktemp) +LOCAL_MAP=$(mktemp) +FINAL_LIST=$(mktemp) + +# 2.1 Fetch Remote Runners (Try Admin first, then Org) +# Note: Admin endpoint /api/v1/admin/runners lists all runners +HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REMOTE_LIST" \ + -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_URL}/api/v1/admin/runners?page=1&limit=100") + +if [ "$HTTP_CODE" != "200" ]; then + # Fallback to Org level if defined + if [ -n "$GITEA_DEFAULT_ORG" ]; then + HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REMOTE_LIST" \ + -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_URL}/api/v1/orgs/${GITEA_DEFAULT_ORG}/actions/runners?page=1&limit=100") + fi +fi + +if [ "$HTTP_CODE" != "200" ]; then + echo -e "${RED}❌ 无法获取 Runner 列表 (HTTP $HTTP_CODE)${NC}" + cat "$REMOTE_LIST" + rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST" + exit 1 +fi + +# 2.2 Scan Local Directories to map UUID -> Path +# We need to find which local directory corresponds to which runner ID/UUID +echo "{}" > "$LOCAL_MAP" + +if [ -d "$RUNNERS_BASE_DIR" ]; then + for d in "$RUNNERS_BASE_DIR"/*; do + if [ -d "$d" ]; then + # Check Host mode .runner + if [ -f "$d/.runner" ]; then + uuid=$(jq -r '.uuid' "$d/.runner" 2>/dev/null) + if [ -n "$uuid" ] && [ "$uuid" != "null" ]; then + # Add to JSON map + tmp=$(mktemp) + jq --arg uuid "$uuid" --arg path "$d" '.[$uuid] = $path' "$LOCAL_MAP" > "$tmp" && mv "$tmp" "$LOCAL_MAP" + fi + fi + + # Check Docker mode data/.runner + if [ -f "$d/data/.runner" ]; then + uuid=$(jq -r '.uuid' "$d/data/.runner" 2>/dev/null) + if [ -n "$uuid" ] && [ "$uuid" != "null" ]; then + tmp=$(mktemp) + jq --arg uuid "$uuid" --arg path "$d" '.[$uuid] = $path' "$LOCAL_MAP" > "$tmp" && mv "$tmp" "$LOCAL_MAP" + fi + fi + fi + done +fi + +# ========================================== +# 3. Display Interface +# ========================================== + +# Combine Remote and Local info +# Output format: index | id | name | status | local_path +jq -r --slurpfile local "$LOCAL_MAP" ' + .runners[] | + [.id, .uuid, .name, .status, ($local[0][.uuid] // "")] | + @tsv +' "$REMOTE_LIST" > "$FINAL_LIST" + +count=$(wc -l < "$FINAL_LIST" | tr -d ' ') + +if [ "$count" -eq 0 ]; then + echo "没有发现任何 Runners。" + rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST" + exit 0 +fi + +echo "" +echo -e "${YELLOW}Gitea Runners 列表 (共 $count 个)${NC}" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +printf "%-4s | %-8s | %-20s | %-10s | %-30s\n" "序号" "ID" "名称" "状态" "本地目录" +echo "----------------------------------------------------------------------------" + +i=1 +declare -a runner_ids +declare -a runner_names +declare -a runner_paths + +while IFS=$'\t' read -r id uuid name status local_path; do + status_icon="🔴" + if [ "$status" = "online" ] || [ "$status" = "idle" ] || [ "$status" = "active" ]; then + status_icon="🟢" + fi + + local_mark="" + if [ -n "$local_path" ]; then + local_mark="$(basename "$local_path")" + else + local_mark="-" + fi + + printf "%-4d | %-8s | %-20s | %s %-8s | %-30s\n" "$i" "$id" "${name:0:20}" "$status_icon" "$status" "$local_mark" + + runner_ids[$i]=$id + runner_names[$i]=$name + runner_paths[$i]=$local_path + + i=$((i+1)) +done < "$FINAL_LIST" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# ========================================== +# 4. User Selection +# ========================================== + +echo "请输入要删除的序号:" +echo " - 单个: 1" +echo " - 多选: 1,3,5 或 1 3 5" +echo " - 全部: all" +echo " - 退出: q" +echo "" +read -p "选择 > " selection + +if [[ "$selection" =~ ^[qQ] ]]; then + echo "已取消。" + rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST" + exit 0 +fi + +target_indices=() + +if [ "$selection" = "all" ]; then + for ((j=1; j<=count; j++)); do + target_indices+=($j) + done +else + # Replace commas with spaces and iterate + for idx in ${selection//,/ }; do + # Validate number + if [[ "$idx" =~ ^[0-9]+$ ]] && [ "$idx" -ge 1 ] && [ "$idx" -le "$count" ]; then + target_indices+=($idx) + else + echo -e "${YELLOW}⚠️ 忽略无效序号: $idx${NC}" + fi + done +fi + +if [ ${#target_indices[@]} -eq 0 ]; then + echo -e "${RED}未选择任何有效 Runner。${NC}" + rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST" + exit 1 +fi + +# ========================================== +# 5. Confirmation +# ========================================== + +echo "" +echo -e "${RED}⚠️ 警告: 即将删除以下 ${#target_indices[@]} 个 Runner:${NC}" +for idx in "${target_indices[@]}"; do + echo " - [${runner_ids[$idx]}] ${runner_names[$idx]}" + if [ -n "${runner_paths[$idx]}" ]; then + echo " └─ 本地目录: ${runner_paths[$idx]}" + fi +done +echo "" +echo "此操作将从服务器注销 Runner 并删除本地文件/容器。" +read -p "确认删除? (输入 yes 继续): " confirm + +if [ "$confirm" != "yes" ]; then + echo "操作已取消。" + rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST" + exit 0 +fi + +# ========================================== +# 6. Execution +# ========================================== + +echo "" +echo "开始执行删除..." + +for idx in "${target_indices[@]}"; do + r_id="${runner_ids[$idx]}" + r_name="${runner_names[$idx]}" + r_path="${runner_paths[$idx]}" + + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "正在处理: $r_name (ID: $r_id)" + + # 6.1 Delete from Server + echo -n " 1. 从服务器注销... " + del_code=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \ + -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_URL}/api/v1/admin/actions/runners/${r_id}") + + if [ "$del_code" = "204" ] || [ "$del_code" = "404" ]; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败 (HTTP $del_code)${NC}" + # Continue cleanup anyway + fi + + # 6.2 Cleanup Local + if [ -n "$r_path" ] && [ -d "$r_path" ]; then + dir_name=$(basename "$r_path") + + # Stop Docker container if name matches folder name (common convention) + if docker ps -a --format '{{.Names}}' | grep -q "^${dir_name}$"; then + echo -n " 2. 停止并删除 Docker 容器 ($dir_name)... " + docker rm -f "$dir_name" >/dev/null 2>&1 + echo -e "${GREEN}完成${NC}" + fi + + # Stop Host process (if PID file exists) + if [ -f "$r_path/pid" ]; then + pid=$(cat "$r_path/pid") + echo -n " 2. 停止本地进程 (PID: $pid)... " + kill "$pid" >/dev/null 2>&1 || true + echo -e "${GREEN}完成${NC}" + fi + + echo -n " 3. 删除本地目录... " + rm -rf "$r_path" + echo -e "${GREEN}完成${NC}" + else + echo " - 本地目录未找到或已清理" + fi + +done + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo -e "${GREEN}✅ 批量删除操作完成${NC}" + +# Cleanup temps +rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST" +``` diff --git a/skill/gitea/runner-management.md b/skill/gitea/runner-management.md index a297e21..5dc8fa2 100644 --- a/skill/gitea/runner-management.md +++ b/skill/gitea/runner-management.md @@ -267,6 +267,8 @@ act_runner --version 7. 获取注册 token(优先全局) 8. 注册并启动 runner +> **提示**:你可以从 [create-runner.md](./create-runner.md) 获取完整的 Bash 脚本。 + ### 详细创建流程 当运行 `/gitea-create-runner` 命令时,会执行以下步骤: @@ -640,23 +642,58 @@ log: level: info runner: - file: /path/to/.runner + file: /data/.runner # 容器内路径 capacity: 2 timeout: 3h - labels: - - "ubuntu-latest:docker://catthehacker/ubuntu:act-latest" + shutdown_timeout: 30s + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: [] # 通过环境变量设置 cache: enabled: true - dir: "/path/to/cache" - host: "192.168.0.103" # 主机 IP(非 127.0.0.1) - port: 9000 + dir: "/data/cache" # 容器内缓存目录 + host: "host.docker.internal" # 宿主机地址(Docker 特殊 DNS) + port: 9040 # 缓存服务端口 container: - options: "--platform=linux/amd64" # 容器选项 - network: "host" # 网络模式 + # 使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问 + network: "host" + privileged: false + options: + workdir_parent: /data/workspace + valid_volumes: [] + docker_host: "" + force_pull: false + +host: + workdir_parent: /data/workspace ``` +**Docker 容器启动命令**: + +```bash +docker run -d \ + --name "$runner_name" \ + --restart always \ + --network host \ + -v "$runner_dir/config.yaml:/config.yaml" \ + -v "$runner_dir/data:/data" \ + -v "/var/run/docker.sock:/var/run/docker.sock" \ + -e GITEA_INSTANCE_URL="$GITEA_URL" \ + -e GITEA_RUNNER_REGISTRATION_TOKEN="$token" \ + -e GITEA_RUNNER_NAME="$runner_name" \ + -e GITEA_RUNNER_LABELS="ubuntu-latest:docker://node:16-bullseye,ubuntu-22.04:docker://node:16-bullseye,linux:docker://node:16-bullseye" \ + gitea/act_runner:latest daemon --config /config.yaml +``` + +**关键配置说明**: +- `--network host`:使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问 +- `host.docker.internal`:Docker 内部 DNS,指向宿主机 +- 环境变量自动注册:容器启动时自动完成 Runner 注册 +- `/var/run/docker.sock`:允许容器内创建兄弟容器执行 jobs + ## 多 Runner 缓存共享 ### 方案 A: Master-Slave 模式(推荐 2-3 个 runner) @@ -778,6 +815,64 @@ crontab -e /gitea-list-runners ``` +**API 调用详情**: + +1. **加载配置**: +```bash +source ~/.config/gitea/config.env +``` + +2. **调用 API**: +```bash +curl -s -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_URL}/api/v1/admin/actions/runners" +``` + +3. **响应结构**: +```json +{ + "runners": [...], + "total_count": 1 +} +``` + +4. **解析每个 Runner**: + - `id`: Runner ID + - `name`: Runner 名称 + - `status`: 状态("online"/"offline") + - `busy`: 是否忙碌(true/false) + - `ephemeral`: 是否临时(true/false) + - `labels`: 标签数组 + +5. **状态图标**: + - 🟢 在线 - `status: "online"` + - 🔴 离线 - `status: "offline"` + - ⚠️ 未知 - 无法确定 + +6. **输出格式**: +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Gitea 全局 Runners +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +服务器: [server_url] +总计: N 个全局 runner + +[runner-name] + 状态: 🟢/🔴 [在线/离线] + ID: [id] + 忙碌: 是/否 + 临时: 是/否 + 标签: [comma-separated labels] + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +**注意**: +- 需要管理员 API Token +- 正确的 API 端点是 `/api/v1/admin/actions/runners`(不是 `/api/v1/admin/runners`) +- 使用 `jq` 解析 JSON 响应 + ### 启动 Runner ```bash