chore: 重构 OpenCode 命令和技能文档体系

- 新增:统一的 git 命令文档(add/commit/push/pull 等)
- 新增:整合的 Gitea 技能文档(API、运行器、工作流等)
- 新增:工作流模板(Android、Go、Node.js 等)
- 移除:已弃用的旧命令脚本和发布脚本
- 改进:.gitignore 添加敏感文件保护规则
- 改进:AGENTS.md 完善了开发规范和示例

此次重组统一了命令和技能的文档结构,便于后续维护和扩展。
This commit is contained in:
Voson
2026-01-13 00:27:14 +08:00
parent 84a3b48d43
commit 5a05d5ab53
35 changed files with 9658 additions and 1609 deletions

View File

@@ -1,240 +0,0 @@
---
description: Auto-generate commit message, commit and create tag
agent: build
---
# auto-commit
Auto-generate commit message for staged files, commit to local repository.
## Features
- **Create tag**: Automatically generate version number and create tag by default
- **Skip tag**: Skip creating tag when user inputs "skip" or "skip tag"
> Version number update is **consistent** with git tag: AI will automatically update version number based on project type and changes, and create tag with the same version number.
## Steps
### 1. Check Staging Area
Run `git diff --cached --name-only` to check if there are files in staging area.
**If staging area is empty**:
- Output prompt: "No files in staging area, please use `git add` to add files first."
- **Terminate command execution**, do not continue
### 2. Collect Information (Execute in parallel)
- Run `git status` to view current status
- Run `git diff --cached` to view specific changes in staging area
- Run `git log --oneline -10` to view recent commit history, understand project's commit style
- Run `git tag --list | sort -V | tail -5` to view recent tags
- Read `AGENTS.md` file (if exists), understand project type, structure and **version update rules**
### 3. Detect Repository Type
**Detect repository type (polyrepo or monorepo)**:
- Check if `AGENTS.md` file indicates **monorepo**, if `AGENTS.md` doesn't exist or doesn't clearly indicate, default to **polyrepo**
**If monorepo, analyze change scope**:
- Based on changed files from step 1, analyze if changes only affect a specific subproject
- If only single subproject is affected, record subproject name (e.g., extract `user-service` from path `packages/user-service/src/index.ts`)
### 4. Detect Project Type and Determine Version Number
**Prioritize reading version update rules from AGENTS.md**:
If `AGENTS.md` defines version update rules (such as version file path, version field name, etc.), prioritize using that rule.
**Auto-detect project type** (when AGENTS.md is not defined):
AI needs to intelligently identify project type and determine version file, common project types include but not limited to:
| Project Type | Version File | Version Field/Location |
| --- | --- | --- |
| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` |
| npm/Node.js | `package.json` | `version` |
| Android (Groovy) | `app/build.gradle` | `versionName` |
| Android (Kotlin DSL) | `app/build.gradle.kts` | `versionName` |
| Python (pyproject) | `pyproject.toml` | `[project] version` or `[tool.poetry] version` |
| Python (setup) | `setup.py` | `version` parameter |
| Rust | `Cargo.toml` | `[package] version` |
| Go | Usually only uses git tag | - |
| Flutter | `pubspec.yaml` | `version` |
| .NET | `*.csproj` | `<Version>` or `<PackageVersion>` |
> AI should determine project type based on files that actually exist in repository, can check multiple possible version files if necessary.
**Read current version number**:
1. Read current version number from identified version file
2. Parse as `major.minor.patch`:
- If parsing fails or doesn't exist: treat as `0.1.0`
- If current version only has `major.minor` format, auto-complete to `major.minor.0`
**Calculate new version number** (based on change type):
Version number uses **semantic versioning format**: `0.1.0`, `0.2.0`, ..., `0.9.0`, `1.0.0`, `1.1.0`, `1.1.1`...
- **Default starting version**: `0.1.0`
- **Increment rules**:
- **Major/breaking changes**: `1.2.3` -> `2.0.0` (major +1, minor and patch reset to zero)
- **New feature (feat)**: `1.2.3` -> `1.3.0` (minor +1, patch reset to zero)
- **Bug fix (fix)**: `1.2.3` -> `1.2.4` (patch +1)
**Determine if version number update is needed**:
> Core principle: **Version number reflects "user-perceivable changes"**. Ask yourself: Has the product that users download/use changed?
**Need to update version number** (packaged into final product, user-perceivable):
| commit type | version change | description |
| --- | --- | --- |
| `feat` | minor +1 | new feature |
| `fix` | patch +1 | user-perceivable bug fix |
| `perf` | patch +1 | performance optimization (user-perceivable improvement) |
| breaking change (`!`) | major +1 | API/protocol incompatible changes |
**No need to update version number** (doesn't affect final product, user-imperceptible):
| commit type | description | example |
| --- | --- | --- |
| `chore` | miscellaneous/toolchain | build scripts, CI config, dependency updates |
| `ci` | CI/CD config | `.github/workflows/*.yml`, `release.mjs` |
| `docs` | documentation | README, comments, API docs |
| `test` | test code | unit tests, E2E tests |
| `refactor` | refactoring | code reorganization without changing external behavior |
| `style` | code style | formatting, spaces, semicolons |
| `build` | build config | `tsconfig.json`, `biome.json`, `webpack.config.js` |
**Judgment tips**:
1. **Will the file be packaged into final product?**
- `scripts/`, `.github/`, `*.config.js` -> No -> Don't update version
- `src/`, `lib/`, `app/` -> Yes -> May need to update version
2. **Does the change only affect developers?**
- Dev tool config, CI scripts, build process -> Only affects developers -> Don't update version
- Feature code, UI, API -> Affects users -> Update version
3. **If project type cannot be identified or no version file** -> Only create git tag, don't update version file
### 5. Generate Commit Message
Based on changes in staging area, **analyze and generate meaningful commit message by AI**:
- Analyze changed code content, understand the purpose and intent of this modification
- Reference project's commit history style
- Use [Conventional Commits](https://www.conventionalcommits.org/) specification
- Commit message should concisely but accurately describe "why" rather than just "what"
- Common types: `feat` (new feature), `fix` (fix), `docs` (documentation), `refactor` (refactoring), `chore` (miscellaneous), `test` (test), etc.
- **Language selection**:
- **Default (macOS/Linux)**: Use Chinese (中文) for commit messages
- **Windows**: Use English due to encoding issues with Cursor Shell tool
- **If monorepo and this commit only affects single subproject, include subproject name in commit message**:
- Format: `<type>(<scope>): <description>`, where `<scope>` is subproject name
- Example (Chinese): `feat(ios): 支持 OGG Opus 上传` or `fix(electron): 修复剪贴板注入失败`
- Example (English): `feat(ios): support OGG Opus upload` or `fix(electron): fix clipboard injection failure`
- If affecting multiple subprojects or entire repository, no need to add scope
### 6. Update Project Version Number
> Only execute when step 4 determines version number update is needed and version file is identified
**Execution steps**:
1. Based on version file and field identified in step 4, update version number to calculated new version
2. Add version file to staging area: `git add <version file>`
3. **Verify staging area**: Run `git diff --cached --name-only` to confirm version file is in staging area
### 7. Execute Commit
Execute commit with generated commit message (staging area now includes user's changes and version number update).
**Commit message language by platform:**
**macOS/Linux** (use Chinese commit messages):
```bash
# Single line commit
git commit -m "feat(android): 添加新功能"
# Multi-line commit (recommended)
git commit -m "$(cat <<'EOF'
feat(android): 添加新功能
- 详细说明 1
- 详细说明 2
EOF
)"
```
**Windows** (use English commit messages):
Due to Cursor's Shell tool encoding issues on Windows, **must use English** commit messages.
```powershell
# Single line commit
git commit -m "feat(android): add new feature"
# Multi-line commit (use --message multiple times)
git commit --message="fix(android): fix code review issues" --message="- Fix syntax error" --message="- Use JSONObject instead of manual JSON"
```
**Windows prohibited methods** (will cause garbled text):
- No Chinese commit messages - Cursor Shell tool encoding error when passing Chinese parameters
- No `Out-File -Encoding utf8` - writes UTF-8 with BOM
- No Write tool to write temp files - encoding uncontrollable
- No PowerShell here-string `@"..."@` - newline parsing issues
### 8. Create Tag
> **Executed by default**. Only skip this step when user explicitly inputs "skip" or "skip tag".
> Only create tag when step 4 determines version number update is needed (docs/chore types don't create tag).
**Tag annotation content requirements**:
- **Use the same content as commit message for tag annotation**
- Tag annotation will be used as Release notes by CI/CD scripts, should include detailed change content
- If commit message has multiple lines, tag annotation should also be multi-line
**polyrepo**:
```bash
git tag -a "<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
```
**monorepo**:
```bash
git tag -a "<subproject>-<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
```
Examples (single line commit):
- polyrepo: `git tag -a "1.2.0" -m "feat: add user authentication"`
- monorepo: `git tag -a "android-1.2.0" -m "feat(android): add user authentication"`
Examples (multi-line commit, more recommended):
- polyrepo:
```bash
git tag -a "1.2.1" -m "fix: resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
```
- monorepo:
```bash
git tag -a "android-1.2.1" -m "fix(android): resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
```
## Notes
- **Staging area check first**: Must check if staging area has files first, if not, terminate immediately, don't execute any subsequent operations.
- **AGENTS.md priority**: If `AGENTS.md` defines version update rules, prioritize using that rule; otherwise AI auto-detects project type.
- **Smart detection**: AI should intelligently determine project type and version file location based on files that actually exist in repository.
- **Version number and tag consistency**: Project version number and git tag use the same version number, ensure consistency.
- **Version number format**: Use `major.minor.patch` semantic versioning format (e.g., `0.1.0`, `1.1.0`, `1.1.1`), default starting `0.1.0`.
- **Create tag by default**: Unless user inputs "skip" or "skip tag", create tag by default.
- **Update version before commit**: First determine version number and modify version file, then commit at once, avoid using `--amend`.
- **Version file must be verified**: After updating version number and `git add`, must run `git diff --cached --name-only` to confirm version file is in staging area before executing commit.
- **Commit message language**: Default use Chinese (macOS/Linux); Windows must use English due to Cursor Shell tool encoding issues.
- **monorepo scope**: If staging area only affects single subproject, commit message should have scope; if affecting multiple subprojects, no scope needed.
- **monorepo tag format**: Use `<subproject>-<version>` format (e.g., `ios-0.1.0`, `android-1.1.0`).
- **No version file case**: If project type cannot be identified or no version file (like pure Go project), only create git tag, don't update any files.

View File

@@ -1,259 +0,0 @@
---
description: Auto-generate commit, create tag, and push to remote
agent: build
---
# commit-push
Auto-generate commit message for staged files, commit to local repository, then push to remote repository origin.
## Features
- **Create tag**: Automatically generate version number and create tag by default, push to remote
- **Skip tag**: Skip creating tag when user inputs "skip" or "skip tag"
> Version number update is **consistent** with git tag: AI will automatically update version number based on project type and changes, and create tag with the same version number.
## Steps
### 1. Check Staging Area
Run `git diff --cached --name-only` to check if there are files in staging area.
**If staging area is empty**:
- Output prompt: "No files in staging area, please use `git add` to add files first."
- **Terminate command execution**, do not continue
### 2. Collect Information (Execute in parallel)
- Run `git status` to view current status
- Run `git diff --cached` to view specific changes in staging area
- Run `git log --oneline -10` to view recent commit history, understand project's commit style
- Run `git tag --list | sort -V | tail -5` to view recent tags
- Read `AGENTS.md` file (if exists), understand project type, structure and **version update rules**
### 3. Detect Repository Type
**Detect repository type (polyrepo or monorepo)**:
- Check if `AGENTS.md` file indicates **monorepo**, if `AGENTS.md` doesn't exist or doesn't clearly indicate, default to **polyrepo**
**If monorepo, analyze change scope**:
- Based on changed files from step 1, analyze if changes only affect a specific subproject
- If only single subproject is affected, record subproject name (e.g., extract `user-service` from path `packages/user-service/src/index.ts`)
### 4. Detect Project Type and Determine Version Number
**Prioritize reading version update rules from AGENTS.md**:
If `AGENTS.md` defines version update rules (such as version file path, version field name, etc.), prioritize using that rule.
**Auto-detect project type** (when AGENTS.md is not defined):
AI needs to intelligently identify project type and determine version file, common project types include but not limited to:
| Project Type | Version File | Version Field/Location |
| --- | --- | --- |
| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` |
| npm/Node.js | `package.json` | `version` |
| Android (Groovy) | `app/build.gradle` | `versionName` |
| Android (Kotlin DSL) | `app/build.gradle.kts` | `versionName` |
| Python (pyproject) | `pyproject.toml` | `[project] version` or `[tool.poetry] version` |
| Python (setup) | `setup.py` | `version` parameter |
| Rust | `Cargo.toml` | `[package] version` |
| Go | Usually only uses git tag | - |
| Flutter | `pubspec.yaml` | `version` |
| .NET | `*.csproj` | `<Version>` or `<PackageVersion>` |
> AI should determine project type based on files that actually exist in repository, can check multiple possible version files if necessary.
**Read current version number**:
1. Read current version number from identified version file
2. Parse as `major.minor.patch`:
- If parsing fails or doesn't exist: treat as `0.1.0`
- If current version only has `major.minor` format, auto-complete to `major.minor.0`
**Calculate new version number** (based on change type):
Version number uses **semantic versioning format**: `0.1.0`, `0.2.0`, ..., `0.9.0`, `1.0.0`, `1.1.0`, `1.1.1`...
- **Default starting version**: `0.1.0`
- **Increment rules**:
- **Major/breaking changes**: `1.2.3` -> `2.0.0` (major +1, minor and patch reset to zero)
- **New feature (feat)**: `1.2.3` -> `1.3.0` (minor +1, patch reset to zero)
- **Bug fix (fix)**: `1.2.3` -> `1.2.4` (patch +1)
**Determine if version number update is needed**:
> Core principle: **Version number reflects "user-perceivable changes"**. Ask yourself: Has the product that users download/use changed?
**Need to update version number** (packaged into final product, user-perceivable):
| commit type | version change | description |
| --- | --- | --- |
| `feat` | minor +1 | new feature |
| `fix` | patch +1 | user-perceivable bug fix |
| `perf` | patch +1 | performance optimization (user-perceivable improvement) |
| breaking change (`!`) | major +1 | API/protocol incompatible changes |
**No need to update version number** (doesn't affect final product, user-imperceptible):
| commit type | description | example |
| --- | --- | --- |
| `chore` | miscellaneous/toolchain | build scripts, CI config, dependency updates |
| `ci` | CI/CD config | `.github/workflows/*.yml`, `release.mjs` |
| `docs` | documentation | README, comments, API docs |
| `test` | test code | unit tests, E2E tests |
| `refactor` | refactoring | code reorganization without changing external behavior |
| `style` | code style | formatting, spaces, semicolons |
| `build` | build config | `tsconfig.json`, `biome.json`, `webpack.config.js` |
**Judgment tips**:
1. **Will the file be packaged into final product?**
- `scripts/`, `.github/`, `*.config.js` -> No -> Don't update version
- `src/`, `lib/`, `app/` -> Yes -> May need to update version
2. **Does the change only affect developers?**
- Dev tool config, CI scripts, build process -> Only affects developers -> Don't update version
- Feature code, UI, API -> Affects users -> Update version
3. **If project type cannot be identified or no version file** -> Only create git tag, don't update version file
### 5. Generate Commit Message
Based on changes in staging area, **analyze and generate meaningful commit message by AI**:
- Analyze changed code content, understand the purpose and intent of this modification
- Reference project's commit history style
- Use [Conventional Commits](https://www.conventionalcommits.org/) specification
- Commit message should concisely but accurately describe "why" rather than just "what"
- Common types: `feat` (new feature), `fix` (fix), `docs` (documentation), `refactor` (refactoring), `chore` (miscellaneous), `test` (test), etc.
- **Language selection**:
- **Default (macOS/Linux)**: Use Chinese (中文) for commit messages
- **Windows**: Use English due to encoding issues with Cursor Shell tool
- **If monorepo and this commit only affects single subproject, include subproject name in commit message**:
- Format: `<type>(<scope>): <description>`, where `<scope>` is subproject name
- Example (Chinese): `feat(ios): 支持 OGG Opus 上传` or `fix(electron): 修复剪贴板注入失败`
- Example (English): `feat(ios): support OGG Opus upload` or `fix(electron): fix clipboard injection failure`
- If affecting multiple subprojects or entire repository, no need to add scope
### 6. Update Project Version Number
> Only execute when step 4 determines version number update is needed and version file is identified
**Execution steps**:
1. Based on version file and field identified in step 4, update version number to calculated new version
2. Add version file to staging area: `git add <version file>`
3. **Verify staging area**: Run `git diff --cached --name-only` to confirm version file is in staging area
### 7. Execute Commit
Execute commit with generated commit message (staging area now includes user's changes and version number update).
**Commit message language by platform:**
**macOS/Linux** (use Chinese commit messages):
```bash
# Single line commit
git commit -m "feat(android): 添加新功能"
# Multi-line commit (recommended)
git commit -m "$(cat <<'EOF'
feat(android): 添加新功能
- 详细说明 1
- 详细说明 2
EOF
)"
```
**Windows** (use English commit messages):
Due to Cursor's Shell tool encoding issues on Windows, **must use English** commit messages.
```powershell
# Single line commit
git commit -m "feat(android): add new feature"
# Multi-line commit (use --message multiple times)
git commit --message="fix(android): fix code review issues" --message="- Fix syntax error" --message="- Use JSONObject instead of manual JSON"
```
**Windows prohibited methods** (will cause garbled text):
- No Chinese commit messages - Cursor Shell tool encoding error when passing Chinese parameters
- No `Out-File -Encoding utf8` - writes UTF-8 with BOM
- No Write tool to write temp files - encoding uncontrollable
- No PowerShell here-string `@"..."@` - newline parsing issues
### 8. Create Tag
> **Executed by default**. Only skip this step when user explicitly inputs "skip" or "skip tag".
> Only create tag when step 4 determines version number update is needed (docs/chore types don't create tag).
**Tag annotation content requirements**:
- **Use the same content as commit message for tag annotation**
- Tag annotation will be used as Release notes by CI/CD scripts, should include detailed change content
- If commit message has multiple lines, tag annotation should also be multi-line
**polyrepo**:
```bash
git tag -a "<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
```
**monorepo**:
```bash
git tag -a "<subproject>-<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
```
Examples (single line commit):
- polyrepo: `git tag -a "1.2.0" -m "feat: add user authentication"`
- monorepo: `git tag -a "android-1.2.0" -m "feat(android): add user authentication"`
Examples (multi-line commit, more recommended):
- polyrepo:
```bash
git tag -a "1.2.1" -m "fix: resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
```
- monorepo:
```bash
git tag -a "android-1.2.1" -m "fix(android): resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
```
### 9. Push to Remote Repository
```bash
# Push current branch
git push origin $(git branch --show-current)
```
**If tag was created, also push tag**:
**polyrepo**:
```bash
git push origin <version>
```
**monorepo**:
```bash
git push origin <subproject>-<version>
```
## Notes
- **Staging area check first**: Must check if staging area has files first, if not, terminate immediately, don't execute any subsequent operations.
- **AGENTS.md priority**: If `AGENTS.md` defines version update rules, prioritize using that rule; otherwise AI auto-detects project type.
- **Smart detection**: AI should intelligently determine project type and version file location based on files that actually exist in repository.
- **Version number and tag consistency**: Project version number and git tag use the same version number, ensure consistency.
- **Version number format**: Use `major.minor.patch` semantic versioning format (e.g., `0.1.0`, `1.1.0`, `1.1.1`), default starting `0.1.0`.
- **Create tag by default**: Unless user inputs "skip" or "skip tag", create and push tag by default.
- **Update version before commit**: First determine version number and modify version file, then commit at once, avoid using `--amend`.
- **Version file must be verified**: After updating version number and `git add`, must run `git diff --cached --name-only` to confirm version file is in staging area before executing commit.
- **Commit message language**: Default use Chinese (macOS/Linux); Windows must use English due to Cursor Shell tool encoding issues.
- **monorepo scope**: If staging area only affects single subproject, commit message should have scope; if affecting multiple subprojects, no scope needed.
- **monorepo tag format**: Use `<subproject>-<version>` format (e.g., `ios-0.1.0`, `android-1.1.0`).
- **No version file case**: If project type cannot be identified or no version file (like pure Go project), only create git tag, don't update any files.

View File

@@ -1,130 +0,0 @@
---
description: Create a new Git repository on Gitea
agent: build
---
# create-gitea-repo
Create a new Git repository on Gitea.
## Features
- Create new repository under specified organization or user via Gitea API
- Support creating private or public repositories
- Automatically add remote repository address after successful creation
## User Input Format
User can specify parameters in the following format:
```
<owner>/<repo> [private|public]
```
- `owner`: Organization name or username (required)
- `repo`: Repository name (required)
- `private|public`: Visibility (optional, default `private`)
**Examples**:
- `ai/my-project` - Create private repository my-project under ai organization
- `ai/my-project public` - Create public repository my-project under ai organization
- `voson/test private` - Create private repository test under voson user
## Configuration
Use the following configuration when executing command:
| Config Item | Value |
| --- | --- |
| Gitea Server URL | `https://git.digitevents.com/` |
| API Token | `{env:GITEA_API_TOKEN}` |
## Steps
### 1. Parse User Input
Parse from user input:
- `owner`: Organization name or username
- `repo`: Repository name
- `visibility`: `private` (default) or `public`
**Input validation**:
- If user didn't provide `owner/repo` format input, prompt user for correct format and terminate execution
- Repository name can only contain letters, numbers, underscores, hyphens and dots
### 2. Call Gitea API to Create Repository
Use curl to call Gitea API:
```bash
curl -s -X POST "https://git.digitevents.com/api/v1/orgs/<owner>/repos" \
-H "Authorization: token $GITEA_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "<repo>",
"private": <true|false>
}'
```
> Note: If owner is personal user instead of organization, API path should be `/api/v1/user/repos`, but usually try organization API first.
### 3. Handle Response
**Success** (HTTP 201):
- Extract repository info from response:
- `html_url`: Repository web URL
- `clone_url`: HTTPS clone URL
- `ssh_url`: SSH clone URL
- Output creation success message
**Failure**:
- If 404 error, owner may not exist or no permission
- If 409 error, repository already exists
- Output error message and terminate
### 4. Ask Whether to Add Remote Repository
Ask user whether to add the newly created repository as current project's remote repository.
**If user confirms**:
1. Check if current directory is a Git repository:
```bash
git rev-parse --is-inside-work-tree
```
2. If not a Git repository, ask whether to initialize:
```bash
git init
```
3. Check if origin remote already exists:
```bash
git remote get-url origin
```
4. Add or update remote repository:
- If no origin: `git remote add origin <clone_url>`
- If origin exists: Ask whether to overwrite, after confirmation execute `git remote set-url origin <clone_url>`
### 5. Output Result Summary
Output creation result summary table:
```
Repository created successfully!
| Property | Value |
|----------|-------|
| Repository Name | owner/repo |
| Web URL | https://git.digitevents.com/owner/repo |
| Clone URL (HTTPS) | https://git.digitevents.com/owner/repo.git |
| Clone URL (SSH) | git@git.digitevents.com:owner/repo.git |
| Private | Yes/No |
```
## Notes
- **Permission check**: Ensure Token has permission to create repository
- **Organization vs User**: Creating organization repository and user repository use different API endpoints
- **Repository naming**: Follow Gitea naming rules, avoid special characters

321
command/git-add.md Normal file
View File

@@ -0,0 +1,321 @@
---
description: Stage changes with automatic filtering of sensitive files
---
# git-add
Intelligently stage changes while automatically filtering security-sensitive files.
## What It Does
- Detects all unstaged changes
- Automatically excludes common sensitive files (credentials, secrets, etc.)
- Previews files that will be staged
- Asks for confirmation before staging
- Shows excluded sensitive files for awareness
## Quick Start
Use this command when you want to safely stage changes without accidentally committing sensitive information.
## Sensitive Files Filtered
**Always excluded:**
- `.env*` - Environment files
- `*.key`, `*.pem`, `*.p8` - Private keys
- `.aws/*`, `.gcloud/*` - Cloud credentials
- `.ssh/*` - SSH keys
- `credentials.json`, `secrets.json` - Credential files
- `package-lock.json`, `yarn.lock` (optional, can override)
- `node_modules/`, `vendor/`, `.venv/` - Dependencies
- `dist/`, `build/`, `.next/` - Build artifacts
- `.DS_Store`, `Thumbs.db` - System files
**Custom exclusions:**
- Can be specified in project `.gitignore` or `.secretsignore`
## Steps
### 1. Detect All Unstaged Changes
```bash
git status --porcelain
git diff --name-only
```
Categories:
- Modified files (M)
- Deleted files (D)
- Untracked files (??) - **重要:第一次就显示并提供选项**
### 2. Filter Sensitive Files
Build exclusion list:
- Read `.gitignore` for patterns
- Read `.secretsignore` if exists (project-specific rules)
- Apply built-in security patterns
- Check for `.env*`, `*.key`, `credentials.json`, etc.
Separate files into:
- **Modified/Deleted files (tracked)**: 已跟踪的修改和删除
- **Untracked files (safe)**: 未跟踪但安全的新文件
- **Sensitive files**: 敏感文件(需要 force 才能暂存)
**关键逻辑:**
- 默认选项 (y): 只暂存已跟踪的修改/删除
- all/u 选项: 暂存所有安全文件(包括未跟踪)
- force 选项: 暂存所有文件(包括敏感)
- 一次性显示所有选项,不需要二次运行命令
### 3. Display Preview
Show clear summary in format:
```
=== 将要暂存的文件 (3) ===
M src/index.js
M src/utils.js
D old-file.js
=== 未跟踪的文件 (2) ===
?? new-feature.js
?? tests/new-test.js
=== 敏感文件已过滤 (2) ===
⚠ .env.local (Environment file)
⚠ config/secrets.json (Credential file)
=== 操作选项 ===
- 输入 "y" 或 "yes" 暂存已修改/已删除的文件(不包括未跟踪文件)
- 输入 "all" 暂存所有文件(包括未跟踪文件,但排除敏感文件)
- 输入 "with-untracked" 或 "u" 暂存所有文件(包括未跟踪文件)
- 输入 "force" 强制暂存所有文件(包括敏感文件,谨慎使用)
- 输入 "no" 或 "cancel" 取消操作
- 输入文件路径 暂存特定文件
```
### 4. User Confirmation
Prompt user:
```
是否确认暂存上述文件? (y/all/u/no)
```
**Options:**
- `y` or `yes`: Stage modified/deleted files only (exclude untracked)
- `all` or `with-untracked` or `u`: Stage all including untracked files (exclude sensitive)
- `force`: Stage everything including sensitive files (show warning)
- `no` or `cancel`: Abort
- File path: Stage only specific file(s)
**智能提示:**
- 如果没有未跟踪文件,只显示 y/no 选项
- 如果有未跟踪文件,显示 y/all/u/no 选项,并高亮推荐使用 "all" 或 "u"
- 如果有敏感文件,额外显示 force 选项并警告风险
### 5. Execute Staging
If user confirms:
```bash
# Option 1: Stage modified/deleted only (y)
git add <modified-file-1> <modified-file-2> ...
# Option 2: Stage all including untracked (all/u)
git add <all-safe-files-including-untracked>
# Option 3: Stage everything including sensitive (force)
git add .
```
**Warning for "force" option:**
```
⚠️ 警告:你选择暂存所有文件,包括敏感文件!
请确认这是有意的,避免意外提交凭证或密钥。
已暂存的敏感文件:
- .env.local
- config/secrets.json
输入 "confirm" 继续,或 "cancel" 取消操作
```
**Success message for "all/u" option:**
```
✓ 已暂存所有文件(包括未跟踪文件)
已暂存 5 个文件:
M src/index.js
M src/utils.js
D old-file.js
A new-feature.js
A tests/new-test.js
敏感文件已自动过滤并排除。
```
### 6. Display Result
Show success message in Chinese:
```
✓ 暂存成功
已暂存 3 个文件:
M src/index.js
M src/utils.js
A command/git-add.md
敏感文件已过滤并排除,保护了你的凭证信息。
下一步:
- 运行 /git-commit 生成提交信息并提交
- 运行 /git-status 查看暂存区状态
```
## Safety Features
### Automatic Filters
| Pattern | Why | Can Override |
|---------|-----|--------------|
| `.env*` | Environment variables | No |
| `*.key`, `*.pem` | Private keys | No |
| `credentials.json` | API credentials | No |
| `secrets.json` | Secrets | No |
| `.aws/*`, `.gcloud/*` | Cloud credentials | No |
| `.ssh/*` | SSH keys | No |
| `package-lock.json` | Lock files (optional) | Yes |
### Warnings
- Show count of filtered files
- List filtered file names for transparency
- Warn when using "all" option
- Explain why each sensitive file was excluded
## Use Cases
- Stage changes safely before commit
- Prevent accidental credential leaks
- Review what will be committed before staging
- Follow security best practices
## Related Commands
- `/git-status` - Check file changes before staging
- `/git-commit` - Commit staged files
- `/git-push` - Push commits to remote
## Examples
### Normal Usage (无未跟踪文件)
```bash
/git-add
# 显示3 个已修改文件
# 提示:是否确认暂存? (y/no)
# 输入 "y" 暂存所有已修改文件
```
### 包含未跟踪文件的情况
```bash
/git-add
# 显示:
# - 3 个已修改/已删除文件
# - 2 个未跟踪文件
# 提示:是否确认暂存? (y/all/u/no)
# 输入 "y" 仅暂存已修改文件
# 输入 "all" 或 "u" 暂存所有文件(包括未跟踪)
```
### 强制暂存敏感文件
```bash
/git-add
# 显示:包含 2 个敏感文件
# 提示:是否确认暂存? (y/all/force/no)
# 输入 "force" 强制暂存所有文件
# ⚠️ 显示二次确认警告
```
### 暂存特定文件
```bash
/git-add
# 显示预览
# 输入文件路径src/index.js
# 仅暂存指定的文件
```
### 取消操作
```bash
/git-add
# 显示预览
# 输入 "no" 或 "cancel"
# 操作中止
```
## Implementation Guide
### 关键实现要点
**1. 文件分类逻辑**
```bash
# 获取所有状态
git status --porcelain
# 分类处理
tracked_modified=() # M 状态
tracked_deleted=() # D 状态
untracked_safe=() # ?? 状态且非敏感
untracked_sensitive=() # ?? 状态且敏感
tracked_sensitive=() # M/D 状态但匹配敏感规则
```
**2. 选项显示逻辑**
```python
if has_untracked_files:
if has_sensitive_files:
prompt = "是否确认暂存? (y/all/force/no)"
options = {
"y": "仅暂存已跟踪的修改/删除",
"all/u": "暂存所有安全文件(含未跟踪)",
"force": "暂存所有文件(含敏感)⚠️",
"no": "取消操作"
}
else:
prompt = "是否确认暂存? (y/all/no)"
options = {
"y": "仅暂存已跟踪的修改/删除",
"all/u": "暂存所有文件(含未跟踪)✓ 推荐",
"no": "取消操作"
}
else:
prompt = "是否确认暂存? (y/no)"
```
**3. 执行逻辑**
```bash
case $choice in
y|yes)
git add "${tracked_modified[@]}" "${tracked_deleted[@]}"
;;
all|u|with-untracked)
git add "${tracked_modified[@]}" "${tracked_deleted[@]}" "${untracked_safe[@]}"
;;
force)
# 二次确认
read -p "⚠️ 确认暂存敏感文件? (输入 confirm): " confirm
if [[ "$confirm" == "confirm" ]]; then
git add .
fi
;;
esac
```
## Notes
- This command prioritizes security over convenience
- Sensitive files must be explicitly forced to stage
- **重要:第一次运行就显示所有选项,不需要用户多次运行命令**
- Untracked files are displayed upfront with clear options
- Use `.secretsignore` file for project-specific exclusion patterns
- Consider setting up git hooks for additional security

189
command/git-commit.md Normal file
View File

@@ -0,0 +1,189 @@
---
description: Commit staged files with auto-generated message and create version tag
---
# git-commit
Auto-generate commit message for staged files, commit to local repository, and create version tag.
## What It Does
- Analyzes staged changes
- Auto-generates meaningful commit message following Conventional Commits
- Detects project type and updates version number if needed
- Creates appropriate git tag (polyrepo or monorepo format)
- Does NOT push to remote (local only)
## Quick Start
Use this command when you have files in staging area and want to commit with proper version tagging.
## Workflow
This command follows the git workflow defined in `skill/git/SKILL.md`:
1. ✓ Check staging area (must have files)
2. ✓ Analyze changes and repository type
3. ✓ Detect project type and version file
4. ✓ Generate commit message (Conventional Commits)
5. ✓ Update version number if needed
6. ✓ Commit with generated message
7. ✓ Create version tag
8. ✗ Skip push (use `/git-push` to push)
## Prerequisites
**Staging area must not be empty:**
```bash
git add <files>
```
## Options
User can optionally input:
- **"skip tag"** or **"skip"**: Skip tag creation, only commit
## Steps
### 1. Check Staging Area
```bash
git diff --cached --name-only
```
**If empty:**
- Display: "暂存区为空,请先使用 `git add` 添加文件。"
- **Terminate execution**
### 2. Collect Information (parallel)
```bash
git status
git diff --cached
git log --oneline -10
git tag --list | sort -V | tail -5
```
If `AGENTS.md` exists, read it for:
- Repository type (polyrepo/monorepo)
- Version update rules
- Project structure
### 3. Detect Repository Type
- **Polyrepo**: Single project, tag format `1.2.0`
- **Monorepo**: Multiple subprojects, tag format `<subproject>-1.2.0`
Detection:
- Check `AGENTS.md` for monorepo indicator
- Check directory structure (`packages/`, `apps/`, etc.)
- Analyze changed file paths for subproject scope
### 4. Detect Project Type and Version
Follow `skill/git/SKILL.md` guidelines:
**Common project types:**
- iOS: `*.xcodeproj/project.pbxproj``MARKETING_VERSION`
- Node.js: `package.json``version`
- Android: `build.gradle(.kts)``versionName`
- Go: Git tag only (no version file)
- etc.
**Version increment rules:**
- `feat`: minor +1 → `1.2.0``1.3.0`
- `fix`: patch +1 → `1.2.3``1.2.4`
- `perf`: patch +1
- Breaking change: major +1 → `1.2.3``2.0.0`
**Only update version for user-perceivable changes:**
- ✓ feat, fix, perf, breaking changes
- ✗ docs, test, refactor, style, chore, ci, build
### 5. Generate Commit Message
Follow Conventional Commits specification:
**Format:**
```
<type>(<scope>): <subject>
<body>
```
**Commit language:**
- macOS/Linux: Chinese (中文)
- Windows: English (encoding issue)
**Monorepo scope:**
- If changes affect single subproject: `feat(ios): 添加新功能`
- If multiple subprojects: `feat: 添加新功能`
### 6. Update Version Number
If version update is needed:
1. Update version file with new version
2. Add version file to staging: `git add <version-file>`
3. Verify: `git diff --cached --name-only`
### 7. Commit Changes
```bash
# macOS/Linux (Chinese)
git commit -m "feat(android): 添加用户认证"
# Windows (English)
git commit -m "feat(android): add user authentication"
# Multi-line (macOS/Linux)
git commit -m "$(cat <<'EOF'
feat: add user authentication
- Add OAuth2 support
- Implement JWT tokens
EOF
)"
```
### 8. Create Tag
**Only if:**
- Version update occurred
- User didn't input "skip tag"
**Tag format:**
- Polyrepo: `git tag -a "1.2.0" -m "feat: add feature"`
- Monorepo: `git tag -a "ios-1.2.0" -m "feat(ios): add feature"`
**Tag annotation:**
- Use same content as commit message
- Multi-line commits → multi-line annotations
### 9. Display Result
Show summary in Chinese:
```
✓ 提交成功
提交信息feat(android): 添加用户认证
版本标签android-1.3.0
要推送到远程仓库,请运行:/git-push
```
## Use Cases
- Commit staged changes with proper versioning
- Create local version tag for release preparation
- Follow semantic versioning automatically
## Related Commands
- `/git-status` - Check file changes before commit
- `/git-push` - Push commits and tags to remote
- `/git-push-tags` - Push tags only
## Reference
Complete workflow documentation: `skill/git/SKILL.md`

85
command/git-pull.md Normal file
View File

@@ -0,0 +1,85 @@
---
description: Pull latest changes from remote repository
---
# git-pull
Pull latest changes from remote repository for current branch.
## What It Does
- Fetches latest changes from remote
- Merges remote changes into local branch
- Updates working directory
## Quick Start
Use this command to synchronize your local branch with the latest remote changes.
## Steps
### 1. Execute Pull
```bash
git pull
```
This command will:
- Fetch updates from remote repository
- Automatically merge changes into current branch
- Update your working directory
### 2. Handle Conflicts (if any)
If merge conflicts occur:
- Git will mark conflicting files
- Resolve conflicts manually
- Stage resolved files: `git add <file>`
- Complete merge: `git commit`
Or use: `/git-status` to check conflict status
### 3. Display Result
Show result message:
```
✓ 拉取成功
分支已更新至最新状态。
```
Or if conflicts:
```
⚠️ 发生合并冲突
请解决以下文件中的冲突:
- src/index.js
- README.md
然后运行:
git add <file>
git commit
或使用 /git-status 查看详细状态
```
## Use Cases
- Sync local branch with remote updates
- Get latest changes from team
- Before starting new feature work
- Before pushing your changes
## Related Commands
- `/git-status` - Check file changes and merge status
- `/git-push` - Push local changes to remote
- `/git-commit` - Commit local changes
## Notes
- Pulls from tracking remote branch (usually origin/main)
- Uses default merge strategy (recursive merge)
- If conflicts occur, resolve them before committing

91
command/git-push-tags.md Normal file
View File

@@ -0,0 +1,91 @@
---
description: Push all local tags to remote repository
---
# git-push-tags
Push all local tags to the remote repository.
## What It Does
1. Lists all local tags
2. Shows which tags are not yet on remote
3. Pushes all tags to remote (origin)
4. Confirms successful push
## Steps
### 1. List Local Tags
```bash
echo "=== Local Tags ==="
git tag --list | sort -V
```
### 2. Check Remote Tags
```bash
echo "=== Remote Tags ==="
git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sort -V
```
### 3. Identify Unpushed Tags
Compare local and remote tags to identify which tags need to be pushed.
### 4. Confirm Before Push
Display summary in Chinese:
```
本地标签总数15 个
远程标签总数12 个
待推送标签3 个
- 1.3.0
- 1.3.1
- ios-2.0.0
确认推送所有标签到 origin
```
If user confirms or no confirmation needed, proceed to push.
### 5. Push All Tags
```bash
git push --tags
# or
git push origin --tags
```
### 6. Verify Push
```bash
echo "=== Push Result ==="
git ls-remote --tags origin | tail -5
```
Display confirmation in Chinese:
```
✓ 已成功推送所有标签到 origin
最近 5 个远程标签:
- 1.3.0
- 1.3.1
- ios-2.0.0
- android-1.5.0
- electron-3.0.0
```
## Use Cases
- After creating multiple local tags
- Sync tags with remote repository
- Before triggering CI/CD release workflows
- Share version tags with team
## Notes
- **Safe operation**: Pushing tags does not affect commits
- **No force push**: Uses standard push, won't overwrite existing tags
- **All tags**: Pushes ALL local tags, not just one
- If you only want to push a specific tag, use: `git push origin <tag-name>`

190
command/git-push.md Normal file
View File

@@ -0,0 +1,190 @@
---
description: Commit staged files, create version tag, and push to remote repository
---
# git-push
Complete workflow: auto-generate commit message, create version tag, and push everything to remote repository.
## What It Does
This is the **all-in-one command** that:
1. ✓ Analyzes and commits staged changes (like `/git-commit`)
2. ✓ Creates version tag if needed
3. ✓ Pushes commit to remote repository
4. ✓ Pushes tag to remote repository
## Quick Start
Use this command when you want to commit AND push in one step.
## Prerequisites
**Staging area must have files:**
```bash
git add <files>
```
## Options
User can optionally input:
- **"skip tag"** or **"skip"**: Skip tag creation, only commit and push
## Workflow
This command combines `/git-commit` + push operations:
1. ✓ Check staging area
2. ✓ Analyze changes and repository type
3. ✓ Detect project type and version
4. ✓ Generate commit message
5. ✓ Update version number if needed
6. ✓ Commit with generated message
7. ✓ Create version tag
8. ✓ Push commit to remote
9. ✓ Push tag to remote
## Steps
### 1-8. Commit and Tag
Execute the same steps as `/git-commit`:
- Check staging area (must not be empty)
- Collect information (status, diff, logs, tags, AGENTS.md)
- Detect repository type (polyrepo/monorepo)
- Detect project type and version file
- Generate commit message (Conventional Commits, Chinese/English)
- Update version number if needed
- Commit changes
- Create tag if needed
Refer to `/git-commit` for detailed steps or see `skill/git/SKILL.md`.
### 9. Push Commit to Remote
```bash
# Push current branch to origin
git push origin $(git branch --show-current)
```
### 10. Push Tag to Remote
**Only if tag was created:**
**Polyrepo:**
```bash
git push origin <version>
# Example: git push origin 1.2.0
```
**Monorepo:**
```bash
git push origin <subproject>-<version>
# Example: git push origin ios-1.2.0
```
### 11. Display Result
Show summary in Chinese:
```
✓ 提交并推送成功
分支main
提交信息feat(android): 添加用户认证
版本标签android-1.3.0
已推送到远程仓库origin
- 提交a1b2c3d
- 标签android-1.3.0
```
## Comparison with Other Commands
| Command | Commit | Tag | Push Commit | Push Tag |
|---------|--------|-----|-------------|----------|
| `/git-commit` | ✓ | ✓ | ✗ | ✗ |
| `/git-push` | ✓ | ✓ | ✓ | ✓ |
| `/git-push-tags` | ✗ | ✗ | ✗ | ✓ (all tags) |
## Use Cases
- **Quick workflow**: Commit and push in one command
- **Release preparation**: Create version tag and push for CI/CD
- **Daily development**: Commit and sync with remote immediately
## When to Use Which Command
**Use `/git-commit`** (local only):
- You want to review before pushing
- Working on feature branch not ready to share
- Creating multiple commits before one push
**Use `/git-push`** (commit + push):
- Ready to share changes immediately
- Main branch development with CI/CD
- Quick fixes that should be synced now
**Use `/git-push-tags`** (tags only):
- Already committed but forgot to push tags
- Want to push multiple accumulated tags at once
- Tag-only sync without new commits
## Error Handling
### If Staging Area is Empty
```
暂存区为空,请先使用 `git add` 添加文件。
```
**Action:** Terminate, user must stage files first.
### If Push Fails
Common reasons:
- Remote branch protection
- Need to pull first (diverged history)
- No permission to push
**Action:** Display error in Chinese, suggest solutions:
```
✗ 推送失败
原因:远程分支有更新,需要先拉取
建议操作:
1. git pull --rebase origin main
2. 解决冲突(如有)
3. 重新运行 /git-push
```
### If Remote Rejects Tag
If tag already exists on remote:
```
✗ 标签推送失败
原因:远程仓库已存在标签 1.2.0
建议操作:
1. 删除本地标签git tag -d 1.2.0
2. 更新版本号后重新提交
```
## Notes
- **Main branch**: Default push target is `main` (not `master`)
- **Conventional Commits**: Auto-generated messages follow standard format
- **Semantic Versioning**: Automatic version bumping based on change type
- **Polyrepo/Monorepo**: Automatically detects and uses correct tag format
- **Platform-specific**: Commit messages in Chinese (macOS/Linux) or English (Windows)
## Related Commands
- `/git-status` - Check changes before committing
- `/git-commit` - Commit locally without pushing
- `/git-push-tags` - Push only tags (no commits)
## Reference
Complete git workflow guide: `skill/git/SKILL.md`
Quick command reference: `skill/git/quick-reference.md`

54
command/git-status.md Normal file
View File

@@ -0,0 +1,54 @@
---
description: Check git working directory status and file changes
---
# git-status
Check current git repository status and display file changes in a clear format.
## What It Does
- Shows current branch
- Lists changed files (unstaged and staged)
## Steps
Execute the following commands in parallel:
```bash
# Current branch
git branch --show-current
# Repository status
git status
# List changed files only
echo "=== Unstaged Changes ==="
git diff --name-only
echo "=== Staged Changes ==="
git diff --cached --name-only
```
## Output Format
Present the information in Chinese with clear sections:
```
当前分支main
未暂存的文件 (3):
- src/index.js
- src/utils.js
- README.md
已暂存的文件 (2):
- package.json
- src/config.js
```
## Use Cases
- Quick status check before committing
- Review what files have changed
- Check if you're on the correct branch

168
command/gitea-config.md Normal file
View File

@@ -0,0 +1,168 @@
---
description: View current Gitea configuration and runner status
---
# gitea-config
查看当前 Gitea 配置信息和 Runner 状态。
## Features
- 显示配置的 Gitea URL
- 显示默认组织
- 验证 Token 状态和关联用户
- 显示已配置的 Runner 数量和列表
- 显示配置文件路径
## Steps
### 1. Check Configuration File
```bash
config_dir="$HOME/.config/gitea"
config_file="$config_dir/config.env"
if [ ! -f "$config_file" ]; then
echo "❌ Gitea 未配置"
echo "请运行 /gitea-reset 进行配置"
exit 1
fi
```
### 2. Load and Display Configuration
```bash
source "$config_file"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "当前 Gitea 配置"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " URL: $GITEA_URL"
echo " 默认组织: ${GITEA_DEFAULT_ORG:-<未设置>}"
echo " 配置文件: $config_file"
echo ""
```
### 3. Validate Token and Display User Info
```bash
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: token $GITEA_TOKEN" \
"${GITEA_URL}/api/v1/user")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" = "200" ]; then
username=$(echo "$body" | jq -r '.login')
email=$(echo "$body" | jq -r '.email // "<未设置>"')
echo " Token 状态: ✓ 有效"
echo " 登录用户: $username"
echo " 邮箱: $email"
else
echo " Token 状态: ✗ 无效或已过期"
fi
```
### 4. Display Runner Information
```bash
runners_dir="$config_dir/runners"
if [ -d "$runners_dir" ]; then
runner_count=$(ls -1 "$runners_dir" 2>/dev/null | wc -l | tr -d ' ')
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Runner 信息"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 已配置 Runner 数量: $runner_count"
echo " Runner 目录: $runners_dir"
if [ "$runner_count" -gt 0 ]; then
echo ""
echo " 已配置的 Runners:"
ls -1 "$runners_dir" | while read runner; do
# Check if running
config_file="$runners_dir/$runner/config.yaml"
if [ -f "$config_file" ]; then
if pgrep -f "act_runner daemon --config $config_file" > /dev/null; then
status="🟢"
else
status="🔴"
fi
echo " $status $runner"
else
echo " ⚠️ $runner (配置文件缺失)"
fi
done
fi
else
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Runner 信息"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 未配置任何 Runner"
fi
```
### 5. Display Management Commands
```bash
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "管理命令"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 重置配置: /gitea-reset"
echo " 切换组织: /gitea-switch-org <org-name>"
echo " 列出 Runners: /gitea-list-runners"
echo " 创建仓库: /create-gitea-repo <repo-name>"
echo ""
```
## Output Example
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
当前 Gitea 配置
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
URL: https://git.digitevents.com
默认组织: ai
配置文件: /Users/voson/.config/gitea/config.env
Token 状态: ✓ 有效
登录用户: your_username
邮箱: your_username@example.com
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Runner 信息
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
已配置 Runner 数量: 2
Runner 目录: /Users/voson/.config/gitea/runners
已配置的 Runners:
🟢 runner-macbook-pro
🔴 runner-mac-mini
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
管理命令
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
重置配置: /gitea-reset
切换组织: /gitea-switch-org <org-name>
列出 Runners: /gitea-list-runners
创建仓库: /create-gitea-repo <repo-name>
```
## Notes
- 使用 `jq` 解析 JSON 响应
- 检查 runner 进程使用 `pgrep`
- Token 验证通过调用 `/api/v1/user` endpoint
- Runner 状态:🟢 运行中、🔴 已停止、⚠️ 配置异常

View File

@@ -0,0 +1,256 @@
---
description: Create a new Git repository on Gitea
---
# gitea-create-repo
Create a new Git repository on Gitea.
## Features
- Create new repository under specified organization or user via Gitea API
- Support creating private or public repositories
- Automatically add remote repository address after successful creation
## User Input Format
User can specify parameters in the following format:
```
[<owner>/]<repo> [private|public]
```
- `owner`: Organization name or username (optional, uses `GITEA_DEFAULT_ORG` if set, otherwise uses current user)
- `repo`: Repository name (required)
- `private|public`: Visibility (optional, default `private`)
**Examples**:
- `my-project` - Create private repository under default organization (or current user if not set)
- `ai/my-project` - Create private repository my-project under ai organization
- `ai/my-project public` - Create public repository my-project under ai organization
- `username/test private` - Create private repository test under username user
## Configuration
Load configuration from `~/.config/gitea/config.env`:
| Config Item | Source |
| --- | --- |
| Gitea Server URL | `GITEA_URL` from config.env |
| API Token | `GITEA_TOKEN` from config.env |
| Default Organization | `GITEA_DEFAULT_ORG` from config.env (optional) |
## Steps
### 0. Load Configuration
Before executing, load Gitea configuration:
```bash
config_file="$HOME/.config/gitea/config.env"
if [ ! -f "$config_file" ]; then
echo "❌ Gitea 未配置,请运行 /gitea-reset 进行初始化"
exit 1
fi
source "$config_file"
# Validate required variables
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
echo "❌ 配置文件不完整,请运行 /gitea-reset 重新配置"
exit 1
fi
```
### 1. Parse User Input
Parse from user input:
- `owner`: Organization name or username
- `repo`: Repository name
- `visibility`: `private` (default) or `public`
**Input parsing logic**:
```bash
input="$1"
visibility="${2:-private}"
# Parse owner/repo
if [[ "$input" =~ / ]]; then
owner=$(echo "$input" | cut -d'/' -f1)
repo=$(echo "$input" | cut -d'/' -f2)
else
# Use default organization if available, otherwise use current user
if [ -z "$GITEA_DEFAULT_ORG" ]; then
# Get current user from Gitea API
owner=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
"${GITEA_URL}/api/v1/user" | jq -r '.login')
if [ -z "$owner" ] || [ "$owner" = "null" ]; then
echo "❌ 无法获取当前用户信息,请使用 owner/repo 格式"
exit 1
fi
echo "使用当前用户: $owner"
else
owner="$GITEA_DEFAULT_ORG"
echo "使用默认组织: $owner"
fi
repo="$input"
fi
# Convert visibility to boolean
private_bool=$([ "$visibility" = "private" ] && echo "true" || echo "false")
```
**Input validation**:
- Repository name can only contain letters, numbers, underscores, hyphens and dots
```bash
if ! [[ "$repo" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
echo "❌ 仓库名只能包含字母、数字、下划线、连字符和点"
exit 1
fi
```
### 2. Call Gitea API to Create Repository
Use curl to call Gitea API with configuration:
```bash
echo "正在创建仓库: $owner/$repo ($visibility)"
# Try organization repository first
response=$(curl -s -w "\n%{http_code}" -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"${repo}\",
\"private\": ${private_bool},
\"auto_init\": false,
\"default_branch\": \"main\"
}" \
"${GITEA_URL}/api/v1/orgs/${owner}/repos")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
# If 404, try user repository
if [ "$http_code" = "404" ]; then
echo "⚠️ 组织不存在,尝试创建用户仓库..."
response=$(curl -s -w "\n%{http_code}" -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"${repo}\",
\"private\": ${private_bool},
\"auto_init\": false,
\"default_branch\": \"main\"
}" \
"${GITEA_URL}/api/v1/user/repos")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
fi
```
> Note: First try organization API, if 404 then try user API.
### 3. Handle Response
```bash
case "$http_code" in
201)
echo "✓ 仓库创建成功"
;;
409)
echo "❌ 仓库已存在: $owner/$repo"
echo "查看仓库: ${GITEA_URL}/$owner/$repo"
exit 1
;;
404)
echo "❌ Owner 不存在或无权限: $owner"
exit 1
;;
*)
echo "❌ 创建失败 (HTTP $http_code)"
echo "$body" | jq -r '.message // empty'
exit 1
;;
esac
# Extract repository info
html_url=$(echo "$body" | jq -r '.html_url')
clone_url=$(echo "$body" | jq -r '.clone_url')
ssh_url=$(echo "$body" | jq -r '.ssh_url')
```
**Response Handling**:
- **HTTP 201**: Repository created successfully
- **HTTP 409**: Repository already exists
- **HTTP 404**: Owner does not exist or no permission
- **Other**: API error, display error message
### 4. Ask Whether to Add Remote Repository
Ask user whether to add the newly created repository as current project's remote repository.
**If user confirms**:
1. Check if current directory is a Git repository:
```bash
git rev-parse --is-inside-work-tree
```
2. If not a Git repository, ask whether to initialize:
```bash
git init
```
3. Check if origin remote already exists:
```bash
git remote get-url origin
```
4. Add or update remote repository:
- If no origin: `git remote add origin <clone_url>`
- If origin exists: Ask whether to overwrite, after confirmation execute `git remote set-url origin <clone_url>`
### 5. Output Result Summary
Output creation result summary:
```bash
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "仓库创建成功"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 名称: $owner/$repo"
echo " 可见性: $visibility"
echo " Web URL: $html_url"
echo " HTTPS URL: $clone_url"
echo " SSH URL: $ssh_url"
echo ""
```
**Example Output**:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
仓库创建成功
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名称: ai/my-project
可见性: private
Web URL: https://git.digitevents.com/ai/my-project
HTTPS URL: https://git.digitevents.com/ai/my-project.git
SSH URL: git@git.digitevents.com:ai/my-project.git
```
## Notes
- **Permission check**: Ensure Token has permission to create repository
- **Organization vs User**: Creating organization repository and user repository use different API endpoints
- **Repository naming**: Follow Gitea naming rules, avoid special characters

View File

@@ -0,0 +1,662 @@
---
description: Create and start a Gitea Actions runner (default host mode)
---
# gitea-create-runner
创建并启动 Gitea Actions Runner默认 host 模式)。
## 命令说明
此命令用于快速创建和启动一个 Gitea Actions Runner。默认使用 host 模式,自动检测系统环境并配置。
**重要**这是一个可执行命令AI 应该按照以下步骤执行操作。
## Features
- 自动检查并安装 act_runner如果未安装
- 自动加载 Gitea 配置(如果不存在则提示初始化)
- 默认使用 host 模式(支持 Android SDK、iOS 构建等原生工具)
- 智能检测系统环境OS、架构并生成合适的 labels
- 自动注册并后台启动 runner
- 优先尝试创建全局 runner需要管理员权限
- 权限不足时自动降级到组织 runner
## User Input Format
无需参数,运行后自动创建。可选提供 runner 名称。
```bash
/gitea-create-runner
# 或
/gitea-create-runner my-runner-name
```
## AI 执行指导
当用户调用此命令时AI 应该:
1. **检查 act_runner 安装**:如果未安装,自动安装
2. **加载 Gitea 配置**:如果不存在,提示用户先初始化
3. **生成 runner 名称**:基于主机名或用户输入
4. **检测系统环境**:自动生成 labels
5. **创建 runner 目录**:在 `~/.config/gitea/runners/` 下创建
6. **生成配置文件**:默认 host 模式配置
7. **获取注册 token**:优先全局,失败则降级到组织
8. **注册 runner**:使用 act_runner register
9. **启动 runner**:后台启动并显示状态
## Implementation Steps
### 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 <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

View File

@@ -0,0 +1,595 @@
---
description: Delete a Gitea runner configuration (interactive)
---
# gitea-delete-runner
删除 Gitea Runner 配置(交互式选择)。
## 命令说明
此命令用于从 Gitea 服务器删除 runner 配置。支持交互式选择单个或所有 runners。
**重要**这是一个可执行命令AI 应该按照以下步骤执行操作,并与用户进行交互。
## Features
- 显示 Gitea 服务器上的全局 runners
- 交互式选择要删除的 runner
- 支持删除单个或所有 runners
- 删除 runner 配置目录(包括 cache 和 workspace
- 停止运行中的 runner 进程
- 自动从 Gitea 服务器注销 runner
- 安全确认机制(需要用户输入 'yes'
## User Input Format
无需参数,运行后交互式选择。
```bash
/gitea-delete-runner
```
## AI 执行指导
当用户调用此命令时AI 应该:
1. **获取并展示 runner 列表**:调用 Gitea API 获取服务器上的全局 runners并以清晰的格式展示给用户
2. **等待用户选择**:让用户选择要删除的 runner序号、'all' 或 'q'
3. **确认操作**:在删除前要求用户输入 'yes' 确认
4. **执行删除**:按照三步流程删除选中的 runners
5. **显示结果**:展示删除操作的详细结果
**注意**:此命令需要与用户进行多次交互,不要一次性执行所有步骤。
## Implementation Steps
### 1. Load Configuration
```bash
config_file_main="$HOME/.config/gitea/config.env"
if [ ! -f "$config_file_main" ]; then
echo "❌ 未找到 Gitea 配置文件"
echo " 路径: $config_file_main"
exit 1
fi
source "$config_file_main"
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
echo "❌ Gitea 配置不完整"
echo " 需要 GITEA_URL 和 GITEA_TOKEN"
exit 1
fi
```
### 2. Fetch and Display Runners
**AI 执行**:运行以下命令获取并显示 runners 列表,然后等待用户选择。
```bash
source "$HOME/.config/gitea/config.env"
echo "正在从 Gitea 服务器获取全局 runners..."
echo ""
# Fetch global runners from Gitea API
api_endpoint="${GITEA_URL}/api/v1/admin/actions/runners"
response=$(curl -s -H "Authorization: token $GITEA_TOKEN" "$api_endpoint")
if [ $? -ne 0 ] || [ -z "$response" ]; then
echo "❌ 无法连接到 Gitea 服务器"
exit 1
fi
# Parse runners using jq
if ! command -v jq &> /dev/null; then
echo "❌ 需要安装 jq 工具"
echo " 安装: brew install jq"
exit 1
fi
# Check if response is valid JSON
if ! echo "$response" | jq empty 2>/dev/null; then
echo "❌ API 返回数据格式错误"
echo " 请检查 Token 权限(需要 admin 权限)"
exit 1
fi
# Extract runner information (注意API 返回格式是 {"runners": [...], "total_count": N})
runner_count=$(echo "$response" | jq '.runners | length')
if [ "$runner_count" -eq 0 ]; then
echo "⚠️ 服务器上没有全局 runners"
exit 0
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Gitea 全局 Runners (共 $runner_count 个)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Display runners with formatted output
echo "$response" | jq -r '.runners[] | [.id, .name, .status] | @tsv' | \
awk 'BEGIN{i=1} {
printf "%2d. %-30s [ID: %-5s] %s\n",
i++, $2, $1, ($3=="online"?"🟢 在线":"🔴 离线")
}'
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "选择要删除的 Runner"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 输入序号: 删除单个 runner"
echo " 输入 'all': 删除所有 runners"
echo " 输入 'q' 或 'quit': 取消"
echo ""
# Save runner data to temp file for later use
echo "$response" | jq -r '.runners[] | "\(.id)|\(.name)"' > /tmp/gitea_runners.txt
```
**AI 指导**:执行完上述命令后,等待用户输入选择(序号、'all' 或 'q')。
### 3. Process User Selection
**AI 指导**:根据用户的输入(从步骤 2 获取),执行相应的处理逻辑。
- 如果用户输入 'q' 或 'quit':取消操作,清理临时文件
- 如果用户输入 'all':准备删除所有 runners进入步骤 4 确认
- 如果用户输入序号:验证并准备删除对应的 runner进入步骤 4 确认
**选择处理脚本**AI 根据用户输入执行相应部分):
```bash
# 假设用户选择存储在变量 $USER_SELECTION 中
if [ "$USER_SELECTION" = "q" ] || [ "$USER_SELECTION" = "quit" ]; then
echo "已取消"
rm -f /tmp/gitea_runners.txt
exit 0
fi
# Read runner data from temp file
mapfile -t runner_data < /tmp/gitea_runners.txt
runner_count=${#runner_data[@]}
if [ "$USER_SELECTION" = "all" ]; then
# Prepare to delete all runners
echo ""
echo "⚠️ 将删除所有 $runner_count 个 runners"
echo ""
# 继续到步骤 4 显示警告并确认
else
# Validate selection is a number
if ! [[ "$USER_SELECTION" =~ ^[0-9]+$ ]]; then
echo "❌ 无效的选择"
rm -f /tmp/gitea_runners.txt
exit 1
fi
# Validate selection is in range
if [ "$USER_SELECTION" -lt 1 ] || [ "$USER_SELECTION" -gt "$runner_count" ]; then
echo "❌ 选择超出范围 (1-$runner_count)"
rm -f /tmp/gitea_runners.txt
exit 1
fi
# Get selected runner info
selected_data="${runner_data[$((USER_SELECTION-1))]}"
IFS='|' read -r id name <<< "$selected_data"
echo ""
echo "已选择: $name (ID: $id)"
echo ""
# 继续到步骤 4 显示警告并确认
fi
```
### 4. Display Warning and Get Confirmation
**AI 执行**:显示删除警告,列出将要删除的 runners然后等待用户输入 'yes' 确认。
```bash
echo "⚠️ 警告: 此操作将执行以下操作:"
echo " - 从 Gitea 服务器注销 runner"
echo " - 停止本地运行的 runner 进程"
echo " - 删除 runner 配置文件"
echo " - 删除 cache 和 workspace 目录"
echo " - 删除所有相关数据"
echo ""
# List runners to be deleted
if [ "$USER_SELECTION" = "all" ]; then
echo "将删除以下 runners:"
cat /tmp/gitea_runners.txt | while IFS='|' read -r id name; do
echo " - $name (ID: $id)"
done
else
# Single runner already displayed in step 3
:
fi
echo ""
```
**AI 指导**:显示完警告后,等待用户输入确认('yes' 继续,其他取消)。
### 5. Execute Deletion
**AI 执行**:如果用户确认(输入 'yes'),执行删除操作;否则取消。
```bash
# 假设用户确认输入存储在 $USER_CONFIRM 中
if [ "$USER_CONFIRM" != "yes" ]; then
echo "已取消"
rm -f /tmp/gitea_runners.txt
exit 0
fi
source "$HOME/.config/gitea/config.env"
echo "开始删除..."
echo ""
success_count=0
fail_count=0
runners_dir="$HOME/.config/gitea/runners"
# Process all selected runners
while IFS='|' read -r runner_id runner_name; do
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "删除: $runner_name (ID: $runner_id)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Find local runner directory by ID (处理 runners/* 不存在的情况)
runner_dir=""
if [ -d "$runners_dir" ]; then
shopt -s nullglob # 避免 * 无匹配时报错
for dir in "$runners_dir"/*; do
if [ -f "$dir/.runner" ]; then
local_id=$(jq -r '.id // ""' "$dir/.runner" 2>/dev/null)
if [ "$local_id" = "$runner_id" ]; then
runner_dir="$dir"
break
fi
fi
done
shopt -u nullglob
fi
# Step 1: Unregister from Gitea server
echo "[1/3] 从 Gitea 服务器注销..."
api_endpoint="${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}"
http_code=$(curl -s -w "%{http_code}" -o /dev/null \
-X DELETE \
-H "Authorization: token $GITEA_TOKEN" \
"$api_endpoint")
if [ "$http_code" = "204" ]; then
echo " ✓ 已从服务器注销"
else
echo " ⚠️ 注销失败 (HTTP $http_code)"
fi
# Step 2: Stop local process if running
echo "[2/3] 检查本地进程..."
if [ -n "$runner_dir" ] && [ -f "$runner_dir/config.yaml" ]; then
config_file="$runner_dir/config.yaml"
if pgrep -f "act_runner daemon --config $config_file" > /dev/null 2>&1; then
pid=$(pgrep -f "act_runner daemon --config $config_file")
# Check if runner is busy (executing jobs)
# 从服务器获取 runner 的 busy 状态
runner_info=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
"${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}")
is_busy=$(echo "$runner_info" | jq -r '.busy // false')
if [ "$is_busy" = "true" ]; then
echo " ⚠️ 警告: Runner 正在执行 job"
echo " 强制停止可能导致 job 中断和数据不一致"
echo ""
echo " 选项:"
echo " 1. 等待 job 完成后再停止(推荐)"
echo " 2. 强制立即停止"
echo ""
# AI 应在此处等待用户选择
# 假设用户选择存储在 $STOP_CHOICE 中
if [ "$STOP_CHOICE" = "1" ]; then
echo " 等待 job 完成..."
# 轮询检查 runner 是否仍然 busy
max_wait=300 # 最多等待 5 分钟
waited=0
while [ $waited -lt $max_wait ]; do
sleep 10
waited=$((waited + 10))
runner_info=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
"${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}")
is_busy=$(echo "$runner_info" | jq -r '.busy // false')
if [ "$is_busy" = "false" ]; then
echo " ✓ Job 已完成"
break
fi
echo " 仍在执行... (已等待 ${waited}s)"
done
if [ $waited -ge $max_wait ]; then
echo " ⚠️ 等待超时,将强制停止"
fi
else
echo " ⚠️ 用户选择强制停止"
fi
fi
# 优雅停止 runner
echo " 正在停止进程 (PID: $pid)..."
kill "$pid" 2>/dev/null
sleep 2
# 如果进程还在运行,强制杀死
if pgrep -f "act_runner daemon --config $config_file" > /dev/null 2>&1; then
echo " 进程未响应,强制终止..."
kill -9 "$pid" 2>/dev/null
sleep 1
fi
# 验证进程已停止
if pgrep -f "act_runner daemon --config $config_file" > /dev/null 2>&1; then
echo " ❌ 无法停止进程"
else
echo " ✓ 进程已停止"
fi
else
echo " ✓ 未运行"
fi
else
echo " ⓘ 未找到本地配置"
fi
# Step 3: Delete local directory
echo "[3/3] 删除本地配置..."
if [ -n "$runner_dir" ] && [ -d "$runner_dir" ]; then
rm -rf "$runner_dir"
if [ ! -d "$runner_dir" ]; then
echo " ✓ 本地配置已删除"
((success_count++))
else
echo " ❌ 删除失败"
((fail_count++))
fi
else
# Server runner deleted, but no local config
((success_count++))
echo " ⓘ 无本地配置需要删除"
fi
echo ""
done < /tmp/gitea_runners.txt
# Cleanup temp file
rm -f /tmp/gitea_runners.txt
```
### 6. Display Summary
**AI 执行**:显示删除操作的最终结果。
```bash
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "删除完成"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "成功: $success_count"
if [ $fail_count -gt 0 ]; then
echo "失败: $fail_count"
fi
echo ""
echo "管理命令:"
echo " 查看剩余 runners: /gitea-list-runners"
echo " 创建新 runner: /gitea-create-runner"
echo ""
```
**AI 指导**:删除完成后,可以选择性地验证服务器上的 runner 数量,确认删除成功。
## Output Example
### Example 1: Delete Single Runner
```
正在从 Gitea 服务器获取全局 runners...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Gitea 全局 Runners (共 3 个)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. runner-mac-mini4 [ID: 42 ] 🟢 在线
系统: darwin 架构: arm64 最后在线: 2026-01-12 10:30
2. runner-macbook-pro [ID: 43 ] 🔴 离线
系统: darwin 架构: arm64 最后在线: 2026-01-10 18:45
3. runner-linux-server [ID: 44 ] 🟢 在线
系统: linux 架构: amd64 最后在线: 2026-01-12 10:25
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
选择要删除的 Runner
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
输入序号: 删除单个 runner
输入 'all': 删除所有 runners
输入 'q' 或 'quit': 取消
请选择: 2
已选择: runner-macbook-pro (ID: 43)
⚠️ 警告: 此操作将执行以下操作:
- 从 Gitea 服务器注销 runner
- 停止本地运行的 runner 进程
- 删除 runner 配置文件
- 删除 cache 和 workspace 目录
- 删除所有相关数据
确认删除? 输入 'yes' 继续: yes
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
删除: runner-macbook-pro (ID: 43)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[1/3] 从 Gitea 服务器注销...
✓ 已从服务器注销
[2/3] 检查本地进程...
✓ 未运行
[3/3] 删除本地配置...
✓ 本地配置已删除
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
删除完成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
成功: 1 个
管理命令:
查看剩余 runners: /gitea-list-runners
创建新 runner: /gitea-create-runner
```
### Example 2: Delete All Runners
```
正在从 Gitea 服务器获取全局 runners...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Gitea 全局 Runners (共 2 个)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. runner-mac-mini4 [ID: 42 ] 🟢 在线
系统: darwin 架构: arm64 最后在线: 2026-01-12 10:30
2. runner-linux-server [ID: 44 ] 🟢 在线
系统: linux 架构: amd64 最后在线: 2026-01-12 10:25
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
选择要删除的 Runner
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
输入序号: 删除单个 runner
输入 'all': 删除所有 runners
输入 'q' 或 'quit': 取消
请选择: all
⚠️ 将删除所有 2 个 runners
⚠️ 警告: 此操作将执行以下操作:
- 从 Gitea 服务器注销 runner
- 停止本地运行的 runner 进程
- 删除 runner 配置文件
- 删除 cache 和 workspace 目录
- 删除所有相关数据
将删除 2 个 runners:
- runner-mac-mini4 (ID: 42)
- runner-linux-server (ID: 44)
确认删除? 输入 'yes' 继续: yes
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
删除: runner-mac-mini4 (ID: 42)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[1/3] 从 Gitea 服务器注销...
✓ 已从服务器注销
[2/3] 检查本地进程...
正在停止进程 (PID: 12345)...
✓ 进程已停止
[3/3] 删除本地配置...
✓ 本地配置已删除
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
删除: runner-linux-server (ID: 44)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[1/3] 从 Gitea 服务器注销...
✓ 已从服务器注销
[2/3] 检查本地进程...
ⓘ 未找到本地配置
[3/3] 删除本地配置...
ⓘ 无本地配置需要删除
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
删除完成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
成功: 2 个
管理命令:
查看剩余 runners: /gitea-list-runners
创建新 runner: /gitea-create-runner
```
## Safety Features
- **服务器数据优先**:直接从 Gitea 服务器获取 runner 列表,确保准确性
- **交互式选择**:支持选择单个或所有 runners避免误删
- **双重确认**:需要输入 'yes' 进行最终确认(防止误删)
- **Busy 状态检测**:检查 runner 是否正在执行 job
- 如果 runner 正在执行 job给用户选择
- 等待 job 完成后停止(推荐)
- 强制立即停止(有风险)
- **优雅停止**:先尝试 SIGTERM2 秒后才使用 SIGKILL
- **服务器注销**:自动从 Gitea 服务器注销 runner
- **三步删除流程**
1. 从服务器注销
2. 停止本地进程(检测 busy 状态)
3. 删除本地配置
- **清晰提示**:显示每个步骤的执行状态和警告信息
- **批量删除支持**:可一次性删除所有 runners
- **错误处理**:各步骤独立执行,部分失败不影响其他操作
- **超时保护**:等待 job 完成最多 5 分钟,超时后强制停止
## Technical Notes
- **必需工具**:需要安装 `jq` 工具(`brew install jq`
- **权限要求**:需要 Gitea admin 权限(全局 runner 管理)
- **配置文件**:读取 `~/.config/gitea/config.env` 获取 API 配置
- **本地匹配**:通过 runner ID 匹配本地配置目录
- **服务器同步**:从服务器注销后再删除本地配置
- **无本地配置**:如果只存在服务器记录,仅注销服务器端
- **取消操作**:输入 'q' 或 'quit' 可随时取消
- **临时文件**:使用 `/tmp/gitea_runners.txt` 存储临时数据,操作完成后自动清理
- **API 格式**Gitea API 返回格式为 `{"runners": [...], "total_count": N}`,不是直接的数组
- **Busy 检测**:通过 API 的 `busy` 字段判断 runner 是否正在执行 job
- **停止信号**
- `kill $pid` (SIGTERM): 优雅停止,给进程清理资源的机会
- `kill -9 $pid` (SIGKILL): 强制终止,无法被捕获或忽略
- **等待策略**:如果 runner busy最多等待 5 分钟300 秒),每 10 秒检查一次状态
## AI 执行流程总结
当用户调用 `/gitea-delete-runner`AI 应该按以下流程执行:
1. **步骤 1**:加载并验证 Gitea 配置
2. **步骤 2**:获取并展示 runners 列表 → **等待用户选择**
3. **步骤 3**:处理用户选择,验证输入
4. **步骤 4**:显示删除警告和列表 → **等待用户确认**
5. **步骤 5**:执行删除操作
- 5.1: 从服务器注销
- 5.2: 检查并停止本地进程
- **如果 runner 正在执行 jobbusy** → **等待用户选择**(等待完成 or 强制停止)
- 5.3: 删除本地配置
6. **步骤 6**:显示操作结果摘要
**重要**:这是一个交互式命令,可能需要在以下位置等待用户输入:
- 步骤 2: 选择要删除的 runner
- 步骤 4: 确认删除操作
- 步骤 5.2: 如果 runner 正在执行 job选择等待或强制停止
不要一次性执行所有步骤。

View File

@@ -0,0 +1,202 @@
---
description: List all configured Gitea runners and their status
---
# gitea-list-runners
列出所有已配置的 Gitea Runners 及其运行状态。
## Features
- 显示所有已配置的 runner
- 检查 runner 运行状态(运行中/已停止)
- 显示 runner 配置信息labels、capacity 等)
- 显示 runner ID 和名称
- 提供启动命令
## Steps
### 1. Check Configuration
```bash
config_dir="$HOME/.config/gitea"
runners_dir="$config_dir/runners"
if [ ! -d "$runners_dir" ]; then
echo "❌ 未找到 runner 目录"
echo "请先创建 runner"
exit 1
fi
```
### 2. List All Runners
```bash
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Gitea Runners"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
runners=$(ls -1 "$runners_dir" 2>/dev/null)
if [ -z "$runners" ]; then
echo "未配置任何 runner"
echo ""
echo "创建 runner"
echo " /gitea-create-runner"
exit 0
fi
runner_count=$(echo "$runners" | wc -l | tr -d ' ')
echo "总计: $runner_count 个 runner"
echo ""
```
### 3. Display Each Runner's Status
```bash
for runner in $runners; do
runner_dir="$runners_dir/$runner"
config_file="$runner_dir/config.yaml"
echo "[$runner]"
# Check if config exists
if [ ! -f "$config_file" ]; then
echo " ⚠️ 配置文件缺失"
echo ""
continue
fi
# Check if runner process is running
if pgrep -f "act_runner daemon --config $config_file" > /dev/null; then
status="🟢 运行中"
pid=$(pgrep -f "act_runner daemon --config $config_file")
else
status="🔴 已停止"
pid="-"
fi
echo " 状态: $status"
echo " PID: $pid"
# Display configuration info
if command -v yq &> /dev/null; then
# Use yq if available
capacity=$(yq eval '.runner.capacity' "$config_file" 2>/dev/null)
timeout=$(yq eval '.runner.timeout' "$config_file" 2>/dev/null)
else
# Fallback to grep
capacity=$(grep "capacity:" "$config_file" | awk '{print $2}')
timeout=$(grep "timeout:" "$config_file" | awk '{print $2}')
fi
echo " 容量: ${capacity:-N/A}"
echo " 超时: ${timeout:-N/A}"
# Display labels
labels=$(grep -A 10 "labels:" "$config_file" | grep "^ -" | sed 's/^ - "//' | sed 's/"$//' | tr '\n' ',' | sed 's/,$//')
if [ -n "$labels" ]; then
echo " Labels: $labels"
fi
# Display runner info from .runner file
if [ -f "$runner_dir/.runner" ]; then
if command -v jq &> /dev/null; then
runner_id=$(jq -r '.id // "N/A"' "$runner_dir/.runner" 2>/dev/null)
runner_name=$(jq -r '.name // "N/A"' "$runner_dir/.runner" 2>/dev/null)
echo " ID: $runner_id"
echo " 名称: $runner_name"
fi
fi
echo " 路径: $runner_dir"
# Display start command
echo ""
echo " 启动命令:"
echo " act_runner daemon --config $config_file"
# Display background start command
if [ "$status" = "🔴 已停止" ]; then
echo ""
echo " 后台启动:"
echo " nohup act_runner daemon --config $config_file > $runner_dir/runner.log 2>&1 &"
fi
echo ""
done
```
### 4. Display Summary Commands
```bash
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "管理命令"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 查看配置: /gitea-config"
echo " 创建 runner: /gitea-create-runner"
echo " 删除 runner: /gitea-delete-runner"
echo ""
```
## Output Example
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Gitea Runners
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总计: 2 个 runner
[runner-macbook-pro]
状态: 🟢 运行中
PID: 12345
容量: 2
超时: 3h
Labels: self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
ID: 42
名称: runner-macbook-pro
路径: /Users/voson/.config/gitea/runners/runner-macbook-pro
启动命令:
act_runner daemon --config /Users/voson/.config/gitea/runners/runner-macbook-pro/config.yaml
[runner-mac-mini]
状态: 🔴 已停止
PID: -
容量: 2
超时: 3h
Labels: self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
ID: 43
名称: runner-mac-mini
路径: /Users/voson/.config/gitea/runners/runner-mac-mini
启动命令:
act_runner daemon --config /Users/voson/.config/gitea/runners/runner-mac-mini/config.yaml
后台启动:
nohup act_runner daemon --config /Users/voson/.config/gitea/runners/runner-mac-mini/config.yaml > /Users/voson/.config/gitea/runners/runner-mac-mini/runner.log 2>&1 &
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
管理命令
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
查看配置: /gitea-config
创建 runner: /gitea-create-runner
删除 runner: /gitea-delete-runner
```
## Notes
- 使用 `pgrep` 检查进程状态
- 优先使用 `yq` 解析 YAMLfallback 到 `grep`
- 优先使用 `jq` 解析 JSON `.runner` 文件
- Runner 状态图标:
- 🟢 运行中
- 🔴 已停止
- ⚠️ 配置异常
- 显示启动命令方便用户复制执行
- 对已停止的 runner额外显示后台启动命令

314
command/gitea-reset.md Normal file
View File

@@ -0,0 +1,314 @@
---
description: Reset Gitea configuration with interactive setup wizard
---
# gitea-reset
重置 Gitea 配置,启动交互式配置向导。
## Features
- 交互式引导配置
- 验证 URL 和 Token
- 检查 Token 权限
- 自动保存配置到 `~/.config/gitea/config.env`
- 创建必要的目录结构
## Steps
### 1. Create Configuration Directory
```bash
config_dir="$HOME/.config/gitea"
config_file="$config_dir/config.env"
# Create directories
mkdir -p "$config_dir/runners"
echo "开始 Gitea 配置向导..."
echo ""
```
### 2. Input Gitea URL
```bash
read -p "请输入 Gitea 实例地址 (例如: https://git.digitevents.com): " gitea_url
# Validate URL format
if ! [[ "$gitea_url" =~ ^https?:// ]]; then
echo "❌ URL 必须以 http:// 或 https:// 开头"
exit 1
fi
# Remove trailing slash
gitea_url="${gitea_url%/}"
echo "✓ URL: $gitea_url"
```
### 3. Input Personal Access Token
```bash
echo ""
read -sp "请输入 Personal Access Token: " gitea_token
echo ""
if [ -z "$gitea_token" ]; then
echo "❌ Token 不能为空"
exit 1
fi
echo "✓ Token 已输入"
```
**Token 获取提示**
在用户输入 Token 前,可以显示帮助信息:
```
提示:获取 Personal Access Token 的步骤:
1. 登录 Gitea
2. 右上角头像 → 设置 → 应用 → 访问令牌
3. 点击 "生成新令牌"
4. 设置令牌名称(如 opencode-cli
5. 选择权限repo, admin:org, write:runner推荐
6. 点击 "生成令牌"
7. 复制生成的 Token
```
### 4. Test Connection
```bash
echo ""
echo "正在测试连接..."
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: token $gitea_token" \
"${gitea_url}/api/v1/user")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" != "200" ]; then
echo "❌ 连接失败 (HTTP $http_code)"
echo "请检查:"
echo " - URL 是否正确"
echo " - Token 是否有效"
echo " - 网络连接是否正常"
exit 1
fi
username=$(echo "$body" | jq -r '.login')
echo "✓ 连接成功!"
echo "✓ 登录用户: $username"
```
### 5. Validate Token Permissions
```bash
echo ""
echo "正在检查 Token 权限..."
# Check repo permission
if curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token $gitea_token" \
"${gitea_url}/api/v1/user/repos" | grep -q "200"; then
echo " ✓ repo (仓库管理)"
has_repo=true
else
echo " ✗ repo (仓库管理) - 缺少"
has_repo=false
fi
# Check org permission
if curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token $gitea_token" \
"${gitea_url}/api/v1/user/orgs" | grep -q "200"; then
echo " ✓ admin:org (组织管理)"
has_org=true
else
echo " ⚠ admin:org (组织管理) - 缺少(创建组织 Runner 时需要)"
has_org=false
fi
# Check runner permission (try to get a registration token)
if curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token $gitea_token" \
"${gitea_url}/api/v1/user/actions/runners/registration-token" 2>/dev/null | grep -q "200"; then
echo " ✓ write:runner (Runner 管理)"
has_runner=true
else
echo " ⚠ write:runner (Runner 管理) - 缺少(创建 Runner 时需要)"
has_runner=false
fi
# Warning if missing critical permissions
if [ "$has_repo" = false ]; then
echo ""
echo "❌ 缺少必需的 repo 权限"
read -p "是否继续? [y/N] " continue_anyway
if [[ ! "$continue_anyway" =~ ^[Yy]$ ]]; then
echo "已取消,请重新创建具有足够权限的 Token"
exit 1
fi
fi
```
### 6. Input Default Organization (Optional)
```bash
echo ""
echo "设置默认组织(可选):"
echo " - 创建仓库时,如果不指定 owner将使用默认组织"
echo " - 创建组织级 Runner 时使用"
echo ""
read -p "请输入默认组织名称 (回车跳过): " default_org
if [ -n "$default_org" ]; then
# Validate organization exists
echo "正在验证组织..."
org_response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: token $gitea_token" \
"${gitea_url}/api/v1/orgs/${default_org}")
org_http_code=$(echo "$org_response" | tail -n1)
if [ "$org_http_code" = "200" ]; then
echo "✓ 组织验证成功: $default_org"
else
echo "⚠️ 组织 '$default_org' 不存在或无权限访问"
read -p "仍然设置为默认组织? [Y/n] " set_anyway
if [[ "$set_anyway" =~ ^[Nn]$ ]]; then
default_org=""
fi
fi
fi
```
### 7. Save Configuration
```bash
echo ""
echo "正在保存配置..."
cat > "$config_file" << EOF
# Gitea Configuration
# Generated at $(date '+%Y-%m-%d %H:%M:%S')
GITEA_URL=$gitea_url
GITEA_TOKEN=$gitea_token
${default_org:+GITEA_DEFAULT_ORG=$default_org}
# Runner Default Settings
GITEA_RUNNER_CAPACITY=2
GITEA_RUNNER_TIMEOUT=3h
# Optional: Override auto-detected labels
# GITEA_RUNNER_LABELS=custom-label-1:host,custom-label-2:host
EOF
# Set restrictive permissions
chmod 600 "$config_file"
# Create .gitignore
cat > "$config_dir/.gitignore" << EOF
config.env
runners/*/.runner
runners/*/.env
EOF
echo "✓ 配置已保存"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "配置完成"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 配置文件: $config_file"
echo " Runner 目录: $config_dir/runners"
echo ""
echo "下一步:"
echo " - 查看配置: /gitea-config"
echo " - 创建 Runner: 告诉 AI '创建一个 runner'"
echo " - 创建仓库: /create-gitea-repo <repo-name>"
echo ""
```
## Configuration File Format
生成的 `~/.config/gitea/config.env` 文件格式:
```bash
# Gitea Configuration
# Generated at 2026-01-12 22:00:00
GITEA_URL=https://git.digitevents.com
GITEA_TOKEN=git_xxxxxxxxxxxxxxxxxxxx
GITEA_DEFAULT_ORG=ai
# Runner Default Settings
GITEA_RUNNER_CAPACITY=2
GITEA_RUNNER_TIMEOUT=3h
# Optional: Override auto-detected labels
# GITEA_RUNNER_LABELS=custom-label-1:host,custom-label-2:host
```
## Output Example
```
开始 Gitea 配置向导...
请输入 Gitea 实例地址 (例如: https://git.digitevents.com): https://git.digitevents.com
✓ URL: https://git.digitevents.com
请输入 Personal Access Token: ****************
✓ Token 已输入
正在测试连接...
✓ 连接成功!
✓ 登录用户: your_username
正在检查 Token 权限...
✓ repo (仓库管理)
✓ admin:org (组织管理)
✓ write:runner (Runner 管理)
设置默认组织(可选):
- 创建仓库时,如果不指定 owner将使用默认组织
- 创建组织级 Runner 时使用
请输入默认组织名称 (回车跳过): ai
正在验证组织...
✓ 组织验证成功: ai
正在保存配置...
✓ 配置已保存
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
配置完成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
配置文件: /Users/voson/.config/gitea/config.env
Runner 目录: /Users/voson/.config/gitea/runners
下一步:
- 查看配置: /gitea-config
- 创建 Runner: 告诉 AI '创建一个 runner'
- 创建仓库: /create-gitea-repo <repo-name>
```
## Security Notes
- 配置文件权限设置为 `600`(仅所有者可读写)
- Token 不会在日志中显示
- 创建 `.gitignore` 文件排除敏感信息
- 建议定期轮换 Token每 3-6 个月)
## Notes
- **必需权限**: `repo` - 创建和管理仓库
- **推荐权限**: `admin:org` - 创建组织级 Runner
- **推荐权限**: `write:runner` - 管理 Runner
- **可选权限**: `admin:repo_hook` - 配置 Webhooks
- Token 只显示一次,请妥善保管
- 重置配置不会影响已创建的 Runner但 Runner 会继续使用旧的注册信息

155
command/gitea-switch-org.md Normal file
View File

@@ -0,0 +1,155 @@
---
description: Switch default Gitea organization
---
# gitea-switch-org
切换默认 Gitea 组织。
## Features
- 更新配置文件中的默认组织
- 验证组织是否存在
- 立即生效,无需重启
## User Input Format
```
<organization_name>
```
**Examples**:
- `ai` - Switch to 'ai' organization
- `my-team` - Switch to 'my-team' organization
## Steps
### 1. Check Configuration
```bash
config_file="$HOME/.config/gitea/config.env"
if [ ! -f "$config_file" ]; then
echo "❌ Gitea 未配置"
echo "请先运行 /gitea-reset 进行配置"
exit 1
fi
source "$config_file"
```
### 2. Parse User Input
```bash
new_org="$1"
if [ -z "$new_org" ]; then
echo "用法: /gitea-switch-org <organization_name>"
echo ""
echo "示例:"
echo " /gitea-switch-org ai"
echo " /gitea-switch-org my-team"
exit 1
fi
```
### 3. Validate Organization Exists
```bash
echo "正在验证组织 '$new_org'..."
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: token $GITEA_TOKEN" \
"${GITEA_URL}/api/v1/orgs/${new_org}")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" != "200" ]; then
echo "❌ 组织 '$new_org' 不存在或无权限访问"
# Suggest available organizations
echo ""
echo "你可以访问的组织:"
curl -s -H "Authorization: token $GITEA_TOKEN" \
"${GITEA_URL}/api/v1/user/orgs" | jq -r '.[].username' | sed 's/^/ - /'
exit 1
fi
org_name=$(echo "$body" | jq -r '.full_name // .username')
echo "✓ 组织验证成功: $org_name"
```
### 4. Update Configuration File
```bash
echo "正在更新配置..."
# Check if GITEA_DEFAULT_ORG already exists in config
if grep -q "^GITEA_DEFAULT_ORG=" "$config_file"; then
# Update existing line (macOS compatible)
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/^GITEA_DEFAULT_ORG=.*/GITEA_DEFAULT_ORG=$new_org/" "$config_file"
else
sed -i "s/^GITEA_DEFAULT_ORG=.*/GITEA_DEFAULT_ORG=$new_org/" "$config_file"
fi
else
# Add new line after GITEA_TOKEN
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "/^GITEA_TOKEN=/a\\
GITEA_DEFAULT_ORG=$new_org
" "$config_file"
else
sed -i "/^GITEA_TOKEN=/a GITEA_DEFAULT_ORG=$new_org" "$config_file"
fi
fi
echo "✓ 默认组织已切换到: $new_org"
```
### 5. Display Summary
```bash
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "切换完成"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " 新的默认组织: $new_org"
echo ""
echo "现在可以:"
echo " - 创建仓库: /create-gitea-repo my-project"
echo " (将创建到 $new_org/my-project"
echo " - 查看配置: /gitea-config"
echo ""
```
## Output Example
```
正在验证组织 'ai'...
✓ 组织验证成功: AI Team
正在更新配置...
✓ 默认组织已切换到: ai
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
切换完成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
新的默认组织: ai
现在可以:
- 创建仓库: /create-gitea-repo my-project
(将创建到 ai/my-project
- 查看配置: /gitea-config
```
## Notes
- 切换组织不会影响已创建的仓库和 Runner
- 仅影响后续创建仓库时的默认 owner
- 可以随时切换到其他组织
- 使用 `jq` 解析 JSON 响应
- macOS 和 Linux 的 `sed` 命令略有不同,需兼容处理

View File

@@ -1,81 +0,0 @@
---
description: Pull latest OpenCode config changes from remote
agent: build
---
# sync-oc-pull
Pull latest changes for OpenCode configuration from remote repository.
## Use Cases
When you updated OpenCode configuration on another device, or team members shared new commands/configurations, use this command to sync to local.
## Steps
### 1. Switch to OpenCode Config Directory
```bash
cd ~/.config/opencode
```
### 2. Check Local Status
Run `git status` to check if there are uncommitted local changes.
**If there are uncommitted changes**:
- List changed files
- Ask user how to handle:
- **Stash**: `git stash` to save local changes, restore after pull
- **Discard**: `git checkout -- .` to discard local changes
- **Cancel**: Terminate operation, let user handle manually
### 3. Pull Remote Changes
```bash
git pull origin main
```
### 4. Handle Conflicts (if any)
If conflicts occur during pull:
1. List conflicting files
2. Open conflict files, analyze conflict content
3. Ask user to choose:
- **Keep local version**: Use `git checkout --ours <file>`
- **Use remote version**: Use `git checkout --theirs <file>`
- **Manual merge**: Prompt user to manually edit then execute `git add <file>`
4. After resolving all conflicts, complete merge:
```bash
git add .
git commit -m "chore: resolve merge conflicts"
```
### 5. Restore Stashed Changes (if any)
If `git stash` was used in step 2:
```bash
git stash pop
```
If conflicts occur during restore, handle according to step 4.
### 6. Show Update Summary
After pull completes, show update content:
```bash
git log --oneline -5
```
List newly added or modified command files to help user understand what new configurations are available.
## Notes
- **Backup important configs**: If there are local modifications before pull, suggest backing up or using `git stash` first.
- **Conflict handling**: Config file conflicts usually prioritize keeping local version, unless explicitly needing remote's new config.
- **Verify config**: After pull, suggest checking if `opencode.json` and other config files work correctly.

View File

@@ -1,86 +0,0 @@
---
description: Commit and push OpenCode config changes to remote
agent: build
---
# sync-oc-push
Commit and push OpenCode configuration repository changes to remote repository.
## Use Cases
When you modified config files in `~/.config/opencode` directory (such as `command/`, `skill/`, `opencode.json`, etc.), use this command to sync changes to remote repository.
## Steps
### 1. Switch to OpenCode Config Directory
```bash
cd ~/.config/opencode
```
### 2. Check Change Status
Run `git status` to view current changes.
**If there are no changes**:
- Output prompt: "No changes to commit."
- **Terminate command execution**
### 3. Collect Information (Execute in parallel)
- Run `git diff` to view unstaged changes
- Run `git diff --cached` to view staged changes
- Run `git log --oneline -5` to view recent commit history
### 4. Add Changes to Staging Area
Add all relevant config files to staging area:
```bash
git add command/ skill/ opencode.json
```
> Only add config files that need to be synced, ignore other local files.
### 5. Generate Commit Message and Commit
Generate concise commit message based on change content:
- Use [Conventional Commits](https://www.conventionalcommits.org/) specification
- **Language selection**:
- **Default (macOS/Linux)**: Use Chinese (中文) for commit messages
- **Windows**: Use English due to encoding issues with Cursor Shell tool
- Common types:
- `feat`: New command or config
- `fix`: Fix command or config issues
- `docs`: Documentation update
- `chore`: Miscellaneous adjustments
**Examples (macOS/Linux - Chinese)**:
```bash
git commit -m "feat: 添加 Vue.js 开发命令"
git commit -m "fix: 修正 MCP 服务器配置"
git commit -m "docs: 更新 review 命令说明"
```
**Examples (Windows - English)**:
```bash
git commit -m "feat: add new developer command for Vue.js"
git commit -m "fix: correct MCP server configuration"
git commit -m "docs: update review command instructions"
```
### 6. Push to Remote Repository
```bash
git push origin main
```
## Notes
- **Only sync config files**: Only add `command/`, `skill/` and `opencode.json`, don't commit other local data.
- **Sensitive info**: `opencode.json` may contain API keys, ensure remote repository access permissions are set correctly.
- **Commit message language**: Default use Chinese (macOS/Linux); Windows must use English due to Cursor Shell tool encoding issues.