Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
740ff4e1d8 | ||
|
|
135ea99deb | ||
|
|
6bc2506842 | ||
|
|
c0b5f15895 | ||
|
|
32d674a4c0 | ||
|
|
02d870a2d6 | ||
|
|
417f3e6d2b | ||
|
|
ece54efc14 | ||
|
|
d5ad180fae | ||
|
|
fa227d9689 | ||
|
|
6153911e46 | ||
|
|
7084e9be35 | ||
|
|
ef67dc7dd2 | ||
|
|
9a39fa4725 | ||
|
|
491a7897c4 | ||
|
|
87b09e0ffd | ||
|
|
26c333dc84 | ||
|
|
dffa3fae12 | ||
|
|
43e138b19e |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -18,3 +18,9 @@ config.env
|
||||
|
||||
# Gitea 配置(如果不小心复制到这里)
|
||||
gitea-config.env
|
||||
|
||||
# Superpowers 插件和外部依赖
|
||||
superpowers/
|
||||
plugin/
|
||||
.runner
|
||||
package-lock.json
|
||||
|
||||
@@ -127,3 +127,7 @@
|
||||
## 6. skill 和 command
|
||||
|
||||
- 默认在oc 的全局配置目录下创建 skill 和 command
|
||||
|
||||
## 7. 临时文件
|
||||
|
||||
- 临时创建的脚本或文件,使用结束后,主动删除和清理。
|
||||
|
||||
64
README.md
64
README.md
@@ -1,64 +0,0 @@
|
||||
# OpenCode
|
||||
|
||||
## 目录
|
||||
|
||||
```
|
||||
opencode/
|
||||
├── command/ # CLI 命令定义
|
||||
│ ├── git-commit.md # 自动生成提交信息并提交
|
||||
│ ├── git-pull.md # 拉取远程最新变更
|
||||
│ ├── git-push.md # 提交+创建标签+推送(一键完成)
|
||||
│ ├── git-push-tags.md # 推送所有标签到远程
|
||||
│ ├── gitea-config.md # 查看 Gitea 配置和 Runner 状态
|
||||
│ ├── gitea-create-repo.md # 在 Gitea 创建新仓库
|
||||
│ ├── gitea-create-runner.md # 创建并启动 Gitea Actions Runner
|
||||
│ ├── gitea-delete-runner.md # 删除已配置的 Runner
|
||||
│ ├── gitea-list-runners.md # 列出所有已配置的 Runners
|
||||
│ ├── gitea-reset.md # 重置 Gitea 配置
|
||||
│ ├── gitea-switch-org.md # 切换默认组织
|
||||
│ └── review.md # 代码审查命令
|
||||
│
|
||||
├── skill/ # 可复用技能库和指南
|
||||
│ ├── git/ # Git 工作流程和版本管理
|
||||
│ │ ├── SKILL.md # 完整的 Git 工作流程指南
|
||||
│ │ └── quick-reference.md # Git 快速参考
|
||||
│ │
|
||||
│ ├── gitea/ # Gitea 平台集成
|
||||
│ │ ├── SKILL.md # Gitea 完整指南
|
||||
│ │ ├── setup-guide.md # 初始化和配置指南
|
||||
│ │ ├── repository-operations.md # 仓库操作指南
|
||||
│ │ ├── runner-management.md # Runner 管理指南
|
||||
│ │ ├── api-reference.md # Gitea API 参考
|
||||
│ │ ├── troubleshooting.md # 常见问题和解决方案
|
||||
│ │ ├── workflow-generator.md # Workflow 自动生成工具
|
||||
│ │ └── workflow-templates/ # CI/CD Workflow 模板库
|
||||
│ │ ├── android-app.md # Android App 构建 Workflow
|
||||
│ │ ├── go-backend.md # Go 后端服务 Workflow
|
||||
│ │ ├── nodejs-frontend.md # Node.js 前端 Workflow
|
||||
│ │ └── wechat-miniprogram.md # 微信小程序 Workflow
|
||||
│ │
|
||||
│ ├── android-developer/ # Android 开发指南
|
||||
│ │ └── SKILL.md # Android 项目开发规范
|
||||
│ │
|
||||
│ ├── ios-developer/ # iOS 开发指南
|
||||
│ │ └── SKILL.md # iOS 项目开发规范
|
||||
│ │
|
||||
│ ├── go-developer/ # Go 后端开发指南
|
||||
│ │ └── SKILL.md # Go 项目开发规范
|
||||
│ │
|
||||
│ ├── electron-developer/ # Electron 桌面应用指南
|
||||
│ │ └── SKILL.md # Electron 项目开发规范
|
||||
│ │
|
||||
│ └── mqtts-developer/ # MQTT over TLS/SSL 开发指南
|
||||
│ ├── SKILL.md # MQTT 完整指南
|
||||
│ ├── README.md # MQTT 项目说明
|
||||
│ ├── setup-mqtts-acme.md # ACME 证书配置
|
||||
│ ├── mqtts-client-config.md # 客户端配置
|
||||
│ ├── mqtts-quick-reference.md # 快速参考
|
||||
│ └── USAGE_EXAMPLES.md # 使用示例
|
||||
│
|
||||
├── README.md # 项目说明文档(当前文件)
|
||||
├── AGENTS.md # 全局开发规范和指南
|
||||
├── opencode.json # 项目配置文件
|
||||
└── .gitignore # Git 忽略文件配置
|
||||
```
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
description: Commit staged files with auto-generated message and create version tag
|
||||
---
|
||||
|
||||
Auto-generate a commit message for staged files, commit to the local repository, and create a version tag following semantic versioning.
|
||||
|
||||
Please follow the git workflow defined in `@skill/git/SKILL.md`:
|
||||
|
||||
1. **Check staging area** - Verify files are staged with `git diff --cached --name-only`
|
||||
- If empty, inform the user and stop
|
||||
2. **Collect information** - Run these commands in parallel:
|
||||
- `git status`
|
||||
- `git diff --cached`
|
||||
- `git log --oneline -10`
|
||||
- `git tag --list | sort -V | tail -5`
|
||||
- Read `@AGENTS.md` if it exists (repository type, version rules, project structure)
|
||||
3. **Detect repository type** - Polyrepo (tag: `1.2.0`) or Monorepo (tag: `subproject-1.2.0`)
|
||||
4. **Detect project type and version** - Check for version files:
|
||||
- iOS: `*.xcodeproj/project.pbxproj` → `MARKETING_VERSION`
|
||||
- Node.js: `package.json` → `version`
|
||||
- Android: `build.gradle(.kts)` → `versionName`
|
||||
- Go: Git tag only
|
||||
5. **Generate commit message** following Conventional Commits:
|
||||
- Format: `<type>(<scope>): <subject>`
|
||||
- Use Chinese for commit messages (macOS/Linux)
|
||||
- Types: feat, fix, docs, style, refactor, perf, test, chore, ci, build
|
||||
- For monorepo, use subproject as scope if changes affect single subproject
|
||||
6. **Update version number** if needed:
|
||||
- feat: minor +1 (1.2.0 → 1.3.0)
|
||||
- fix/perf: patch +1 (1.2.3 → 1.2.4)
|
||||
- Breaking change: major +1 (1.2.3 → 2.0.0)
|
||||
- Only for user-perceivable changes (feat, fix, perf, breaking)
|
||||
- Add updated version file to staging
|
||||
7. **Commit changes** with generated message
|
||||
8. **Create version tag** if version was updated (unless user specified "skip tag"):
|
||||
- Polyrepo: `git tag -a "1.2.0" -m "commit message"`
|
||||
- Monorepo: `git tag -a "subproject-1.2.0" -m "commit message"`
|
||||
|
||||
**Options:**
|
||||
- User can input "skip tag" or "skip" to skip tag creation
|
||||
|
||||
**Display result in Chinese:**
|
||||
```
|
||||
✓ 提交成功
|
||||
|
||||
提交信息:[commit message]
|
||||
版本标签:[tag] (如果创建了)
|
||||
|
||||
要推送到远程仓库,请运行:/git-push
|
||||
```
|
||||
|
||||
**Important:** This command does NOT push to remote. Use `/git-push` to push commits and tags.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
description: Pull latest changes from remote repository
|
||||
---
|
||||
|
||||
Pull the latest changes from the remote repository for the current branch.
|
||||
|
||||
Please perform the following tasks:
|
||||
|
||||
1. **Run `git pull`** to fetch and merge remote changes
|
||||
2. **Handle merge conflicts if they occur:**
|
||||
- Check conflict files with `git status`
|
||||
- Guide me through conflict resolution
|
||||
- Help stage resolved files with `git add <file>`
|
||||
- Complete the merge with `git commit`
|
||||
3. **Show the result** with branch status and changes summary
|
||||
|
||||
If there are any errors or conflicts, explain them clearly in Chinese and provide step-by-step guidance for resolution.
|
||||
|
||||
Present the final result showing:
|
||||
- Branch name
|
||||
- Number of commits pulled
|
||||
- Files changed
|
||||
- Any conflicts that need attention
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
description: Push all local tags to remote repository
|
||||
---
|
||||
|
||||
Push all local tags to the remote repository.
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **List local tags:**
|
||||
```bash
|
||||
git tag --list | sort -V
|
||||
```
|
||||
|
||||
2. **Check remote tags:**
|
||||
```bash
|
||||
git ls-remote --tags origin
|
||||
```
|
||||
|
||||
3. **Identify unpushed tags** - Compare local and remote to find tags that need to be pushed
|
||||
|
||||
4. **Display summary in Chinese:**
|
||||
```
|
||||
本地标签总数:N 个
|
||||
远程标签总数:M 个
|
||||
待推送标签:K 个
|
||||
- [list of unpushed tags]
|
||||
|
||||
确认推送所有标签到 origin?
|
||||
```
|
||||
|
||||
5. **Wait for user confirmation** (or proceed if no confirmation needed)
|
||||
|
||||
6. **Push all tags:**
|
||||
```bash
|
||||
git push --tags
|
||||
```
|
||||
|
||||
7. **Verify and display result in Chinese:**
|
||||
```
|
||||
✓ 已成功推送所有标签到 origin
|
||||
|
||||
最近 5 个远程标签:
|
||||
- [list of recent tags]
|
||||
```
|
||||
|
||||
**Use cases:**
|
||||
- After creating multiple local tags
|
||||
- Sync tags with remote repository
|
||||
- Before triggering CI/CD release workflows
|
||||
- Share version tags with team
|
||||
|
||||
**Notes:**
|
||||
- Pushes ALL local tags, not just one
|
||||
- To push a specific tag: `git push origin <tag-name>`
|
||||
- Safe operation: won't overwrite existing tags (no force push)
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
description: Commit staged files, create version tag, and push to remote repository
|
||||
---
|
||||
|
||||
Complete workflow: auto-generate commit message, create version tag, commit, and push everything to remote repository.
|
||||
|
||||
This is the **all-in-one command** that combines `/git-commit` + push operations.
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1-7. **Follow the same steps as `/git-commit`:**
|
||||
- Check staging area (must not be empty)
|
||||
- Analyze changes and repository type
|
||||
- Detect project type and version
|
||||
- Generate commit message (Conventional Commits, Chinese)
|
||||
- Update version number if needed
|
||||
- Commit changes
|
||||
- Create version tag
|
||||
|
||||
Refer to `/git-commit` for detailed steps or `@skill/git/SKILL.md` for complete workflow.
|
||||
|
||||
8. **Push commit to remote:**
|
||||
```bash
|
||||
git push origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
9. **Push tag to remote** (only if tag was created):
|
||||
- Polyrepo: `git push origin <version>`
|
||||
- Monorepo: `git push origin <subproject>-<version>`
|
||||
|
||||
10. **Display result in Chinese:**
|
||||
```
|
||||
✓ 提交并推送成功
|
||||
|
||||
分支:[branch]
|
||||
提交信息:[commit message]
|
||||
版本标签:[tag] (如果创建了)
|
||||
|
||||
已推送到远程仓库:origin
|
||||
- 提交:[commit hash]
|
||||
- 标签:[tag]
|
||||
```
|
||||
|
||||
**Error handling:**
|
||||
- If staging area is empty: "暂存区为空,请先使用 `git add` 添加文件。"
|
||||
- If push fails (e.g., need to pull first): Show error in Chinese with suggested solutions
|
||||
- If remote rejects tag (already exists): Show error and suggest deleting local tag or updating version
|
||||
|
||||
**Options:**
|
||||
- User can input "skip tag" or "skip" to skip tag creation
|
||||
|
||||
**When to use:**
|
||||
- `/git-commit`: Local only, review before pushing
|
||||
- `/git-push`: Commit and push immediately
|
||||
- `/git-push-tags`: Push tags only (no commits)
|
||||
@@ -1,72 +0,0 @@
|
||||
---
|
||||
description: View current Gitea configuration and runner status
|
||||
---
|
||||
|
||||
Display the current Gitea configuration and runner status.
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **Check if configuration exists:**
|
||||
- Config file:
|
||||
- macOS/Linux: `~/.config/gitea/config.env`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\config.env`
|
||||
- If not exists, prompt user to run `/gitea-reset`
|
||||
|
||||
2. **Load and display configuration:**
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object {
|
||||
if ($_ -match '^([^=]+)=(.*)$') {
|
||||
[Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Show in Chinese:
|
||||
- Gitea URL
|
||||
- Default organization (if set)
|
||||
- Config file path (根据平台显示正确路径)
|
||||
|
||||
3. **Validate token and display user info:**
|
||||
- Call API: `GET ${GITEA_URL}/api/v1/user`
|
||||
- Header: `Authorization: token ${GITEA_TOKEN}`
|
||||
- Show: Token status (✓ 有效 / ✗ 无效), username, email
|
||||
|
||||
4. **Display runner information:**
|
||||
- Runners directory:
|
||||
- macOS/Linux: `~/.config/gitea/runners`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\runners`
|
||||
- Count configured runners
|
||||
- List each runner with status:
|
||||
- 🟢 运行中 (process running)
|
||||
- 🔴 已停止 (process not running)
|
||||
- ⚠️ 配置异常 (config file missing)
|
||||
|
||||
5. **Show management commands:**
|
||||
```
|
||||
管理命令:
|
||||
- 重置配置: /gitea-reset
|
||||
- 切换组织: /gitea-switch-org <org-name>
|
||||
- 列出 Runners: /gitea-list-runners
|
||||
- 创建仓库: /create-gitea-repo <repo-name>
|
||||
```
|
||||
|
||||
Use `jq` to parse JSON responses and `pgrep` to check runner process status.
|
||||
@@ -1,104 +0,0 @@
|
||||
---
|
||||
description: Create a new Git repository on Gitea
|
||||
---
|
||||
|
||||
Create a new Git repository on Gitea via API.
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
配置文件从该目录加载。
|
||||
|
||||
**User input format:**
|
||||
```
|
||||
$ARGUMENTS = [<owner>/]<repo> [private|public]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
- `my-project` - Private repo under default org or current user
|
||||
- `ai/my-project` - Private repo under ai organization
|
||||
- `ai/my-project public` - Public repo under ai organization
|
||||
- `username/test private` - Private repo under username
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **Load configuration:**
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object {
|
||||
if ($_ -match '^([^=]+)=(.*)$') {
|
||||
[Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- If not exists: prompt to run `/gitea-reset`
|
||||
|
||||
2. **Parse user input from `$ARGUMENTS`:**
|
||||
- Extract: owner (optional), repo (required), visibility (optional, default: private)
|
||||
- If no owner specified:
|
||||
- Use `GITEA_DEFAULT_ORG` if set
|
||||
- Otherwise get current user from API: `GET /api/v1/user`
|
||||
- Validate repo name: only letters, numbers, underscores, hyphens, dots
|
||||
|
||||
3. **Create repository via API:**
|
||||
- Try organization API first:
|
||||
```bash
|
||||
POST ${GITEA_URL}/api/v1/orgs/${owner}/repos
|
||||
Body: {
|
||||
"name": "${repo}",
|
||||
"private": true/false,
|
||||
"auto_init": false,
|
||||
"default_branch": "main"
|
||||
}
|
||||
```
|
||||
- If 404, try user API: `POST /api/v1/user/repos`
|
||||
- Handle response codes:
|
||||
- 201: Success
|
||||
- 409: Repository already exists
|
||||
- 404: Owner not found or no permission
|
||||
- Other: API error
|
||||
|
||||
4. **Extract repository info from response:**
|
||||
- `html_url` - Web URL
|
||||
- `clone_url` - HTTPS URL
|
||||
- `ssh_url` - SSH URL
|
||||
|
||||
5. **Ask user if they want to add remote:**
|
||||
- Check if current directory is a git repo
|
||||
- If not, ask to initialize: `git init`
|
||||
- Check if `origin` remote exists
|
||||
- Add or update remote: `git remote add/set-url origin <clone_url>`
|
||||
|
||||
6. **Display result in Chinese:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
仓库创建成功
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
名称: [owner]/[repo]
|
||||
可见性: [private/public]
|
||||
Web URL: [html_url]
|
||||
HTTPS URL: [clone_url]
|
||||
SSH URL: [ssh_url]
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Requires repo creation permission in token
|
||||
- Organization and user repositories use different API endpoints
|
||||
- Default branch is `main` (not `master`)
|
||||
@@ -1,770 +0,0 @@
|
||||
---
|
||||
description: Create and start a Gitea Actions runner (default host mode)
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# 创建并启动 Gitea Actions Runner
|
||||
|
||||
你的任务是创建并启动一个 Gitea Actions Runner(默认使用 host 模式)。
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
所有 Runner 配置、缓存、工作区都存储在该目录的 `runners/` 子目录下。
|
||||
|
||||
## 核心功能要求
|
||||
|
||||
请按照以下步骤执行:
|
||||
|
||||
1. **检查 act_runner 安装**
|
||||
- 检查 act_runner 是否已安装(使用 `command -v act_runner`)
|
||||
- 如果未安装,使用 Homebrew 自动安装:`brew install act_runner`
|
||||
- 如果 Homebrew 不存在,提示用户安装 Homebrew
|
||||
- 验证安装成功后显示版本信息
|
||||
|
||||
2. **加载 Gitea 配置**
|
||||
- 从配置文件加载配置:
|
||||
- macOS/Linux: `~/.config/gitea/config.env`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\config.env`
|
||||
- 如果配置文件不存在,提示用户运行 `/gitea-reset` 初始化
|
||||
- 验证必需的配置项:`GITEA_URL` 和 `GITEA_TOKEN`
|
||||
- 显示加载成功的配置信息
|
||||
|
||||
3. **生成 Runner 名称**
|
||||
- 如果用户提供了参数 `$ARGUMENTS`,使用该名称
|
||||
- 否则默认基于主机名生成:`runner-$(hostname -s)`
|
||||
- 验证名称只包含字母、数字、下划线和连字符
|
||||
|
||||
4. **检查 Runner 是否已存在**
|
||||
- 检查 Runner 目录:
|
||||
- macOS/Linux: `~/.config/gitea/runners/$runner_name`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\runners\$runner_name`
|
||||
- 如果已存在,提示用户可选操作:
|
||||
- 使用其他名称
|
||||
- 删除现有 runner(使用 `/gitea-delete-runner`)
|
||||
- 查看所有 runners(使用 `/gitea-list-runners`)
|
||||
|
||||
5. **检测系统环境**
|
||||
- 检测操作系统(macOS/Linux)
|
||||
- 检测架构(ARM64/x64)
|
||||
- 生成 host 模式的 labels:
|
||||
- `self-hosted:host`
|
||||
- `{os_label}:host`(如 `macOS:host`)
|
||||
- `{arch_label}:host`(如 `ARM64:host`)
|
||||
- `{combined}:host`(如 `darwin-arm64:host`)
|
||||
|
||||
6. **创建 Runner 目录结构**
|
||||
- 创建目录结构:
|
||||
- macOS/Linux: `~/.config/gitea/runners/$runner_name/{cache,workspace}`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\runners\$runner_name\{cache,workspace}`
|
||||
- 验证目录创建成功
|
||||
|
||||
7. **生成配置文件**
|
||||
- 创建 `config.yaml`,使用 host 模式配置
|
||||
- 从环境变量读取可选配置:
|
||||
- `GITEA_RUNNER_CAPACITY`(默认 2)
|
||||
- `GITEA_RUNNER_TIMEOUT`(默认 3h)
|
||||
- 配置要点:
|
||||
- log level: info
|
||||
- runner.capacity: 并发任务数
|
||||
- runner.timeout: 任务超时
|
||||
- cache: 启用缓存
|
||||
- host.workdir_parent: 工作目录路径
|
||||
- labels: 使用检测到的系统 labels
|
||||
|
||||
8. **获取注册 Token**
|
||||
- 优先尝试创建全局 Runner(需要管理员权限)
|
||||
- API: `GET ${GITEA_URL}/api/v1/admin/runners/registration-token`
|
||||
- Header: `Authorization: token ${GITEA_TOKEN}`
|
||||
- 如果返回 403/权限不足,自动降级到组织 Runner
|
||||
- 使用 `GITEA_DEFAULT_ORG` 作为组织名
|
||||
- API: `POST ${GITEA_URL}/api/v1/orgs/${org_name}/actions/runners/registration-token`
|
||||
- 从响应中提取 token(JSON 格式)
|
||||
- 记录使用的 runner 级别(global 或 organization)
|
||||
|
||||
9. **注册 Runner**
|
||||
- 执行命令:
|
||||
```bash
|
||||
act_runner register \
|
||||
--config "$runner_dir/config.yaml" \
|
||||
--instance "$GITEA_URL" \
|
||||
--token "$registration_token" \
|
||||
--name "$runner_name" \
|
||||
--labels "$labels" \
|
||||
--no-interactive
|
||||
```
|
||||
- 验证 `.runner` 文件是否创建
|
||||
- 如果失败,提供诊断建议
|
||||
|
||||
10. **后台启动 Runner**
|
||||
- 使用 nohup 后台启动:
|
||||
```bash
|
||||
nohup act_runner daemon --config "$runner_dir/config.yaml" \
|
||||
> "$runner_dir/runner.log" 2>&1 &
|
||||
```
|
||||
- 记录进程 PID
|
||||
- 等待 3 秒初始化
|
||||
- 验证进程仍在运行
|
||||
- 如果失败,显示日志的最后 20 行
|
||||
|
||||
11. **显示创建摘要**
|
||||
- Runner 信息:名称、级别、模式、状态、PID
|
||||
- 如果是组织级别,显示组织名
|
||||
- 配置信息:容量、超时、labels
|
||||
- 目录信息:配置文件、工作目录、缓存目录、日志文件
|
||||
- 管理命令:查看日志、停止 Runner、查看所有、删除
|
||||
- 使用示例:workflow 中的 runs-on 配置
|
||||
|
||||
## 重要配置说明
|
||||
|
||||
- **默认模式**:Host Mode(直接在宿主机执行,支持 Android SDK、iOS 构建等原生工具)
|
||||
- **目录结构**:
|
||||
- macOS/Linux: 所有 runners 位于 `~/.config/gitea/runners/`
|
||||
- Windows: 所有 runners 位于 `%USERPROFILE%\.config\gitea\runners\`
|
||||
- **优雅降级**:全局 runner 权限不足时自动降级到组织 runner
|
||||
- **后台运行**:使用 nohup 后台启动(Unix),或 Start-Process(Windows),日志输出到文件
|
||||
- **进程管理**:需要手动管理进程(系统重启后需重新启动)
|
||||
|
||||
## 可选参数
|
||||
|
||||
- `$ARGUMENTS`: Runner 名称(可选,默认基于主机名生成)
|
||||
|
||||
使用示例:
|
||||
```
|
||||
/gitea-create-runner
|
||||
/gitea-create-runner my-custom-runner
|
||||
```
|
||||
|
||||
## 相关命令
|
||||
|
||||
- `/gitea-config`: 查看 Gitea 配置
|
||||
- `/gitea-reset`: 重置/初始化 Gitea 配置
|
||||
- `/gitea-list-runners`: 列出所有 runners
|
||||
- `/gitea-delete-runner`: 删除指定 runner
|
||||
|
||||
---
|
||||
|
||||
## 详细实现步骤(供 AI 参考)
|
||||
|
||||
### 1. Check act_runner Installation
|
||||
|
||||
**AI 执行**:检查 act_runner 是否已安装,如果没有则自动安装。
|
||||
|
||||
```bash
|
||||
echo "检查 act_runner 安装状态..."
|
||||
|
||||
if command -v act_runner &> /dev/null; then
|
||||
version=$(act_runner --version 2>&1 | head -n1)
|
||||
echo "✓ act_runner 已安装: $version"
|
||||
else
|
||||
echo "⚠️ act_runner 未安装"
|
||||
echo "正在使用 Homebrew 安装..."
|
||||
|
||||
if ! command -v brew &> /dev/null; then
|
||||
echo "❌ 需要先安装 Homebrew"
|
||||
echo " 安装命令: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
brew install act_runner
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
version=$(act_runner --version 2>&1 | head -n1)
|
||||
echo "✓ act_runner 安装成功: $version"
|
||||
else
|
||||
echo "❌ act_runner 安装失败"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 2. Load Gitea Configuration
|
||||
|
||||
**AI 执行**:加载 Gitea 配置,如果不存在则提示初始化。
|
||||
|
||||
```bash
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 配置不存在"
|
||||
echo ""
|
||||
echo "请先初始化 Gitea 配置:"
|
||||
echo " /gitea-reset"
|
||||
echo ""
|
||||
echo "或使用以下命令查看配置:"
|
||||
echo " /gitea-config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file"
|
||||
|
||||
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "❌ Gitea 配置不完整"
|
||||
echo " 需要 GITEA_URL 和 GITEA_TOKEN"
|
||||
echo ""
|
||||
echo "请重新初始化配置:"
|
||||
echo " /gitea-reset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 已加载 Gitea 配置"
|
||||
echo " URL: $GITEA_URL"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 3. Generate Runner Name
|
||||
|
||||
**AI 执行**:生成 runner 名称(基于主机名或用户输入)。
|
||||
|
||||
```bash
|
||||
# Check if runner name provided as argument
|
||||
# 如果用户提供了名称参数,使用该参数;否则基于主机名生成
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
runner_name="$1"
|
||||
echo "使用指定的 Runner 名称: $runner_name"
|
||||
else
|
||||
hostname=$(hostname -s 2>/dev/null || echo "unknown")
|
||||
runner_name="runner-$hostname"
|
||||
echo "生成 Runner 名称: $runner_name"
|
||||
echo " (基于主机名: $hostname)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Validate runner name
|
||||
if [[ ! "$runner_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
||||
echo "❌ Runner 名称只能包含字母、数字、下划线和连字符"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. Check Runner Existence
|
||||
|
||||
**AI 执行**:检查 runner 是否已存在。
|
||||
|
||||
```bash
|
||||
runners_dir="$HOME/.config/gitea/runners"
|
||||
runner_dir="$runners_dir/$runner_name"
|
||||
|
||||
if [ -d "$runner_dir" ]; then
|
||||
echo "❌ Runner '$runner_name' 已存在"
|
||||
echo " 路径: $runner_dir"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " 1. 使用其他名称: /gitea-create-runner <新名称>"
|
||||
echo " 2. 删除现有 runner: /gitea-delete-runner"
|
||||
echo " 3. 查看所有 runners: /gitea-list-runners"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 5. Detect System Environment
|
||||
|
||||
**AI 执行**:智能检测系统环境并生成 labels。
|
||||
|
||||
```bash
|
||||
echo "检测系统环境..."
|
||||
|
||||
# Detect OS
|
||||
OS=$(uname -s)
|
||||
case "$OS" in
|
||||
Darwin) os_label="macOS" ;;
|
||||
Linux) os_label="ubuntu" ;;
|
||||
*) os_label="unknown" ;;
|
||||
esac
|
||||
|
||||
# Detect architecture
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
arm64|aarch64) arch_label="ARM64" ;;
|
||||
x86_64) arch_label="x64" ;;
|
||||
*) arch_label="unknown" ;;
|
||||
esac
|
||||
|
||||
# Generate combined label
|
||||
combined=$(echo "${OS}-${ARCH}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Generate labels for host mode
|
||||
labels="self-hosted:host,${os_label}:host,${arch_label}:host,${combined}:host"
|
||||
|
||||
echo "✓ 系统信息"
|
||||
echo " 操作系统: $OS ($os_label)"
|
||||
echo " 架构: $ARCH ($arch_label)"
|
||||
echo " 组合标签: $combined"
|
||||
echo ""
|
||||
echo "✓ Runner Labels (Host Mode)"
|
||||
echo " $labels"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 6. Create Runner Directory
|
||||
|
||||
**AI 执行**:创建 runner 目录结构。
|
||||
|
||||
```bash
|
||||
echo "创建 Runner 目录..."
|
||||
|
||||
mkdir -p "$runner_dir"/{cache,workspace}
|
||||
|
||||
if [ ! -d "$runner_dir" ]; then
|
||||
echo "❌ 创建目录失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 目录创建成功"
|
||||
echo " 路径: $runner_dir"
|
||||
echo " - cache/"
|
||||
echo " - workspace/"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 7. Generate Configuration File
|
||||
|
||||
**AI 执行**:生成 host 模式配置文件。
|
||||
|
||||
```bash
|
||||
echo "生成配置文件..."
|
||||
|
||||
# Get environment-specific settings (with defaults)
|
||||
runner_capacity="${GITEA_RUNNER_CAPACITY:-2}"
|
||||
runner_timeout="${GITEA_RUNNER_TIMEOUT:-3h}"
|
||||
|
||||
# Generate config.yaml for host mode
|
||||
cat > "$runner_dir/config.yaml" << EOF
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: $runner_dir/.runner
|
||||
capacity: $runner_capacity
|
||||
timeout: $runner_timeout
|
||||
shutdown_timeout: 30s
|
||||
insecure: false
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
labels:
|
||||
- "self-hosted:host"
|
||||
- "${os_label}:host"
|
||||
- "${arch_label}:host"
|
||||
- "${combined}:host"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "$runner_dir/cache"
|
||||
host: "127.0.0.1"
|
||||
port: 9000
|
||||
|
||||
host:
|
||||
workdir_parent: "$runner_dir/workspace"
|
||||
EOF
|
||||
|
||||
if [ ! -f "$runner_dir/config.yaml" ]; then
|
||||
echo "❌ 配置文件生成失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 配置文件已生成"
|
||||
echo " 文件: $runner_dir/config.yaml"
|
||||
echo " 模式: Host Mode (原生执行)"
|
||||
echo " 容量: $runner_capacity 并发任务"
|
||||
echo " 超时: $runner_timeout"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 8. Get Registration Token
|
||||
|
||||
**AI 执行**:获取注册 token(优先全局,失败则降级到组织)。
|
||||
|
||||
```bash
|
||||
echo "获取 Runner 注册 Token..."
|
||||
echo ""
|
||||
|
||||
# Try global runner first (requires admin token)
|
||||
echo "尝试创建全局 Runner(可用于所有组织和仓库)..."
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/runners/registration-token")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
# Check for admin permission
|
||||
if [ "$http_code" = "200" ]; then
|
||||
echo "✓ 使用全局 Runner"
|
||||
runner_level="global"
|
||||
registration_token=$(echo "$body" | jq -r '.token')
|
||||
else
|
||||
echo "⚠️ 全局 Runner 权限不足 (HTTP $http_code)"
|
||||
echo " 全局 Runner 需要管理员 Token"
|
||||
echo ""
|
||||
echo "降级到组织 Runner..."
|
||||
|
||||
runner_level="organization"
|
||||
|
||||
if [ -n "$GITEA_DEFAULT_ORG" ]; then
|
||||
org_name="$GITEA_DEFAULT_ORG"
|
||||
echo "使用默认组织: $org_name"
|
||||
else
|
||||
echo "❌ 未配置默认组织"
|
||||
echo " 请在配置文件中设置 GITEA_DEFAULT_ORG"
|
||||
echo " 或重新初始化配置: /gitea-reset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/orgs/$org_name/actions/runners/registration-token")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "❌ 获取注册 Token 失败 (HTTP $http_code)"
|
||||
echo " 响应: $body"
|
||||
echo ""
|
||||
echo "可能的原因:"
|
||||
echo " 1. 组织不存在"
|
||||
echo " 2. Token 没有组织管理权限"
|
||||
echo " 3. 网络连接问题"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
registration_token=$(echo "$body" | jq -r '.token')
|
||||
echo "✓ 组织 Runner Token 已获取"
|
||||
fi
|
||||
|
||||
if [ -z "$registration_token" ] || [ "$registration_token" = "null" ]; then
|
||||
echo "❌ 无法解析注册 Token"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 注册 Token 已准备"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 9. Register Runner
|
||||
|
||||
**AI 执行**:注册 runner 到 Gitea 服务器。
|
||||
|
||||
```bash
|
||||
echo "注册 Runner 到 Gitea 服务器..."
|
||||
|
||||
act_runner register \
|
||||
--config "$runner_dir/config.yaml" \
|
||||
--instance "$GITEA_URL" \
|
||||
--token "$registration_token" \
|
||||
--name "$runner_name" \
|
||||
--labels "$labels" \
|
||||
--no-interactive
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ Runner 注册成功"
|
||||
else
|
||||
echo "❌ Runner 注册失败"
|
||||
echo ""
|
||||
echo "请检查:"
|
||||
echo " 1. Token 是否有效"
|
||||
echo " 2. Gitea 服务器是否可访问"
|
||||
echo " 3. 配置文件是否正确"
|
||||
echo ""
|
||||
echo "查看详细错误,可以手动运行:"
|
||||
echo " act_runner register --config $runner_dir/config.yaml --instance $GITEA_URL --token <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
|
||||
@@ -1,174 +0,0 @@
|
||||
---
|
||||
description: Delete a Gitea runner configuration (interactive)
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
Delete Gitea runner configuration with interactive selection. This command requires multiple user interactions.
|
||||
|
||||
**Important:** This is an interactive command. Wait for user input at each step before proceeding.
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
所有 Runner 配置、进程管理都基于此目录。
|
||||
|
||||
Please perform the following steps:
|
||||
|
||||
## Step 1: Load Configuration and Fetch Runners
|
||||
|
||||
1. **Load Gitea configuration:**
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object {
|
||||
if ($_ -match '^([^=]+)=(.*)$') {
|
||||
[Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Validate `GITEA_URL` and `GITEA_TOKEN` exist
|
||||
|
||||
2. **Fetch global runners from Gitea server:**
|
||||
- API: `GET ${GITEA_URL}/api/v1/admin/actions/runners`
|
||||
- Requires admin permissions
|
||||
- If fails: show error and check token permissions
|
||||
|
||||
3. **Display runners list in Chinese:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Gitea 全局 Runners (共 N 个)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. [runner-name] [ID: XX] 🟢 在线/🔴 离线
|
||||
2. [runner-name] [ID: XX] 🟢 在线/🔴 离线
|
||||
...
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
选择要删除的 Runner
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
输入序号: 删除单个 runner
|
||||
输入 'all': 删除所有 runners
|
||||
输入 'q' 或 'quit': 取消
|
||||
```
|
||||
|
||||
4. **Wait for user selection** → Do NOT proceed until user responds
|
||||
|
||||
## Step 2: Process User Selection
|
||||
|
||||
Based on user input:
|
||||
- If `q` or `quit`: Cancel and exit
|
||||
- If `all`: Prepare to delete all runners
|
||||
- If number: Validate and prepare to delete that runner
|
||||
|
||||
## Step 3: Display Warning and Wait for Confirmation
|
||||
|
||||
Display deletion warning in Chinese:
|
||||
```
|
||||
⚠️ 警告: 此操作将执行以下操作:
|
||||
- 从 Gitea 服务器注销 runner
|
||||
- 停止本地运行的 runner 进程
|
||||
- 删除 runner 配置文件
|
||||
- 删除 cache 和 workspace 目录
|
||||
- 删除所有相关数据
|
||||
|
||||
将删除以下 runners:
|
||||
- [list of runners to be deleted]
|
||||
|
||||
确认删除? 输入 'yes' 继续:
|
||||
```
|
||||
|
||||
**Wait for user confirmation** → Do NOT proceed until user types 'yes'
|
||||
|
||||
## Step 4: Execute Deletion
|
||||
|
||||
If user confirmed with 'yes', for each selected runner:
|
||||
|
||||
### 4.1 Unregister from Gitea Server
|
||||
```bash
|
||||
DELETE ${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}
|
||||
```
|
||||
- Expected: HTTP 204
|
||||
- Show: "✓ 已从服务器注销" or "⚠️ 注销失败"
|
||||
|
||||
### 4.2 Stop Local Process
|
||||
1. Find local runner directory by matching ID in `.runner` file
|
||||
2. Check if process is running: `pgrep -f "act_runner daemon --config ..."`
|
||||
3. If running:
|
||||
- Check if runner is busy (executing jobs) via API
|
||||
- **If busy, wait for user choice:**
|
||||
```
|
||||
⚠️ 警告: Runner 正在执行 job!
|
||||
选项:
|
||||
1. 等待 job 完成后再停止(推荐)
|
||||
2. 强制立即停止
|
||||
```
|
||||
- **Wait for user input** → Proceed based on choice
|
||||
- If waiting: Poll status every 10 seconds, max 5 minutes
|
||||
- Stop process: `kill $pid` (graceful), then `kill -9 $pid` if needed (force)
|
||||
|
||||
### 4.3 Delete Local Directory
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
rm -rf ~/.config/gitea/runners/[runner_name]
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
Remove-Item -Path "$env:USERPROFILE\.config\gitea\runners\[runner_name]" -Recurse -Force
|
||||
```
|
||||
|
||||
## Step 5: Display Result
|
||||
|
||||
Show completion summary in Chinese:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
删除完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
成功: N 个
|
||||
失败: M 个 (if any)
|
||||
|
||||
管理命令:
|
||||
查看剩余 runners: /gitea-list-runners
|
||||
创建新 runner: /gitea-create-runner
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Points
|
||||
|
||||
**Interactive checkpoints (wait for user input):**
|
||||
1. Step 1: After displaying runners list → Wait for selection
|
||||
2. Step 3: After displaying warning → Wait for confirmation ('yes')
|
||||
3. Step 4.2: If runner is busy → Wait for stop choice (1 or 2)
|
||||
|
||||
**Safety features:**
|
||||
- Double confirmation required
|
||||
- Busy status detection
|
||||
- Graceful stop before force kill
|
||||
- Three-step deletion process
|
||||
- Clear status reporting
|
||||
|
||||
**Technical notes:**
|
||||
- Requires `jq` for JSON parsing
|
||||
- Requires admin token for global runners
|
||||
- Uses temporary file `/tmp/gitea_runners.txt` for data passing
|
||||
- Cleanup temp file after completion
|
||||
@@ -1,94 +0,0 @@
|
||||
---
|
||||
description: List all global runners on Gitea server
|
||||
---
|
||||
|
||||
List all global runners registered on the Gitea server.
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **Read Gitea configuration:**
|
||||
- Read from config file:
|
||||
- macOS/Linux: `~/.config/gitea/config.env`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\config.env`
|
||||
- Extract:
|
||||
- `GITEA_URL`: Gitea server URL
|
||||
- `GITEA_TOKEN`: API token (admin permission required)
|
||||
- If config not found: prompt user to run `/gitea-reset` first
|
||||
|
||||
2. **Call Gitea API to list runners:**
|
||||
```bash
|
||||
curl -s -H "Authorization: token <token>" \
|
||||
"<server>/api/v1/admin/actions/runners"
|
||||
```
|
||||
|
||||
3. **Parse JSON response and extract information:**
|
||||
- Response structure:
|
||||
```json
|
||||
{
|
||||
"runners": [...],
|
||||
"total_count": 1
|
||||
}
|
||||
```
|
||||
- Use `jq` to parse JSON
|
||||
- For each runner in `runners` array:
|
||||
- `id`: Runner ID
|
||||
- `name`: Runner name
|
||||
- `status`: Runner status ("online"/"offline")
|
||||
- `busy`: Whether runner is currently busy (true/false)
|
||||
- `ephemeral`: Whether runner is ephemeral (true/false)
|
||||
- `labels`: Array of label objects with `name` and `type`
|
||||
|
||||
4. **Determine runner status:**
|
||||
- 🟢 在线 - `status: "online"`
|
||||
- 🔴 离线 - `status: "offline"`
|
||||
- ⚠️ 未知 - Unable to determine
|
||||
|
||||
5. **Filter global runners:**
|
||||
- The API endpoint `/api/v1/admin/actions/runners` returns all global runners
|
||||
- These are runners registered at the instance level (not org or repo specific)
|
||||
|
||||
6. **Display summary in Chinese:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Gitea 全局 Runners
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
服务器: [server_url]
|
||||
总计: N 个全局 runner
|
||||
|
||||
[runner-name]
|
||||
状态: 🟢/🔴 [在线/离线]
|
||||
ID: [id]
|
||||
忙碌: 是/否
|
||||
临时: 是/否
|
||||
标签: [comma-separated labels]
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
管理命令
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
查看配置: /gitea-config
|
||||
创建 runner: /gitea-create-runner
|
||||
删除 runner: /gitea-delete-runner
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Requires admin API token to list runners
|
||||
- **Correct API endpoint**: `/api/v1/admin/actions/runners` (not `/api/v1/admin/runners`)
|
||||
- Only shows global runners (instance-level runners)
|
||||
- Uses `jq` for JSON parsing
|
||||
- Response includes: `id`, `name`, `status`, `busy`, `ephemeral`, `labels`
|
||||
- If API call fails, show error message and suggest checking token permissions
|
||||
- Tested with Gitea version 1.25.3
|
||||
@@ -1,132 +0,0 @@
|
||||
---
|
||||
description: Reset Gitea configuration with interactive setup wizard
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
Launch an interactive configuration wizard to set up or reset Gitea configuration.
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
配置文件和 Runner 目录都将存储在此位置。
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **Create configuration directory:**
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
mkdir -p ~/.config/gitea/runners
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
New-Item -Path "$env:USERPROFILE\.config\gitea\runners" -ItemType Directory -Force
|
||||
```
|
||||
|
||||
2. **Interactive input - Gitea URL:**
|
||||
- Prompt: "请输入 Gitea 实例地址 (例如: https://git.digitevents.com):"
|
||||
- Validate: Must start with http:// or https://
|
||||
- Remove trailing slash
|
||||
|
||||
3. **Interactive input - Personal Access Token:**
|
||||
- Prompt: "请输入 Personal Access Token:"
|
||||
- Before input, show help:
|
||||
```
|
||||
提示:获取 Personal Access Token 的步骤:
|
||||
1. 登录 Gitea
|
||||
2. 右上角头像 → 设置 → 应用 → 访问令牌
|
||||
3. 点击 "生成新令牌"
|
||||
4. 设置令牌名称(如 opencode-cli)
|
||||
5. 选择权限:repo, admin:org, write:runner(推荐)
|
||||
6. 点击 "生成令牌"
|
||||
7. 复制生成的 Token
|
||||
```
|
||||
- Validate: Not empty
|
||||
- Use `read -sp` for secure input (password style)
|
||||
|
||||
4. **Test connection:**
|
||||
- API: `GET ${GITEA_URL}/api/v1/user`
|
||||
- If fails: Show error and possible reasons
|
||||
- If success: Show username
|
||||
|
||||
5. **Validate token permissions:**
|
||||
- Check `repo`: `GET /api/v1/user/repos` (required)
|
||||
- Check `admin:org`: `GET /api/v1/user/orgs` (optional, for org runners)
|
||||
- Check `write:runner`: Try to get registration token (optional, for runners)
|
||||
- Warn if missing required permissions
|
||||
|
||||
6. **Input default organization (optional):**
|
||||
- Prompt: "请输入默认组织名称 (回车跳过):"
|
||||
- If provided, validate it exists: `GET /api/v1/orgs/${org_name}`
|
||||
|
||||
7. **Save configuration:**
|
||||
|
||||
**macOS / Linux** - Save to `~/.config/gitea/config.env`:
|
||||
```bash
|
||||
GITEA_URL=...
|
||||
GITEA_TOKEN=...
|
||||
GITEA_DEFAULT_ORG=... (if set)
|
||||
GITEA_RUNNER_CAPACITY=2
|
||||
GITEA_RUNNER_TIMEOUT=3h
|
||||
```
|
||||
- Set permissions: `chmod 600 ~/.config/gitea/config.env`
|
||||
- Create `.gitignore` to exclude sensitive files
|
||||
|
||||
**Windows** - Save to `%USERPROFILE%\.config\gitea\config.env`:
|
||||
```bash
|
||||
GITEA_URL=...
|
||||
GITEA_TOKEN=...
|
||||
GITEA_DEFAULT_ORG=... (if set)
|
||||
GITEA_RUNNER_CAPACITY=2
|
||||
GITEA_RUNNER_TIMEOUT=3h
|
||||
```
|
||||
- Set file permissions to restrict access (see setup-guide.md for PowerShell script)
|
||||
- Create `.gitignore` to exclude sensitive files
|
||||
|
||||
8. **Display completion summary in Chinese:**
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
配置完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
配置文件: ~/.config/gitea/config.env
|
||||
Runner 目录: ~/.config/gitea/runners
|
||||
|
||||
下一步:
|
||||
- 查看配置: /gitea-config
|
||||
- 创建 Runner: 告诉 AI '创建一个 runner'
|
||||
- 创建仓库: /create-gitea-repo <repo-name>
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
配置完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
配置文件: %USERPROFILE%\.config\gitea\config.env
|
||||
Runner 目录: %USERPROFILE%\.config\gitea\runners
|
||||
|
||||
下一步:
|
||||
- 查看配置: /gitea-config
|
||||
- 创建 Runner: 告诉 AI '创建一个 runner'
|
||||
- 创建仓库: /create-gitea-repo <repo-name>
|
||||
```
|
||||
|
||||
**Security notes:**
|
||||
- Config file permissions: 600 (owner read/write only)
|
||||
- Token is never displayed after initial input
|
||||
- Sensitive files excluded in .gitignore
|
||||
@@ -1,82 +0,0 @@
|
||||
---
|
||||
description: Switch default Gitea organization
|
||||
---
|
||||
|
||||
Switch the default Gitea organization in configuration.
|
||||
|
||||
## 工作目录
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
%USERPROFILE%\.config\gitea\
|
||||
```
|
||||
|
||||
**User input format:** `$ARGUMENTS` = organization name
|
||||
|
||||
**Example usage:**
|
||||
```
|
||||
/gitea-switch-org ai
|
||||
/gitea-switch-org my-team
|
||||
```
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **Check configuration exists:**
|
||||
- Config file:
|
||||
- macOS/Linux: `~/.config/gitea/config.env`
|
||||
- Windows: `%USERPROFILE%\.config\gitea\config.env`
|
||||
- If not exists: prompt user to run `/gitea-reset`
|
||||
|
||||
2. **Load configuration:**
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
Get-Content "$env:USERPROFILE\.config\gitea\config.env" | ForEach-Object {
|
||||
if ($_ -match '^([^=]+)=(.*)$') {
|
||||
[Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Parse user input:**
|
||||
- Organization name from `$ARGUMENTS`
|
||||
- If empty: show usage and examples
|
||||
|
||||
4. **Validate organization exists:**
|
||||
- API: `GET ${GITEA_URL}/api/v1/orgs/${org_name}`
|
||||
- Header: `Authorization: token ${GITEA_TOKEN}`
|
||||
- If 404: Show error and list available organizations:
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/user/orgs" | jq -r '.[].username'
|
||||
```
|
||||
|
||||
5. **Update configuration file:**
|
||||
- If `GITEA_DEFAULT_ORG` exists: update the line
|
||||
- If not exists: add after `GITEA_TOKEN`
|
||||
- Handle macOS (sed -i '') and Linux (sed -i) differences
|
||||
|
||||
6. **Display result in Chinese:**
|
||||
```
|
||||
✓ 默认组织已切换到: [org_name]
|
||||
|
||||
现在可以:
|
||||
- 创建仓库: /create-gitea-repo my-project
|
||||
(将创建到 [org_name]/my-project)
|
||||
- 查看配置: /gitea-config
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Switching organization doesn't affect existing repositories or runners
|
||||
- Only affects default owner for future repository creation
|
||||
- Can switch anytime
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
description: Review code or documentation and provide suggestions
|
||||
agent: plan
|
||||
---
|
||||
|
||||
Review the code or documentation and provide detailed feedback.
|
||||
|
||||
Please perform the following:
|
||||
|
||||
1. **Review** the code or documentation mentioned by the user
|
||||
2. **Identify issues** and areas for improvement
|
||||
3. **Provide suggestions** with clear explanations
|
||||
4. **Ask for confirmation** before making modifications
|
||||
|
||||
If the user hasn't specified what to review, ask them to provide the code or documentation they want reviewed.
|
||||
|
||||
When suggesting changes:
|
||||
- Explain why each change is needed
|
||||
- Prioritize suggestions by importance
|
||||
- Ask if the user wants all changes applied or only specific ones
|
||||
@@ -1,12 +1,14 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {},
|
||||
"model": "moonshotai-cn/kimi-k2.5",
|
||||
"permission": "allow",
|
||||
"plugin": ["@mohak34/opencode-notifier@latest"],
|
||||
"plugin": [
|
||||
"@mohak34/opencode-notifier@latest"
|
||||
],
|
||||
"provider": {
|
||||
"opencode": {
|
||||
"models": {
|
||||
"claude-opus-4-5": {
|
||||
"claude-sonnet-4-5": {
|
||||
"options": {
|
||||
"thinking": {
|
||||
"type": "enabled",
|
||||
@@ -15,13 +17,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"zhipuai-coding-plan": {
|
||||
"options": {
|
||||
"apiKey": "0f76aea86295476dbfa98724013b0fe8.o2EaJVqcl4Cf7WLP"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model": "zhipuai-coding-plan/glm-4.7",
|
||||
"small_model": "zhipuai-coding-plan/glm-4.7"
|
||||
}
|
||||
}
|
||||
|
||||
442
skill/agent-browser/SKILL.md
Normal file
442
skill/agent-browser/SKILL.md
Normal file
@@ -0,0 +1,442 @@
|
||||
---
|
||||
name: ab
|
||||
description: 浏览器自动化工具,用于网页测试、表单填写、截图、数据提取等
|
||||
---
|
||||
|
||||
# 浏览器自动化工具 agent-browser
|
||||
|
||||
ab是 agent-browser 的缩写,它是一个为 AI 代理设计的无头浏览器自动化 CLI 工具,基于 Rust 和 Playwright 构建。支持快速导航、元素交互、页面截图、数据提取等功能。
|
||||
|
||||
注意:必须使用 agent-browser 全称作为命令关键字。
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装检查
|
||||
agent-browser 默认已安装。如果遇到 "command not found" 错误,请运行以下命令安装:
|
||||
|
||||
```bash
|
||||
# 全局安装
|
||||
npm install -g agent-browser
|
||||
|
||||
# 下载 Chromium 浏览器
|
||||
agent-browser install
|
||||
```
|
||||
|
||||
### 核心工作流程(4步法)
|
||||
```bash
|
||||
# 使用 agent-browser
|
||||
1. agent-browser open <url>
|
||||
2. agent-browser snapshot -i
|
||||
3. agent-browser click @e1
|
||||
4. agent-browser fill @e2 "文本"
|
||||
```
|
||||
|
||||
## 核心工作流程详解
|
||||
|
||||
### 1. 导航到页面
|
||||
```bash
|
||||
agent-browser open https://example.com
|
||||
```
|
||||
|
||||
### 2. 获取页面快照(推荐使用交互模式)
|
||||
```bash
|
||||
agent-browser snapshot -i # 仅显示交互元素(按钮、输入框、链接)
|
||||
```
|
||||
|
||||
**输出示例:**
|
||||
```
|
||||
- link "Learn more" [ref=e1]
|
||||
- textbox "Email" [ref=e2]
|
||||
- button "Submit" [ref=e3]
|
||||
```
|
||||
|
||||
### 3. 使用 Refs 进行交互
|
||||
快照中的 `[ref=e1]`、`[ref=e2]` 等是元素的唯一引用标识,**推荐使用 refs 而非 CSS 选择器**:
|
||||
- **确定性**:ref 指向快照中的确切元素
|
||||
- **快速**:无需重新查询 DOM
|
||||
- **AI 友好**:适合 LLM 处理
|
||||
|
||||
### 4. 页面变化后重新快照
|
||||
页面发生重大变化(导航、表单提交等)后,需要重新获取快照:
|
||||
```bash
|
||||
agent-browser snapshot -i # 重新获取新的 refs
|
||||
```
|
||||
|
||||
## 命令参考
|
||||
|
||||
### 导航命令
|
||||
```bash
|
||||
agent-browser open <url> # 导航到 URL(或:ab open <url>)
|
||||
agent-browser back # 后退(或:ab back)
|
||||
agent-browser forward # 前进(或:ab forward)
|
||||
agent-browser reload # 重新加载页面(或:ab reload)
|
||||
agent-browser close # 关闭浏览器(或:ab close)
|
||||
```
|
||||
|
||||
### 快照命令(页面分析)
|
||||
```bash
|
||||
agent-browser snapshot # 完整可访问性树(或:ab snapshot)
|
||||
agent-browser snapshot -i # 仅交互元素(推荐)(或:ab snapshot -i)
|
||||
agent-browser snapshot -c # 紧凑输出(移除空结构元素)(或:ab snapshot -c)
|
||||
agent-browser snapshot -d 3 # 限制深度为 3 级(或:ab snapshot -d 3)
|
||||
agent-browser snapshot -s "#main" # 限定到 CSS 选择器范围(或:ab snapshot -s "#main")
|
||||
```
|
||||
|
||||
### 交互命令(使用 @refs)
|
||||
```bash
|
||||
# 基础交互
|
||||
agent-browser click @e1 # 单击
|
||||
agent-browser dblclick @e1 # 双击
|
||||
agent-browser fill @e2 "文本" # 清空并填写
|
||||
agent-browser type @e2 "文本" # 不清空直接输入
|
||||
agent-browser press Enter # 按键(支持组合键 Control+a)
|
||||
agent-browser hover @e1 # 悬停
|
||||
agent-browser focus @e1 # 聚焦
|
||||
|
||||
# 表单操作
|
||||
agent-browser check @e1 # 勾选复选框
|
||||
agent-browser uncheck @e1 # 取消勾选
|
||||
agent-browser select @e1 "值" # 选择下拉选项
|
||||
agent-browser upload @e1 file1.jpg # 上传文件
|
||||
|
||||
# 滚动
|
||||
agent-browser scroll down 500 # 向下滚动 500px
|
||||
agent-browser scrollintoview @e1 # 滚动元素到可见区域
|
||||
```
|
||||
|
||||
### 获取信息
|
||||
```bash
|
||||
agent-browser get text @e1 # 获取元素文本
|
||||
agent-browser get value @e1 # 获取输入框值
|
||||
agent-browser get html @e1 # 获取 innerHTML
|
||||
agent-browser get attr @e1 id # 获取属性
|
||||
agent-browser get title # 获取页面标题
|
||||
agent-browser get url # 获取当前 URL
|
||||
agent-browser get count ".item" # 计数匹配元素
|
||||
agent-browser get box @e1 # 获取边界框
|
||||
```
|
||||
|
||||
### 检查状态
|
||||
```bash
|
||||
agent-browser is visible @e1 # 检查是否可见
|
||||
agent-browser is enabled @e1 # 检查是否启用
|
||||
agent-browser is checked @e1 # 检查是否勾选
|
||||
```
|
||||
|
||||
### 截图命令
|
||||
```bash
|
||||
agent-browser screenshot # 截图到标准输出
|
||||
agent-browser screenshot page.png # 保存到文件
|
||||
agent-browser screenshot --full # 完整页面截图
|
||||
```
|
||||
|
||||
### 等待命令
|
||||
```bash
|
||||
agent-browser wait @e1 # 等待元素可见
|
||||
agent-browser wait 2000 # 等待毫秒数
|
||||
agent-browser wait --text "成功" # 等待文本出现
|
||||
agent-browser wait --url "*/dashboard" # 等待 URL 模式匹配
|
||||
agent-browser wait --load networkidle # 等待网络空闲
|
||||
|
||||
# 加载状态选项:load, domcontentloaded, networkidle
|
||||
```
|
||||
|
||||
### 语义化定位器(替代 refs)
|
||||
```bash
|
||||
agent-browser find role button click --name "提交"
|
||||
agent-browser find text "登录" click
|
||||
agent-browser find label "邮箱" fill "user@test.com"
|
||||
agent-browser find placeholder "请输入" fill "内容"
|
||||
agent-browser find first ".item" click
|
||||
agent-browser find nth 2 "a" text
|
||||
```
|
||||
|
||||
## 认证与状态管理
|
||||
|
||||
### 方法1:手动登录流程(推荐用于首次)
|
||||
```bash
|
||||
# 导航到登录页面
|
||||
agent-browser open https://example.com/login
|
||||
|
||||
# 填写表单
|
||||
agent-browser snapshot -i
|
||||
# 输出显示:textbox "邮箱" [ref=e1], textbox "密码" [ref=e2], button "登录" [ref=e3]
|
||||
|
||||
agent-browser fill @e1 "user@example.com"
|
||||
agent-browser fill @e2 "password123"
|
||||
agent-browser click @e3
|
||||
|
||||
# 等待登录成功
|
||||
agent-browser wait --url "*/dashboard"
|
||||
|
||||
# 保存认证状态(重要!)
|
||||
agent-browser state save auth.json
|
||||
```
|
||||
|
||||
### 方法2:加载已保存状态(后续使用)
|
||||
```bash
|
||||
# 加载保存的认证状态
|
||||
agent-browser state load auth.json
|
||||
|
||||
# 直接访问受保护页面
|
||||
agent-browser open https://example.com/dashboard
|
||||
```
|
||||
|
||||
### 方法3:HTTP Headers 认证(跳过登录界面)
|
||||
```bash
|
||||
# 为特定域名设置认证头
|
||||
agent-browser open https://api.example.com --headers '{"Authorization": "Bearer <token>"}'
|
||||
```
|
||||
|
||||
### 方法4:Cookies 管理
|
||||
```bash
|
||||
# 设置 cookie
|
||||
agent-browser cookies set session_id "abc123"
|
||||
|
||||
# 查看所有 cookies
|
||||
agent-browser cookies
|
||||
```
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 无头/有头模式
|
||||
```bash
|
||||
# 默认:无头模式(无界面)
|
||||
agent-browser open example.com
|
||||
|
||||
# 有头模式:显示浏览器窗口(适合调试)
|
||||
agent-browser --headed open example.com
|
||||
```
|
||||
|
||||
**无头模式特点**:
|
||||
- 后台运行 Chromium
|
||||
- 不占用屏幕空间
|
||||
- 更快的执行速度
|
||||
- 适合自动化测试和 AI Agent 使用
|
||||
|
||||
### 会话隔离
|
||||
```bash
|
||||
# 创建独立会话
|
||||
agent-browser --session user1 open site-a.com
|
||||
agent-browser --session user2 open site-b.com
|
||||
|
||||
# 查看活动会话
|
||||
agent-browser session list
|
||||
|
||||
# 每个会话独立:
|
||||
# - 浏览器实例
|
||||
# - Cookies 和存储
|
||||
# - 导航历史
|
||||
# - 认证状态
|
||||
```
|
||||
|
||||
### JSON 输出(适合机器解析)
|
||||
```bash
|
||||
agent-browser snapshot -i --json
|
||||
agent-browser get text @e1 --json
|
||||
agent-browser is visible @e2 --json
|
||||
```
|
||||
|
||||
### 自定义浏览器可执行文件
|
||||
```bash
|
||||
# 使用自定义 Chromium 路径
|
||||
agent-browser --executable-path /path/to/chromium open example.com
|
||||
|
||||
# 环境变量方式
|
||||
AGENT_BROWSER_EXECUTABLE_PATH=/path/to/chromium agent-browser open example.com
|
||||
```
|
||||
|
||||
### CDP 模式(连接现有浏览器)
|
||||
```bash
|
||||
# 连接通过 Chrome DevTools Protocol 运行的浏览器
|
||||
agent-browser --cdp 9222 snapshot
|
||||
|
||||
# 可控制:Electron 应用、启用远程调试的 Chrome、WebView2 等
|
||||
```
|
||||
|
||||
### 调试工具
|
||||
```bash
|
||||
agent-browser console # 查看控制台消息
|
||||
agent-browser errors # 查看页面错误
|
||||
agent-browser console --clear # 清空控制台
|
||||
agent-browser errors --clear # 清空错误
|
||||
agent-browser highlight @e1 # 高亮显示元素
|
||||
```
|
||||
|
||||
## 示例场景
|
||||
|
||||
### 示例1:表单提交
|
||||
```bash
|
||||
# 1. 导航到表单页面
|
||||
agent-browser open https://example.com/form
|
||||
|
||||
# 2. 获取交互元素快照
|
||||
agent-browser snapshot -i
|
||||
# 输出:textbox "邮箱" [ref=e1], textbox "密码" [ref=e2], button "提交" [ref=e3]
|
||||
|
||||
# 3. 填写并提交表单
|
||||
agent-browser fill @e1 "user@example.com"
|
||||
agent-browser fill @e2 "password123"
|
||||
agent-browser click @e3
|
||||
|
||||
# 4. 等待结果并验证
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser snapshot -i # 检查结果
|
||||
```
|
||||
|
||||
### 示例2:带认证的完整流程
|
||||
```bash
|
||||
# 首次:登录并保存状态
|
||||
agent-browser open https://app.example.com/login
|
||||
agent-browser fill "#email" "username"
|
||||
agent-browser fill "#password" "password123"
|
||||
agent-browser click "#submit"
|
||||
agent-browser wait --url "**/dashboard"
|
||||
agent-browser state save app-auth.json
|
||||
|
||||
# 后续使用:加载状态
|
||||
agent-browser state load app-auth.json
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
|
||||
# 执行操作
|
||||
agent-browser snapshot -i
|
||||
agent-browser click @e1
|
||||
```
|
||||
|
||||
### 示例3:数据提取
|
||||
```bash
|
||||
# 提取列表数据
|
||||
agent-browser open https://example.com/products
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# 获取所有产品标题
|
||||
for i in $(seq 1 10); do
|
||||
agent-browser get text "@e$i" --json
|
||||
done
|
||||
|
||||
# 或使用 CSS 选择器
|
||||
agent-browser get text ".product-title"
|
||||
```
|
||||
|
||||
### 示例4:并行测试
|
||||
```bash
|
||||
# 会话1:用户A
|
||||
agent-browser --session userA open site.com
|
||||
agent-browser --session userA fill "#email" "userA@test.com"
|
||||
agent-browser --session userA fill "#password" "passA123"
|
||||
|
||||
# 会话2:用户B(同时运行)
|
||||
agent-browser --session userB open site.com
|
||||
agent-browser --session userB fill "#email" "userB@test.com"
|
||||
agent-browser --session userB fill "#password" "passB123"
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 优先使用 Refs
|
||||
- 从 `snapshot -i` 获取 refs
|
||||
- 使用 `@e1`、`@e2` 而非 CSS 选择器
|
||||
- 页面变化后重新快照获取新 refs
|
||||
|
||||
### 2. 合理使用等待
|
||||
- 页面加载:`wait --load networkidle`
|
||||
- 元素出现:`wait @e1`
|
||||
- 文本出现:`wait --text "成功"`
|
||||
- 避免硬编码 sleep,使用条件等待
|
||||
|
||||
### 3. 状态管理策略
|
||||
- 首次登录后使用 `state save`
|
||||
- 后续使用 `state load` 避免重复登录
|
||||
- 敏感操作使用 `--session` 隔离
|
||||
|
||||
### 4. 错误处理
|
||||
- 检查元素是否存在:`is visible @e1`
|
||||
- 查看控制台日志:`console`
|
||||
- 调试时使用 `--headed` 模式
|
||||
|
||||
### 5. 性能优化
|
||||
- 使用 `-i` 参数限制快照输出
|
||||
- 批量操作使用循环
|
||||
- 合理使用等待避免超时
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
**1. "command not found: agent-browser" 错误**
|
||||
```bash
|
||||
# 错误原因:agent-browser 未安装
|
||||
# 解决方案:运行安装命令
|
||||
npm install -g agent-browser
|
||||
agent-browser install
|
||||
```
|
||||
|
||||
**2. "Unsupported token @e1" 错误**
|
||||
```bash
|
||||
# 错误原因:快照后页面已刷新,refs 失效
|
||||
# 解决方案:重新获取快照
|
||||
agent-browser snapshot -i
|
||||
agent-browser click @e1 # 使用新的 ref
|
||||
```
|
||||
|
||||
**3. 元素找不到**
|
||||
```bash
|
||||
# 检查元素是否存在
|
||||
agent-browser is visible @e1
|
||||
|
||||
# 等待元素出现
|
||||
agent-browser wait @e1
|
||||
|
||||
# 使用语义化查找
|
||||
agent-browser find role button click --name "提交"
|
||||
```
|
||||
|
||||
**4. 登录状态丢失**
|
||||
```bash
|
||||
# 重新登录并保存状态
|
||||
agent-browser state save auth.json
|
||||
|
||||
# 或设置 cookies
|
||||
agent-browser cookies set session_id "value"
|
||||
```
|
||||
|
||||
**5. 页面加载缓慢**
|
||||
```bash
|
||||
# 增加等待时间
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser wait 5000
|
||||
|
||||
# 或设置超时
|
||||
agent-browser set timeout 30000
|
||||
```
|
||||
|
||||
## 平台支持
|
||||
|
||||
| 平台 | 原生二进制 | 回退方案 |
|
||||
|------|-----------|----------|
|
||||
| macOS ARM64 | ✓ | Node.js |
|
||||
| macOS x64 | ✓ | Node.js |
|
||||
| Linux ARM64 | ✓ | Node.js |
|
||||
| Linux x64 | ✓ | Node.js |
|
||||
| Windows x64 | ✓ | Node.js |
|
||||
|
||||
## 技术架构
|
||||
|
||||
agent-browser 采用客户端-守护进程架构:
|
||||
1. **Rust CLI**(原生二进制)- 解析命令,与守护进程通信
|
||||
2. **Node.js 守护进程** - 管理 Playwright 浏览器实例
|
||||
3. **回退方案** - 如果原生二进制不可用,直接使用 Node.js
|
||||
|
||||
守护进程在首次命令时自动启动,并在命令间持久化以实现快速后续操作。
|
||||
|
||||
**浏览器引擎**:默认使用 Chromium。守护进程也支持通过 Playwright 协议使用 Firefox 和 WebKit。
|
||||
|
||||
## 相关资源
|
||||
|
||||
- 官方仓库:https://github.com/vercel-labs/agent-browser
|
||||
- 官方文档:https://agent-browser.dev
|
||||
- npm 包:https://www.npmjs.com/package/agent-browser
|
||||
|
||||
## 许可证
|
||||
|
||||
Apache-2.0
|
||||
27
skill/apple/SKILL.md
Normal file
27
skill/apple/SKILL.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: apple
|
||||
description: Apple 开发者账号管理、注册最佳实践与风控规避指南
|
||||
---
|
||||
|
||||
# Apple Developer Account Management
|
||||
|
||||
本 Skill 提供了 Apple 开发者账号申请、管理及风控规避的最佳实践指南。
|
||||
|
||||
## 功能文档
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [注册最佳实践](./registration-guide.md) | Apple 开发者账号注册流程、风控规避与问题诊断指南 |
|
||||
|
||||
## 核心原则 (Core Principles)
|
||||
|
||||
1. **物理与数据隔离**:注册环境必须保持绝对干净(一机、一号、一网、一卡)。
|
||||
2. **真实身份**:必须使用真实的个人身份信息,严禁使用虚假资料。
|
||||
3. **设备纯净**:使用未被 Apple 标记过的设备进行操作。
|
||||
4. **网络安全**:避免使用公共 WiFi 或 VPN,优先使用移动数据网络。
|
||||
|
||||
## 常见问题
|
||||
|
||||
- **联系支持 (Contact Support)**:通常由风控系统触发,原因是设备关联、网络污染或账号行为异常。
|
||||
- **支付失败**:通常由于信用卡被关联或账单地址不匹配。
|
||||
- **身份验证失败**:证件照片不清晰或与填写的名字不匹配。
|
||||
129
skill/apple/registration-guide.md
Normal file
129
skill/apple/registration-guide.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Apple 开发者账号注册最佳实践报告 (2025版)
|
||||
|
||||
本指南针对 Apple 开发者账户注册过程中常见的“联系 Apple 支持”风控拦截问题,提供详细的诊断与注册最佳实践。
|
||||
|
||||
## 1. 问题诊断:为什么会提示“联系支持”?
|
||||
|
||||
当 Apple 的风控算法判定注册行为存在“高风险”或“非真人特征”时,会阻断流程。常见触发原因如下:
|
||||
|
||||
* **设备污染(Device Tainting):最常见原因**
|
||||
* 该 iPhone/iPad 曾登录过被封禁的 Apple ID。
|
||||
* 该设备曾频繁切换不同的 Apple ID。
|
||||
* **关键点**:Apple 记录的是设备的 **UDID/序列号**。简单的“退出登录”或“还原设置”通常不足以清洗被列入黑名单的设备指纹。
|
||||
* **网络环境污染**
|
||||
* 使用了公司的公共 Wi-Fi(如果公司内有其他同事的账号被封,该 IP 可能已被标记)。
|
||||
* 使用了 VPN 或代理工具(IP 地址频繁跳变或属于数据中心号段)。
|
||||
* **账号行为异常**
|
||||
* 新注册的 Apple ID **没有任何使用记录**(如下载 App、充值、云同步),直接申请开发者,会被视为“养号/机器注册”。
|
||||
* 填写的身份信息(拼音/英文名)与证件或信用卡持卡人姓名不完全一致。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心原则:彻底的物理与数据隔离
|
||||
|
||||
为了确保注册成功,必须严格执行**“独立环境”**原则。请放弃“仅仅退出旧账号”的想法,必须把注册环境视为一个全新的“无菌室”。
|
||||
|
||||
**黄金法则:**
|
||||
> **1 台干净设备 + 1 个独立网络 + 1 套真实身份 + 1 张独立银行卡**
|
||||
|
||||
---
|
||||
|
||||
## 3. 最佳实践流程指南
|
||||
|
||||
请按照以下步骤重新规划注册流程(建议换人或换全套环境):
|
||||
|
||||
### 第一阶段:环境准备(硬件与网络)
|
||||
|
||||
1. **设备选择(非常重要)**
|
||||
* **最佳**:使用从未申请过开发者账号、未登录过违规账号的 iPhone 或 iPad。
|
||||
* **次选**:如果必须用旧设备,必须进行**DFU模式彻底刷机**(不只是“抹掉所有内容和设置”),但这仍有风险,因为硬件序列号无法改变。
|
||||
2. **网络环境**
|
||||
* **绝对禁止**:使用公司 Wi-Fi、公共场所 Wi-Fi、VPN。
|
||||
* **必须使用**:手机运营商的 **4G/5G 移动数据网络**。这是最干净、最受信任的 IP 来源。
|
||||
3. **手机号码**
|
||||
* 使用该申请人实名认证的手机号。
|
||||
* **严禁**:使用虚拟运营商号码(170/171段)、接码平台号码。
|
||||
4. **邮箱选择**
|
||||
* **个人注册**:
|
||||
* **推荐**:Gmail、iCloud 邮箱、Outlook/Hotmail
|
||||
* **不推荐**:QQ 邮箱(通过率较低,风控系统可能视为高风险)
|
||||
* **关键**:确保邮箱有真实使用记录,非新注册账号
|
||||
* **组织注册(公司账号)**:
|
||||
* **必须**:公司域名邮箱(如 `@company.com`)
|
||||
* **要求**:邮箱域名必须与公司官网域名一致
|
||||
* **验证**:确保邮箱能正常收发邮件(Apple 会发送验证邮件)
|
||||
|
||||
### 第二阶段:账号“养护”(关键缓冲期)
|
||||
|
||||
不要注册完 Apple ID 马上申请开发者,这非常像机器行为。
|
||||
|
||||
1. **注册 Apple ID**:在设备上直接注册,开启双重认证(2FA)。
|
||||
* **邮箱选择**:优先使用 Gmail 或 iCloud 邮箱,避免使用 QQ 邮箱
|
||||
* **身份验证**:填写真实姓名(拼音/英文),与身份证一致
|
||||
2. **模拟真实用户行为(建议 1-3 天)**:
|
||||
* 登录 App Store 下载几个常用 App(微信、抖音等)。
|
||||
* 开启 iCloud 同步(通讯录、照片)。
|
||||
* 设置并使用 Apple Pay(绑定用于支付的信用卡)。
|
||||
* 如果可能,充值少量金额购买一个 App。
|
||||
* **目的**:向 Apple 证明这是一个“活人”在使用的“主力机”。
|
||||
|
||||
### 第三阶段:正式申请
|
||||
|
||||
1. **下载应用**:使用该 Apple ID 登录 App Store 下载 **Apple Developer App**。
|
||||
2. **填写信息**:
|
||||
* **姓名**:必须填写真实姓名(拼音/英文),必须与**身份证**和**信用卡**上的拼音完全一致。不要用英文昵称(如 Peter Zhang)。
|
||||
* **身份证号**:输入无误。
|
||||
3. **人脸识别**:
|
||||
* 确保光线充足,背景简单。
|
||||
* 必须由账号持有人本人进行扫脸。
|
||||
4. **支付环节**:
|
||||
* **信用卡**:必须使用**从未在其他开发者账号使用过**的 Visa/MasterCard 信用卡。
|
||||
* **账单地址**:尽量填写真实账单地址。
|
||||
|
||||
---
|
||||
|
||||
## 4. 邮箱选择详细指南
|
||||
|
||||
### 官方要求
|
||||
- **个人注册**:可以使用任何邮箱,但**公司域名邮箱**为最佳选择
|
||||
- **组织注册**:**必须**使用公司域名邮箱(如 `@company.com`)
|
||||
|
||||
### 邮箱类型推荐(按优先级)
|
||||
1. **公司域名邮箱**(最佳)
|
||||
- 适用于组织注册,必须使用
|
||||
- 邮箱域名必须与公司官网域名一致
|
||||
2. **Gmail**(次佳)
|
||||
- 国际通用,信誉度高
|
||||
- 风控系统认可度高
|
||||
3. **iCloud 邮箱**(Apple 自家服务)
|
||||
- 最受 Apple 信任
|
||||
- 与 Apple 生态系统无缝集成
|
||||
4. **Outlook/Hotmail**(微软系)
|
||||
- 信誉良好,通过率较高
|
||||
5. **其他主流企业邮箱**
|
||||
- 如企业微信邮箱、阿里云邮箱等
|
||||
|
||||
### 不推荐邮箱类型
|
||||
- **QQ 邮箱**:通过率较低,风控系统可能视为高风险
|
||||
- **163/126 邮箱**:有一定风险,不如 Gmail 可靠
|
||||
- **虚拟邮箱/临时邮箱**:绝对禁止使用
|
||||
- **接码平台邮箱**:会被直接拒绝
|
||||
|
||||
### 关键原则
|
||||
- **邮箱历史**:使用有真实使用记录的邮箱,避免新注册账号
|
||||
- **一致性**:邮箱信息与身份信息保持一致
|
||||
- **可访问性**:确保邮箱能正常收发邮件,Apple 会发送验证邮件
|
||||
|
||||
## 5. 针对已触发风控情况的建议
|
||||
|
||||
如果您的注册尝试已经触发了“联系支持”提示:
|
||||
|
||||
1. **放弃当前环境**:不要继续在已报错的设备上重试,也不要用已报错的 Apple ID 重试。
|
||||
2. **执行“新号新机”方案**:
|
||||
* 找一位**还没有注册过**开发者账号的同事。
|
||||
* 使用该同事**自己的 iPhone**(确保该手机没乱登过别人的 ID)。
|
||||
* 关闭 Wi-Fi,使用 **4G/5G**。
|
||||
* **更换邮箱**:使用 Gmail 或公司域名邮箱
|
||||
* 按照上述“最佳实践”流程操作。
|
||||
3. **关于申诉**:
|
||||
* 除非您确信没有任何违规(设备绝对纯净、身份绝对真实),否则申诉解封的成功率极低,建议直接采用新方案。
|
||||
@@ -7,6 +7,14 @@ description: Git workflow best practices with commit conventions, tagging, and c
|
||||
|
||||
You are an expert in Git version control and repository management.
|
||||
|
||||
## 功能文档
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [Commit Workflow](./commit-workflow.md) | 提交暂存文件,自动生成提交信息并创建版本标签 |
|
||||
| [Push Workflow](./push-workflow.md) | 提交并推送到远程仓库的完整工作流 |
|
||||
| [SSH Keychain](./ssh-keychain.md) | SSH 密钥管理与 macOS Keychain 自动解锁配置 |
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. **Default Main Branch**: Use `main` as the primary branch (not `master`)
|
||||
|
||||
163
skill/git/commit-workflow.md
Normal file
163
skill/git/commit-workflow.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Git Commit Workflow
|
||||
|
||||
提交暂存文件,自动生成提交信息并创建版本标签的完整工作流。
|
||||
|
||||
## 概述
|
||||
|
||||
此工作流用于:
|
||||
- 自动分析暂存区变更
|
||||
- 根据 Conventional Commits 规范生成提交信息
|
||||
- 检测项目类型并更新版本号
|
||||
- 创建语义化版本标签
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### 步骤 1: 检查暂存区
|
||||
|
||||
```bash
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
- 如果暂存区为空,通知用户并停止
|
||||
- 如果有文件,继续下一步
|
||||
|
||||
### 步骤 2: 收集信息(并行执行)
|
||||
|
||||
```bash
|
||||
# 并行执行以下命令
|
||||
git status
|
||||
git diff --cached
|
||||
git log --oneline -10
|
||||
git tag --list | sort -V | tail -5
|
||||
```
|
||||
|
||||
同时检查 `AGENTS.md` 文件获取:
|
||||
- 仓库类型(polyrepo/monorepo)
|
||||
- 版本规则
|
||||
- 项目结构信息
|
||||
|
||||
### 步骤 3: 检测仓库类型
|
||||
|
||||
**Polyrepo(单仓库)**
|
||||
- Tag 格式:`<version>`(如 `1.2.0`)
|
||||
|
||||
**Monorepo(多项目)**
|
||||
- Tag 格式:`<subproject>-<version>`(如 `ios-1.2.0`)
|
||||
- 检测特征:`packages/`、`apps/`、`services/` 目录
|
||||
|
||||
### 步骤 4: 检测项目类型和版本
|
||||
|
||||
| 项目类型 | 版本文件 | 版本字段 |
|
||||
|---------|---------|---------|
|
||||
| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` |
|
||||
| Node.js | `package.json` | `version` |
|
||||
| Android (Groovy) | `app/build.gradle` | `versionName` |
|
||||
| Android (Kotlin) | `app/build.gradle.kts` | `versionName` |
|
||||
| Go | Git tag only | - |
|
||||
| Python | `pyproject.toml` / `setup.py` | `version` |
|
||||
| Rust | `Cargo.toml` | `version` |
|
||||
|
||||
### 步骤 5: 生成提交信息
|
||||
|
||||
遵循 Conventional Commits 格式:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
```
|
||||
|
||||
**提交类型**:
|
||||
|
||||
| Type | 描述 | 版本影响 |
|
||||
|------|------|---------|
|
||||
| `feat` | 新功能 | minor +1 |
|
||||
| `fix` | Bug 修复 | patch +1 |
|
||||
| `perf` | 性能优化 | patch +1 |
|
||||
| `BREAKING CHANGE` | 破坏性变更 | major +1 |
|
||||
| `docs` | 文档更新 | 无 |
|
||||
| `style` | 代码格式 | 无 |
|
||||
| `refactor` | 重构 | 无 |
|
||||
| `test` | 测试 | 无 |
|
||||
| `chore` | 维护任务 | 无 |
|
||||
| `ci` | CI/CD 变更 | 无 |
|
||||
| `build` | 构建配置 | 无 |
|
||||
|
||||
**提交语言**:
|
||||
- macOS/Linux:使用中文
|
||||
- Windows:使用英文(避免编码问题)
|
||||
|
||||
**Monorepo Scope**:
|
||||
- 单项目变更:`feat(ios): 添加上传功能`
|
||||
- 多项目变更:`chore: 更新共享依赖`
|
||||
|
||||
### 步骤 6: 确定新版本号
|
||||
|
||||
根据提交类型计算新版本:
|
||||
|
||||
**版本递增规则**:
|
||||
- `feat`:minor +1(如 `1.2.0` → `1.3.0`)
|
||||
- `fix`/`perf`:patch +1(如 `1.2.3` → `1.2.4`)
|
||||
- Breaking change:major +1(如 `1.2.3` → `2.0.0`)
|
||||
|
||||
**不更新版本**:
|
||||
- `docs`、`test`、`refactor`、`style`、`build`、`ci`、`chore`
|
||||
|
||||
### 步骤 7: 更新版本文件并暂存
|
||||
|
||||
如果需要更新版本(步骤 6 确定了新版本号):
|
||||
|
||||
1. **更新版本文件**:将版本号写入对应的版本文件
|
||||
2. **添加到暂存区**:
|
||||
```bash
|
||||
git add <version-file>
|
||||
```
|
||||
3. **验证暂存**:
|
||||
```bash
|
||||
git diff --cached --name-only
|
||||
```
|
||||
确认版本文件已在暂存区
|
||||
|
||||
### 步骤 8: 执行提交
|
||||
|
||||
```bash
|
||||
git commit -m "<commit-message>"
|
||||
```
|
||||
|
||||
### 步骤 9: 创建版本标签
|
||||
|
||||
仅在版本更新时创建(除非用户指定 "skip tag"):
|
||||
|
||||
**Polyrepo**:
|
||||
```bash
|
||||
git tag -a "1.2.0" -m "<commit-message>"
|
||||
```
|
||||
|
||||
**Monorepo**:
|
||||
```bash
|
||||
git tag -a "ios-1.2.0" -m "<commit-message>"
|
||||
```
|
||||
|
||||
## 选项
|
||||
|
||||
- `skip tag` / `skip`:跳过标签创建
|
||||
|
||||
## 输出格式
|
||||
|
||||
```
|
||||
✓ 提交成功
|
||||
|
||||
提交信息:[commit message]
|
||||
版本标签:[tag](如果创建了)
|
||||
|
||||
要推送到远程仓库,请运行:/git-push
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 此命令**不会推送**到远程,使用 `/git-push` 推送
|
||||
- 暂存区为空时会提示用户先 `git add`
|
||||
- 标签注释使用与提交相同的消息内容
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Git Workflow Best Practices](./SKILL.md)
|
||||
- [Push Workflow](./push-workflow.md)
|
||||
107
skill/git/push-workflow.md
Normal file
107
skill/git/push-workflow.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Git Push Workflow
|
||||
|
||||
提交暂存文件,创建版本标签并推送到远程仓库的完整工作流。
|
||||
|
||||
## 概述
|
||||
|
||||
此工作流是 **All-in-One** 命令,组合了:
|
||||
- `/git-commit` 的所有功能
|
||||
- 推送提交到远程
|
||||
- 推送标签到远程
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### 步骤 1-9: 与 Commit Workflow 相同
|
||||
|
||||
参考 [Commit Workflow](./commit-workflow.md):
|
||||
|
||||
1. 检查暂存区(不能为空)
|
||||
2. 收集变更信息和仓库状态
|
||||
3. 检测仓库类型(polyrepo/monorepo)
|
||||
4. 检测项目类型和版本
|
||||
5. 生成提交信息(Conventional Commits,中文)
|
||||
6. 确定新版本号
|
||||
7. 更新版本文件并添加到暂存区
|
||||
8. 执行提交
|
||||
9. 创建版本标签
|
||||
|
||||
### 步骤 10: 推送提交到远程
|
||||
|
||||
```bash
|
||||
git push origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
### 步骤 11: 推送标签到远程
|
||||
|
||||
仅在创建了标签时执行:
|
||||
|
||||
**Polyrepo**:
|
||||
```bash
|
||||
git push origin <version>
|
||||
```
|
||||
|
||||
**Monorepo**:
|
||||
```bash
|
||||
git push origin <subproject>-<version>
|
||||
```
|
||||
|
||||
## 选项
|
||||
|
||||
- `skip tag` / `skip`:跳过标签创建
|
||||
|
||||
## 输出格式
|
||||
|
||||
```
|
||||
✓ 提交并推送成功
|
||||
|
||||
分支:[branch]
|
||||
提交信息:[commit message]
|
||||
版本标签:[tag](如果创建了)
|
||||
|
||||
已推送到远程仓库:origin
|
||||
- 提交:[commit hash]
|
||||
- 标签:[tag]
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 暂存区为空
|
||||
|
||||
```
|
||||
暂存区为空,请先使用 `git add` 添加文件。
|
||||
```
|
||||
|
||||
### 推送失败
|
||||
|
||||
```
|
||||
❌ 推送失败:[error message]
|
||||
|
||||
可能的解决方案:
|
||||
1. 先拉取远程变更:git pull origin <branch>
|
||||
2. 检查网络连接
|
||||
3. 检查远程仓库权限
|
||||
```
|
||||
|
||||
### 标签已存在
|
||||
|
||||
```
|
||||
❌ 标签推送失败:tag already exists
|
||||
|
||||
解决方案:
|
||||
1. 删除本地标签:git tag -d <tag>
|
||||
2. 更新版本号后重新提交
|
||||
```
|
||||
|
||||
## 使用场景
|
||||
|
||||
| 场景 | 推荐命令 |
|
||||
|------|---------|
|
||||
| 本地提交,稍后审查 | `/git-commit` |
|
||||
| 提交并立即推送 | `/git-push` |
|
||||
| 仅推送已有提交 | `git push origin <branch>` |
|
||||
| 仅推送标签 | `git push origin <tag>` |
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Git Workflow Best Practices](./SKILL.md)
|
||||
- [Commit Workflow](./commit-workflow.md)
|
||||
@@ -1,663 +0,0 @@
|
||||
# Git Quick Reference
|
||||
|
||||
Quick reference guide for common Git operations.
|
||||
|
||||
## File Changes and Status
|
||||
|
||||
### View Changed Files
|
||||
|
||||
```bash
|
||||
# Show working directory status
|
||||
git status
|
||||
|
||||
# Show short status
|
||||
git status -s
|
||||
|
||||
# List changed files only (unstaged)
|
||||
git diff --name-only
|
||||
|
||||
# List changed files only (staged)
|
||||
git diff --cached --name-only
|
||||
# or
|
||||
git diff --staged --name-only
|
||||
|
||||
# Show file change statistics
|
||||
git diff --stat
|
||||
git diff --cached --stat
|
||||
```
|
||||
|
||||
### View Detailed Changes
|
||||
|
||||
```bash
|
||||
# View unstaged changes
|
||||
git diff
|
||||
|
||||
# View staged changes
|
||||
git diff --cached
|
||||
# or
|
||||
git diff --staged
|
||||
|
||||
# View specific file changes
|
||||
git diff <file-path>
|
||||
git diff --cached <file-path>
|
||||
|
||||
# View changes between commits
|
||||
git diff <commit1>..<commit2>
|
||||
git diff HEAD~1..HEAD
|
||||
|
||||
# View changes between branches
|
||||
git diff main..feature-branch
|
||||
```
|
||||
|
||||
## Staging and Committing
|
||||
|
||||
### Add Files to Staging
|
||||
|
||||
```bash
|
||||
# Add specific file
|
||||
git add <file-path>
|
||||
|
||||
# Add all files in directory
|
||||
git add .
|
||||
|
||||
# Add all files in repository
|
||||
git add -A
|
||||
|
||||
# Add files interactively
|
||||
git add -p
|
||||
|
||||
# Add only modified files (not new files)
|
||||
git add -u
|
||||
```
|
||||
|
||||
### Check Staging Area
|
||||
|
||||
```bash
|
||||
# List files in staging area
|
||||
git diff --cached --name-only
|
||||
|
||||
# Show detailed staged changes
|
||||
git diff --cached
|
||||
```
|
||||
|
||||
### Commit Changes
|
||||
|
||||
```bash
|
||||
# Simple commit
|
||||
git commit -m "feat: add user authentication"
|
||||
|
||||
# Multi-line commit (macOS/Linux)
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat: add user authentication
|
||||
|
||||
- Add OAuth2 support
|
||||
- Implement JWT tokens
|
||||
- Add login/logout endpoints
|
||||
EOF
|
||||
)"
|
||||
|
||||
# Multi-line commit (Windows)
|
||||
git commit -m "feat: add user authentication" \
|
||||
-m "" \
|
||||
-m "- Add OAuth2 support" \
|
||||
-m "- Implement JWT tokens" \
|
||||
-m "- Add login/logout endpoints"
|
||||
|
||||
# Commit with automatic staging
|
||||
git commit -am "fix: resolve issue"
|
||||
|
||||
# Amend last commit (before push only!)
|
||||
git commit --amend -m "new message"
|
||||
```
|
||||
|
||||
## Tag Management
|
||||
|
||||
### Create Tags
|
||||
|
||||
```bash
|
||||
# Create annotated tag
|
||||
git tag -a "1.2.0" -m "feat: add new feature"
|
||||
|
||||
# Create lightweight tag
|
||||
git tag "1.2.0"
|
||||
|
||||
# Create tag with multi-line message
|
||||
git tag -a "1.2.1" \
|
||||
-m "fix: resolve connection issue" \
|
||||
-m "" \
|
||||
-m "- Increase timeout to 30s" \
|
||||
-m "- Add retry mechanism"
|
||||
|
||||
# Create tag for specific commit
|
||||
git tag -a "1.2.0" <commit-hash> -m "message"
|
||||
|
||||
# Monorepo tag
|
||||
git tag -a "ios-1.2.0" -m "feat(ios): add feature"
|
||||
```
|
||||
|
||||
### List Tags
|
||||
|
||||
```bash
|
||||
# List all tags
|
||||
git tag
|
||||
|
||||
# List tags with pattern
|
||||
git tag -l "v1.*"
|
||||
|
||||
# List recent tags (sorted)
|
||||
git tag --list | sort -V | tail -5
|
||||
|
||||
# Show tag details
|
||||
git show <tag-name>
|
||||
```
|
||||
|
||||
### Push Tags
|
||||
|
||||
```bash
|
||||
# Push single tag
|
||||
git push origin <tag-name>
|
||||
|
||||
# Push all tags
|
||||
git push --tags
|
||||
# or
|
||||
git push origin --tags
|
||||
|
||||
# Push commit and tag together
|
||||
git push origin main && git push origin 1.2.0
|
||||
```
|
||||
|
||||
### Delete Tags
|
||||
|
||||
```bash
|
||||
# Delete local tag
|
||||
git tag -d <tag-name>
|
||||
|
||||
# Delete remote tag
|
||||
git push origin --delete <tag-name>
|
||||
# or
|
||||
git push origin :refs/tags/<tag-name>
|
||||
|
||||
# Delete multiple tags
|
||||
git tag -d tag1 tag2 tag3
|
||||
```
|
||||
|
||||
## Branch Operations
|
||||
|
||||
### View Branches
|
||||
|
||||
```bash
|
||||
# Show current branch
|
||||
git branch --show-current
|
||||
|
||||
# List local branches
|
||||
git branch
|
||||
|
||||
# List all branches (local + remote)
|
||||
git branch -a
|
||||
|
||||
# List remote branches only
|
||||
git branch -r
|
||||
|
||||
# Show branch with last commit
|
||||
git branch -v
|
||||
```
|
||||
|
||||
### Create and Switch Branches
|
||||
|
||||
```bash
|
||||
# Create new branch
|
||||
git branch <branch-name>
|
||||
|
||||
# Create and switch to new branch (old way)
|
||||
git checkout -b <branch-name>
|
||||
|
||||
# Create and switch to new branch (modern)
|
||||
git switch -c <branch-name>
|
||||
|
||||
# Switch to existing branch (old way)
|
||||
git checkout <branch-name>
|
||||
|
||||
# Switch to existing branch (modern)
|
||||
git switch <branch-name>
|
||||
|
||||
# Switch to previous branch
|
||||
git switch -
|
||||
```
|
||||
|
||||
### Delete Branches
|
||||
|
||||
```bash
|
||||
# Delete local branch (safe)
|
||||
git branch -d <branch-name>
|
||||
|
||||
# Delete local branch (force)
|
||||
git branch -D <branch-name>
|
||||
|
||||
# Delete remote branch
|
||||
git push origin --delete <branch-name>
|
||||
# or
|
||||
git push origin :<branch-name>
|
||||
```
|
||||
|
||||
## Pushing and Pulling
|
||||
|
||||
### Push Changes
|
||||
|
||||
```bash
|
||||
# Push current branch
|
||||
git push
|
||||
|
||||
# Push to specific remote and branch
|
||||
git push origin main
|
||||
|
||||
# Push current branch to remote
|
||||
git push origin $(git branch --show-current)
|
||||
|
||||
# Push with upstream tracking
|
||||
git push -u origin <branch-name>
|
||||
|
||||
# Push all branches
|
||||
git push --all
|
||||
|
||||
# Push all tags
|
||||
git push --tags
|
||||
|
||||
# Force push (dangerous!)
|
||||
git push --force
|
||||
# Better: force push with lease
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
### Pull Changes
|
||||
|
||||
```bash
|
||||
# Pull from tracked remote
|
||||
git pull
|
||||
|
||||
# Pull from specific remote and branch
|
||||
git pull origin main
|
||||
|
||||
# Pull with rebase
|
||||
git pull --rebase
|
||||
|
||||
# Pull and prune deleted remote branches
|
||||
git pull --prune
|
||||
```
|
||||
|
||||
### Fetch Changes
|
||||
|
||||
```bash
|
||||
# Fetch from all remotes
|
||||
git fetch
|
||||
|
||||
# Fetch from specific remote
|
||||
git fetch origin
|
||||
|
||||
# Fetch and prune deleted remote branches
|
||||
git fetch --prune
|
||||
|
||||
# Fetch all branches and tags
|
||||
git fetch --all --tags
|
||||
```
|
||||
|
||||
## History and Logs
|
||||
|
||||
### View Commit History
|
||||
|
||||
```bash
|
||||
# View recent commits
|
||||
git log
|
||||
|
||||
# View compact history
|
||||
git log --oneline
|
||||
|
||||
# View recent 10 commits
|
||||
git log --oneline -10
|
||||
|
||||
# View history with graph
|
||||
git log --graph --oneline --all
|
||||
|
||||
# View history with stats
|
||||
git log --stat
|
||||
|
||||
# View history with patches
|
||||
git log -p
|
||||
```
|
||||
|
||||
### Search History
|
||||
|
||||
```bash
|
||||
# Search commits by message
|
||||
git log --grep="feature"
|
||||
|
||||
# Search by author
|
||||
git log --author="John"
|
||||
|
||||
# Search by date
|
||||
git log --since="2024-01-01"
|
||||
git log --after="2 weeks ago"
|
||||
git log --before="yesterday"
|
||||
|
||||
# Search by file
|
||||
git log -- <file-path>
|
||||
|
||||
# Search code changes
|
||||
git log -S "function_name"
|
||||
```
|
||||
|
||||
### View Commit Details
|
||||
|
||||
```bash
|
||||
# Show specific commit
|
||||
git show <commit-hash>
|
||||
|
||||
# Show specific tag
|
||||
git show <tag-name>
|
||||
|
||||
# Show HEAD commit
|
||||
git show HEAD
|
||||
|
||||
# Show previous commit
|
||||
git show HEAD~1
|
||||
git show HEAD^
|
||||
```
|
||||
|
||||
## Undoing Changes
|
||||
|
||||
### Discard Changes
|
||||
|
||||
```bash
|
||||
# Discard unstaged changes in file
|
||||
git checkout -- <file-path>
|
||||
# or (modern)
|
||||
git restore <file-path>
|
||||
|
||||
# Discard all unstaged changes
|
||||
git checkout -- .
|
||||
# or (modern)
|
||||
git restore .
|
||||
|
||||
# Unstage file (keep changes)
|
||||
git reset HEAD <file-path>
|
||||
# or (modern)
|
||||
git restore --staged <file-path>
|
||||
|
||||
# Unstage all files
|
||||
git reset HEAD
|
||||
# or (modern)
|
||||
git restore --staged .
|
||||
```
|
||||
|
||||
### Reset Commits
|
||||
|
||||
```bash
|
||||
# Undo last commit, keep changes staged
|
||||
git reset --soft HEAD~1
|
||||
|
||||
# Undo last commit, keep changes unstaged
|
||||
git reset HEAD~1
|
||||
# or
|
||||
git reset --mixed HEAD~1
|
||||
|
||||
# Undo last commit, discard changes (dangerous!)
|
||||
git reset --hard HEAD~1
|
||||
|
||||
# Reset to specific commit
|
||||
git reset --hard <commit-hash>
|
||||
```
|
||||
|
||||
### Revert Commits
|
||||
|
||||
```bash
|
||||
# Create new commit that undoes a commit
|
||||
git revert <commit-hash>
|
||||
|
||||
# Revert without committing
|
||||
git revert -n <commit-hash>
|
||||
|
||||
# Revert multiple commits
|
||||
git revert <commit1>..<commit2>
|
||||
```
|
||||
|
||||
## Stash Operations
|
||||
|
||||
### Save Changes
|
||||
|
||||
```bash
|
||||
# Stash current changes
|
||||
git stash
|
||||
|
||||
# Stash with message
|
||||
git stash save "work in progress"
|
||||
|
||||
# Stash including untracked files
|
||||
git stash -u
|
||||
|
||||
# Stash including untracked and ignored files
|
||||
git stash -a
|
||||
```
|
||||
|
||||
### Apply Stash
|
||||
|
||||
```bash
|
||||
# Apply most recent stash
|
||||
git stash apply
|
||||
|
||||
# Apply and remove from stash list
|
||||
git stash pop
|
||||
|
||||
# Apply specific stash
|
||||
git stash apply stash@{2}
|
||||
```
|
||||
|
||||
### Manage Stash
|
||||
|
||||
```bash
|
||||
# List all stashes
|
||||
git stash list
|
||||
|
||||
# Show stash changes
|
||||
git stash show
|
||||
git stash show -p
|
||||
|
||||
# Drop specific stash
|
||||
git stash drop stash@{1}
|
||||
|
||||
# Clear all stashes
|
||||
git stash clear
|
||||
```
|
||||
|
||||
## Remote Operations
|
||||
|
||||
### View Remotes
|
||||
|
||||
```bash
|
||||
# List remotes
|
||||
git remote
|
||||
|
||||
# List remotes with URLs
|
||||
git remote -v
|
||||
|
||||
# Show remote details
|
||||
git remote show origin
|
||||
```
|
||||
|
||||
### Manage Remotes
|
||||
|
||||
```bash
|
||||
# Add remote
|
||||
git remote add <name> <url>
|
||||
|
||||
# Remove remote
|
||||
git remote remove <name>
|
||||
|
||||
# Rename remote
|
||||
git remote rename <old-name> <new-name>
|
||||
|
||||
# Change remote URL
|
||||
git remote set-url <name> <new-url>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### View Configuration
|
||||
|
||||
```bash
|
||||
# View all config
|
||||
git config --list
|
||||
|
||||
# View global config
|
||||
git config --global --list
|
||||
|
||||
# View local config
|
||||
git config --local --list
|
||||
|
||||
# View specific config
|
||||
git config user.name
|
||||
git config user.email
|
||||
```
|
||||
|
||||
### Set Configuration
|
||||
|
||||
```bash
|
||||
# Set user name
|
||||
git config --global user.name "Your Name"
|
||||
|
||||
# Set user email
|
||||
git config --global user.email "your.email@example.com"
|
||||
|
||||
# Set default branch name
|
||||
git config --global init.defaultBranch main
|
||||
|
||||
# Set default editor
|
||||
git config --global core.editor "code --wait"
|
||||
|
||||
# Set credential helper
|
||||
git config --global credential.helper store
|
||||
```
|
||||
|
||||
## Workflow Examples
|
||||
|
||||
### Standard Commit and Tag Workflow
|
||||
|
||||
```bash
|
||||
# 1. Check status
|
||||
git status
|
||||
git diff --cached --name-only
|
||||
|
||||
# 2. Stage changes
|
||||
git add .
|
||||
|
||||
# 3. Commit
|
||||
git commit -m "feat: add user authentication"
|
||||
|
||||
# 4. Create tag
|
||||
git tag -a "1.2.0" -m "feat: add user authentication"
|
||||
|
||||
# 5. Push commit and tag
|
||||
git push origin main
|
||||
git push origin 1.2.0
|
||||
```
|
||||
|
||||
### Complete Staging to Push Workflow
|
||||
|
||||
```bash
|
||||
# Check what files changed
|
||||
git status
|
||||
|
||||
# View changes
|
||||
git diff
|
||||
|
||||
# Stage specific files
|
||||
git add src/auth.js src/api.js
|
||||
|
||||
# Verify staging
|
||||
git diff --cached --name-only
|
||||
|
||||
# Commit with message
|
||||
git commit -m "feat: implement OAuth2 authentication"
|
||||
|
||||
# Push to remote
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Push All Tags Workflow
|
||||
|
||||
```bash
|
||||
# List local tags
|
||||
git tag
|
||||
|
||||
# View recent tags
|
||||
git tag --list | sort -V | tail -5
|
||||
|
||||
# Push all tags to remote
|
||||
git push --tags
|
||||
|
||||
# Verify tags on remote
|
||||
git ls-remote --tags origin
|
||||
```
|
||||
|
||||
### Quick Status Check
|
||||
|
||||
```bash
|
||||
# Full status
|
||||
git status
|
||||
|
||||
# Changed files only
|
||||
git diff --name-only
|
||||
git diff --cached --name-only
|
||||
|
||||
# Recent commits and tags
|
||||
git log --oneline -5
|
||||
git tag --list | sort -V | tail -5
|
||||
|
||||
# Current branch
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
## Tips and Tricks
|
||||
|
||||
### Aliases
|
||||
|
||||
Add to `~/.gitconfig`:
|
||||
|
||||
```ini
|
||||
[alias]
|
||||
st = status
|
||||
co = checkout
|
||||
br = branch
|
||||
ci = commit
|
||||
unstage = restore --staged
|
||||
last = log -1 HEAD
|
||||
lg = log --graph --oneline --all
|
||||
tags = tag -l --sort=-v:refname
|
||||
```
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
git st
|
||||
git co main
|
||||
git lg
|
||||
```
|
||||
|
||||
### Useful One-Liners
|
||||
|
||||
```bash
|
||||
# Delete all merged branches
|
||||
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
|
||||
|
||||
# View file in specific commit
|
||||
git show <commit>:<file-path>
|
||||
|
||||
# Count commits by author
|
||||
git shortlog -sn
|
||||
|
||||
# Find when a line was changed
|
||||
git blame <file-path>
|
||||
|
||||
# Show what changed in each commit for a file
|
||||
git log -p <file-path>
|
||||
|
||||
# List files in a commit
|
||||
git diff-tree --no-commit-id --name-only -r <commit>
|
||||
```
|
||||
209
skill/git/ssh-keychain.md
Normal file
209
skill/git/ssh-keychain.md
Normal file
@@ -0,0 +1,209 @@
|
||||
---
|
||||
name: ssh-keychain
|
||||
description: SSH key management with macOS Keychain for password-protected keys
|
||||
---
|
||||
|
||||
# SSH 密钥与 macOS Keychain 管理
|
||||
|
||||
处理带密码的 SSH 密钥,配置自动解锁避免重复输入密码。
|
||||
|
||||
## 问题场景
|
||||
|
||||
生成带密码的 SSH 密钥后,每次使用都需要输入密码:
|
||||
```bash
|
||||
git pull
|
||||
# Enter passphrase for /Users/xxx/.ssh/id_xxx:
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 生成带密码的 SSH 密钥
|
||||
|
||||
```bash
|
||||
# 生成密钥(推荐使用 ed25519)
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/id_custom -N "your-passphrase"
|
||||
|
||||
# 或使用随机密码
|
||||
PASSPHRASE=$(openssl rand -base64 32)
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/id_custom -N "$PASSPHRASE"
|
||||
```
|
||||
|
||||
### 2. 配置 SSH 使用 Keychain(关键步骤)
|
||||
|
||||
编辑 `~/.ssh/config`:
|
||||
|
||||
```ssh-config
|
||||
Host gitea.example.com
|
||||
HostName gitea.example.com
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_custom
|
||||
IdentitiesOnly yes
|
||||
AddKeysToAgent yes
|
||||
UseKeychain yes
|
||||
```
|
||||
|
||||
**重要配置项:**
|
||||
- `AddKeysToAgent yes` - 自动添加到 ssh-agent
|
||||
- `UseKeychain yes` - 使用 macOS Keychain 存储密码
|
||||
- **不要**使用 `IdentityAgent none`(会禁用 Keychain)
|
||||
|
||||
### 3. 添加密钥到 ssh-agent 并保存到 Keychain
|
||||
|
||||
```bash
|
||||
# 方法 1:使用 --apple-use-keychain (macOS 12+)
|
||||
ssh-add --apple-use-keychain ~/.ssh/id_custom
|
||||
|
||||
# 方法 2:使用 -K 选项 (macOS 11 及更早)
|
||||
ssh-add -K ~/.ssh/id_custom
|
||||
```
|
||||
|
||||
输入密码后,系统会保存到 Keychain,以后自动解锁。
|
||||
|
||||
### 4. 验证配置
|
||||
|
||||
```bash
|
||||
# 检查已加载的密钥
|
||||
ssh-add -l
|
||||
|
||||
# 测试 SSH 连接
|
||||
ssh -T git@gitea.example.com
|
||||
```
|
||||
|
||||
如果显示 `Hi there, xxx! You've successfully authenticated` 且**没有提示输入密码**,则配置成功。
|
||||
|
||||
## 完整工作流程示例
|
||||
|
||||
### 场景:配置 Gitea SSH 访问
|
||||
|
||||
```bash
|
||||
# 1. 生成带密码的密钥
|
||||
PASSPHRASE="bkt/52MFsLVSRSHvIXv2WTCKEUaPhD0btDghUY6RnQI="
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/id_gitea_new -N "$PASSPHRASE"
|
||||
|
||||
# 2. 配置 SSH
|
||||
# 编辑 ~/.ssh/config,添加:
|
||||
cat >> ~/.ssh/config << 'EOF'
|
||||
Host gitea.refining.dev
|
||||
HostName gitea.refining.dev
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_gitea_new
|
||||
IdentitiesOnly yes
|
||||
AddKeysToAgent yes
|
||||
UseKeychain yes
|
||||
EOF
|
||||
|
||||
# 3. 添加到 Keychain
|
||||
ssh-add --apple-use-keychain ~/.ssh/id_gitea_new
|
||||
# 输入密码: bkt/52MFsLVSRSHvIXv2WTCKEUaPhD0btDghUY6RnQI=
|
||||
|
||||
# 4. 验证
|
||||
ssh -T git@gitea.refining.dev
|
||||
|
||||
# 5. 后续使用 git 无需输入密码
|
||||
git pull
|
||||
git push
|
||||
```
|
||||
|
||||
## 常见错误与解决
|
||||
|
||||
### 错误 1:仍然提示输入密码
|
||||
|
||||
**原因:** `~/.ssh/config` 中配置了 `IdentityAgent none`
|
||||
|
||||
**解决:** 移除 `IdentityAgent none`,添加 `UseKeychain yes`
|
||||
|
||||
```ssh-config
|
||||
# ❌ 错误配置
|
||||
Host gitea.example.com
|
||||
IdentityFile ~/.ssh/id_custom
|
||||
IdentityAgent none # 这会禁用 Keychain
|
||||
|
||||
# ✅ 正确配置
|
||||
Host gitea.example.com
|
||||
IdentityFile ~/.ssh/id_custom
|
||||
AddKeysToAgent yes
|
||||
UseKeychain yes
|
||||
```
|
||||
|
||||
### 错误 2:1Password SSH agent 冲突
|
||||
|
||||
如果系统使用 1Password 的 SSH agent(`IdentityAgent "~/Library/Group Containers/.../agent.sock"`):
|
||||
|
||||
```ssh-config
|
||||
Host *
|
||||
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
|
||||
|
||||
Host gitea.example.com
|
||||
HostName gitea.example.com
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_custom
|
||||
IdentitiesOnly yes
|
||||
AddKeysToAgent yes
|
||||
UseKeychain yes
|
||||
# 不使用 1Password agent,直接使用系统 Keychain
|
||||
```
|
||||
|
||||
### 错误 3:ssh-add 命令不存在
|
||||
|
||||
某些 macOS 版本可能不支持 `--apple-use-keychain`:
|
||||
|
||||
```bash
|
||||
# 创建或编辑 ~/.ssh/config,添加全局配置
|
||||
Host *
|
||||
UseKeychain yes
|
||||
AddKeysToAgent yes
|
||||
|
||||
# 然后直接使用
|
||||
ssh-add ~/.ssh/id_custom
|
||||
```
|
||||
|
||||
## 密钥管理最佳实践
|
||||
|
||||
### 文件保存位置
|
||||
|
||||
将密钥备份到安全位置(如 iCloud):
|
||||
|
||||
```bash
|
||||
# 复制到 iCloud Key 文件夹
|
||||
KEY_FOLDER="$HOME/Library/Mobile Documents/com~apple~CloudDocs/key"
|
||||
cp ~/.ssh/id_custom "$KEY_FOLDER/id_custom_$(date +%Y%m%d)"
|
||||
cp ~/.ssh/id_custom.pub "$KEY_FOLDER/id_custom_$(date +%Y%m%d).pub"
|
||||
|
||||
# 创建密码说明文件
|
||||
cat > "$KEY_FOLDER/id_custom_$(date +%Y%m%d)_info.txt" << EOF
|
||||
SSH Key: id_custom
|
||||
Generated: $(date)
|
||||
Passphrase: $PASSPHRASE
|
||||
Host: gitea.example.com
|
||||
EOF
|
||||
```
|
||||
|
||||
### 定期检查
|
||||
|
||||
```bash
|
||||
# 列出所有已加载的密钥
|
||||
ssh-add -l
|
||||
|
||||
# 检查 SSH 配置
|
||||
ssh -G gitea.example.com
|
||||
|
||||
# 测试连接
|
||||
ssh -vT git@gitea.example.com
|
||||
```
|
||||
|
||||
### 安全建议
|
||||
|
||||
1. **始终使用带密码的密钥** - 防止私钥泄露后被直接使用
|
||||
2. **不要将私钥提交到 Git** - 添加到 `.gitignore`
|
||||
3. **定期轮换密钥** - 建议每 6-12 个月
|
||||
4. **为不同服务使用不同密钥** - 隔离风险
|
||||
|
||||
## 快速参考
|
||||
|
||||
| 命令 | 用途 |
|
||||
|------|------|
|
||||
| `ssh-add --apple-use-keychain ~/.ssh/id_custom` | 添加密钥到 Keychain |
|
||||
| `ssh-add -l` | 列出已加载的密钥 |
|
||||
| `ssh-add -D` | 删除所有已加载的密钥 |
|
||||
| `ssh -T git@host` | 测试 SSH 连接 |
|
||||
| `ssh -G host` | 查看 SSH 配置 |
|
||||
@@ -7,15 +7,43 @@ description: Comprehensive Gitea management tool for creating runners, workflows
|
||||
|
||||
完整的 Gitea 管理工具,提供 Runner、Workflow、仓库的创建和管理功能。
|
||||
|
||||
## 最新改进 (2026-01-23)
|
||||
|
||||
### 仓库创建功能增强(简洁高效版)
|
||||
1. **智能解析**:自动识别 `组织/仓库` 格式,优先使用指定组织而非默认组织
|
||||
2. **简化验证**:默认假设组织存在,API创建失败时清晰提示如何创建组织
|
||||
3. **默认私有**:除非明确指定,所有仓库默认创建为私有
|
||||
4. **Git集成**:自动检查当前目录是否为Git仓库,提供一键初始化、提交、推送
|
||||
5. **错误处理**:详细的Token验证、权限检查,API错误时给出具体解决方案
|
||||
6. **工作目录澄清**:仓库操作可在任何目录执行,配置操作在 `~/.config/gitea/`
|
||||
7. **流程优化**:减少不必要的预先验证,API失败时再提示,更简洁高效
|
||||
|
||||
### 使用示例
|
||||
```bash
|
||||
# 智能解析组织/仓库格式
|
||||
/gitea-create-repo shigongcao/shigongcao
|
||||
|
||||
# 创建公开仓库
|
||||
/gitea-create-repo org/project public
|
||||
|
||||
# 自动初始化并推送
|
||||
/gitea-create-repo org/project --init
|
||||
```
|
||||
|
||||
## 工作目录
|
||||
|
||||
**重要:该技能和所有相关命令的工作目录统一为:**
|
||||
**重要:Gitea 配置和 Runner 相关操作的工作目录为 `~/.config/gitea/`,但仓库操作可以在任何目录执行。**
|
||||
|
||||
### macOS / Linux
|
||||
### 配置和 Runner 目录
|
||||
```bash
|
||||
~/.config/gitea/
|
||||
```
|
||||
|
||||
### 仓库操作目录
|
||||
可以在任何项目目录执行,技能会自动:
|
||||
1. 从 `~/.config/gitea/config.env` 读取配置
|
||||
2. 在当前目录创建仓库、初始化 Git 等
|
||||
|
||||
### Windows
|
||||
```powershell
|
||||
# PowerShell
|
||||
@@ -28,7 +56,9 @@ $env:USERPROFILE\.config\gitea\
|
||||
C:\Users\YourUsername\.config\gitea\
|
||||
```
|
||||
|
||||
所有配置文件、Runner 目录、日志文件都存储在此目录下。请确保该目录具有适当的读写权限。
|
||||
**重要区分**:
|
||||
- **配置/Runner 操作**:在 `~/.config/gitea/` 目录执行
|
||||
- **仓库操作**:可在任何项目目录执行(自动加载配置)
|
||||
|
||||
**目录结构(所有平台通用):**
|
||||
```
|
||||
@@ -40,9 +70,9 @@ C:\Users\YourUsername\.config\gitea\
|
||||
```
|
||||
|
||||
**平台兼容性:**
|
||||
- **macOS**: `~/.config/gitea/`(完全支持)
|
||||
- **Linux**: `~/.config/gitea/`(完全支持)
|
||||
- **Windows**: `%USERPROFILE%\.config\gitea\`(Act Runner 支持,但该技能的命令和脚本需要适配)
|
||||
- **macOS**: `~/.config/gitea/`(配置目录),任意目录(仓库操作)
|
||||
- **Linux**: `~/.config/gitea/`(配置目录),任意目录(仓库操作)
|
||||
- **Windows**: `%USERPROFILE%\.config\gitea\`(配置目录),任意目录(仓库操作)
|
||||
|
||||
**Windows 用户注意事项:**
|
||||
- Gitea Act Runner 官方支持 Windows 平台(包括 Host 模式)
|
||||
@@ -57,7 +87,9 @@ C:\Users\YourUsername\.config\gitea\
|
||||
| 功能模块 | 文档 | 说明 |
|
||||
|---------|------|------|
|
||||
| 环境配置 | [setup-guide.md](./setup-guide.md) | 首次使用引导,配置 Gitea URL 和 Token |
|
||||
| SSH 密钥管理 | [ssh-key-management.md](./ssh-key-management.md) | 创建、部署 SSH 密钥,配置本地客户端 |
|
||||
| Runner 管理 | [runner-management.md](./runner-management.md) | 创建、注册、管理 Gitea Act Runner |
|
||||
| 自动创建脚本 | [create-runner.md](./create-runner.md) | 包含完整的 Runner 创建 Bash 脚本 |
|
||||
| Workflow 生成 | [workflow-generator.md](./workflow-generator.md) | 根据项目类型生成 CI/CD workflow |
|
||||
| 仓库操作 | [repository-operations.md](./repository-operations.md) | 创建和配置 Gitea 仓库 |
|
||||
| API 参考 | [api-reference.md](./api-reference.md) | Gitea API 常用接口 |
|
||||
@@ -71,6 +103,7 @@ C:\Users\YourUsername\.config\gitea\
|
||||
- "生成 workflow"、"CI/CD"
|
||||
- "创建仓库"、"gitea 仓库"
|
||||
- "gitea 配置"、"gitea token"
|
||||
- "ssh key"、"ssh密钥"、"gitea ssh"、"部署密钥"
|
||||
|
||||
## 首次使用
|
||||
|
||||
@@ -99,6 +132,7 @@ C:\Users\YourUsername\.config\gitea\
|
||||
| `/gitea-config` | 查看当前 Gitea 配置和 Runner 状态 |
|
||||
| `/gitea-reset` | 重置 Gitea 配置(交互式向导) |
|
||||
| `/gitea-switch-org` | 切换默认组织 |
|
||||
| `/gitea-setup-ssh` | 创建 SSH 密钥并部署到 Gitea 服务器 |
|
||||
| `/gitea-create-runner` | 创建并启动新 Runner(默认 host 模式) |
|
||||
| `/gitea-list-runners` | 列出所有 Runner 及其状态 |
|
||||
| `/gitea-delete-runner` | 删除指定 Runner |
|
||||
@@ -182,12 +216,30 @@ AI: 检测到 Go 项目,服务目录: ./backend
|
||||
[自动生成 .gitea/workflows/backend.yml]
|
||||
```
|
||||
|
||||
### 4. 创建仓库
|
||||
### 4. 创建仓库(智能解析,默认私有)
|
||||
|
||||
**智能解析特性**:
|
||||
- 自动识别 `组织/仓库` 格式,优先使用指定组织
|
||||
- 默认创建私有仓库(除非明确指定公开)
|
||||
- 支持自动初始化 Git 仓库并推送代码
|
||||
|
||||
**示例**:
|
||||
```
|
||||
用户: /gitea-create-repo my-project
|
||||
AI: [使用配置的 Gitea URL 和默认组织创建仓库]
|
||||
✓ 仓库创建成功: ai/my-project
|
||||
用户: /gitea-create-repo shigongcao/shigongcao
|
||||
AI: [智能解析为 shigongcao 组织下的 shigongcao 仓库]
|
||||
✓ 仓库创建成功: shigongcao/shigongcao (私有)
|
||||
✓ 组织验证通过
|
||||
✓ 可选的 Git 初始化流程...
|
||||
|
||||
用户: /gitea-create-repo my-project public
|
||||
AI: [使用默认组织创建公开仓库]
|
||||
✓ 仓库创建成功: ai/my-project (公开)
|
||||
|
||||
用户: /gitea-create-repo org/project --init
|
||||
AI: [创建仓库并自动初始化当前目录的 Git 仓库]
|
||||
✓ 仓库创建成功: org/project
|
||||
✓ Git 初始化完成
|
||||
✓ 代码已推送到远程仓库
|
||||
```
|
||||
|
||||
## 配置管理
|
||||
@@ -375,10 +427,17 @@ AI 会自动:
|
||||
|
||||
## 版本
|
||||
|
||||
- **Skill Version**: 1.0
|
||||
- **Last Updated**: 2026-01-12
|
||||
- **整合内容**: gitea-runner + gitea-workflow
|
||||
- **新增功能**: 统一配置管理、Runner CRUD、智能 labels 检测
|
||||
- **Skill Version**: 1.2
|
||||
- **Last Updated**: 2026-01-28
|
||||
- **整合内容**: gitea-runner + gitea-workflow + 增强仓库管理 + SSH 密钥管理
|
||||
- **主要改进**:
|
||||
- 仓库创建智能解析(优先使用指定组织)
|
||||
- **简化验证**:默认假设组织存在,API失败时提示创建组织
|
||||
- 默认私有仓库策略(除非明确指定公开)
|
||||
- **完整 Git 集成**:自动检查Git状态,提供一键初始化、提交、推送
|
||||
- **简洁高效**:减少预先验证,API失败时给出具体解决方案
|
||||
- 工作目录概念澄清(配置 vs 仓库操作)
|
||||
- **SSH 密钥管理**:完整的密钥创建、部署和跨设备使用指南
|
||||
|
||||
## 相关资源
|
||||
|
||||
|
||||
1118
skill/gitea/create-runner.md
Normal file
1118
skill/gitea/create-runner.md
Normal file
File diff suppressed because it is too large
Load Diff
303
skill/gitea/delete-runner.md
Normal file
303
skill/gitea/delete-runner.md
Normal file
@@ -0,0 +1,303 @@
|
||||
---
|
||||
description: 交互式批量删除 Gitea Runners 脚本
|
||||
agent: general
|
||||
---
|
||||
|
||||
# Delete Runner Script
|
||||
|
||||
本文档包含用于交互式批量删除 Gitea Actions Runner 的完整 Bash 脚本。
|
||||
|
||||
## 功能特点
|
||||
- **多选支持**:支持输入多个序号(如 `1,3` 或 `1 3`)或 `all` 进行批量删除。
|
||||
- **双重清理**:同时从 Gitea 服务器注销 Runner 和删除本地配置/容器。
|
||||
- **智能识别**:自动关联远程 Runner 状态与本地 Runner 目录。
|
||||
- **安全检查**:删除前强制二次确认,防止误删。
|
||||
|
||||
## 脚本文件
|
||||
|
||||
你可以将以下内容保存为 `delete_runner.sh` 并赋予执行权限 (`chmod +x delete_runner.sh`)。
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Gitea Runner Deletion Script
|
||||
# Generated by OpenCode Skill
|
||||
|
||||
set -e
|
||||
|
||||
# ==========================================
|
||||
# 1. Setup & Config
|
||||
# ==========================================
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Config
|
||||
CONFIG_FILE="$HOME/.config/gitea/config.env"
|
||||
RUNNERS_BASE_DIR="$HOME/.config/gitea/runners"
|
||||
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo -e "${RED}❌ 配置文件不存在: $CONFIG_FILE${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
|
||||
echo -e "${RED}❌ 配置无效: 缺少 URL 或 Token${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check requirements
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo -e "${RED}❌ 需要安装 jq 工具来解析 JSON${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在获取 Runner 列表..."
|
||||
|
||||
# ==========================================
|
||||
# 2. Data Collection
|
||||
# ==========================================
|
||||
|
||||
# Temporary files
|
||||
REMOTE_LIST=$(mktemp)
|
||||
LOCAL_MAP=$(mktemp)
|
||||
FINAL_LIST=$(mktemp)
|
||||
|
||||
# 2.1 Fetch Remote Runners (Try Admin first, then Org)
|
||||
# Note: Admin endpoint /api/v1/admin/actions/runners lists all runners
|
||||
HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REMOTE_LIST" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/actions/runners?page=1&limit=100")
|
||||
|
||||
if [ "$HTTP_CODE" != "200" ]; then
|
||||
# Fallback to Org level if defined
|
||||
if [ -n "$GITEA_DEFAULT_ORG" ]; then
|
||||
HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REMOTE_LIST" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/orgs/${GITEA_DEFAULT_ORG}/actions/runners?page=1&limit=100")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$HTTP_CODE" != "200" ]; then
|
||||
echo -e "${RED}❌ 无法获取 Runner 列表 (HTTP $HTTP_CODE)${NC}"
|
||||
cat "$REMOTE_LIST"
|
||||
rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2.2 Scan Local Directories to map UUID -> Path
|
||||
# We need to find which local directory corresponds to which runner ID/UUID
|
||||
echo "{}" > "$LOCAL_MAP"
|
||||
|
||||
if [ -d "$RUNNERS_BASE_DIR" ]; then
|
||||
for d in "$RUNNERS_BASE_DIR"/*; do
|
||||
if [ -d "$d" ]; then
|
||||
# Check Host mode .runner
|
||||
if [ -f "$d/.runner" ]; then
|
||||
uuid=$(jq -r '.uuid' "$d/.runner" 2>/dev/null)
|
||||
if [ -n "$uuid" ] && [ "$uuid" != "null" ]; then
|
||||
# Add to JSON map
|
||||
tmp=$(mktemp)
|
||||
jq --arg uuid "$uuid" --arg path "$d" '.[$uuid] = $path' "$LOCAL_MAP" > "$tmp" && mv "$tmp" "$LOCAL_MAP"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check Docker mode data/.runner
|
||||
if [ -f "$d/data/.runner" ]; then
|
||||
uuid=$(jq -r '.uuid' "$d/data/.runner" 2>/dev/null)
|
||||
if [ -n "$uuid" ] && [ "$uuid" != "null" ]; then
|
||||
tmp=$(mktemp)
|
||||
jq --arg uuid "$uuid" --arg path "$d" '.[$uuid] = $path' "$LOCAL_MAP" > "$tmp" && mv "$tmp" "$LOCAL_MAP"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 3. Display Interface
|
||||
# ==========================================
|
||||
|
||||
# Combine Remote and Local info
|
||||
# Output format: index | id | name | status | local_path
|
||||
jq -r --slurpfile local "$LOCAL_MAP" '
|
||||
.runners[] |
|
||||
[.id, .uuid, .name, .status, ($local[0][.uuid] // "")] |
|
||||
@tsv
|
||||
' "$REMOTE_LIST" > "$FINAL_LIST"
|
||||
|
||||
count=$(wc -l < "$FINAL_LIST" | tr -d ' ')
|
||||
|
||||
if [ "$count" -eq 0 ]; then
|
||||
echo "没有发现任何 Runners。"
|
||||
rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}Gitea Runners 列表 (共 $count 个)${NC}"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
printf "%-4s | %-8s | %-20s | %-10s | %-30s\n" "序号" "ID" "名称" "状态" "本地目录"
|
||||
echo "----------------------------------------------------------------------------"
|
||||
|
||||
i=1
|
||||
declare -a runner_ids
|
||||
declare -a runner_names
|
||||
declare -a runner_paths
|
||||
|
||||
while IFS=$'\t' read -r id uuid name status local_path; do
|
||||
status_icon="🔴"
|
||||
if [ "$status" = "online" ] || [ "$status" = "idle" ] || [ "$status" = "active" ]; then
|
||||
status_icon="🟢"
|
||||
fi
|
||||
|
||||
local_mark=""
|
||||
if [ -n "$local_path" ]; then
|
||||
local_mark="$(basename "$local_path")"
|
||||
else
|
||||
local_mark="-"
|
||||
fi
|
||||
|
||||
printf "%-4d | %-8s | %-20s | %s %-8s | %-30s\n" "$i" "$id" "${name:0:20}" "$status_icon" "$status" "$local_mark"
|
||||
|
||||
runner_ids[$i]=$id
|
||||
runner_names[$i]=$name
|
||||
runner_paths[$i]=$local_path
|
||||
|
||||
i=$((i+1))
|
||||
done < "$FINAL_LIST"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# ==========================================
|
||||
# 4. User Selection
|
||||
# ==========================================
|
||||
|
||||
echo "请输入要删除的序号:"
|
||||
echo " - 单个: 1"
|
||||
echo " - 多选: 1,3,5 或 1 3 5"
|
||||
echo " - 全部: all"
|
||||
echo " - 退出: q"
|
||||
echo ""
|
||||
read -p "选择 > " selection
|
||||
|
||||
if [[ "$selection" =~ ^[qQ] ]]; then
|
||||
echo "已取消。"
|
||||
rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
target_indices=()
|
||||
|
||||
if [ "$selection" = "all" ]; then
|
||||
for ((j=1; j<=count; j++)); do
|
||||
target_indices+=($j)
|
||||
done
|
||||
else
|
||||
# Replace commas with spaces and iterate
|
||||
for idx in ${selection//,/ }; do
|
||||
# Validate number
|
||||
if [[ "$idx" =~ ^[0-9]+$ ]] && [ "$idx" -ge 1 ] && [ "$idx" -le "$count" ]; then
|
||||
target_indices+=($idx)
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 忽略无效序号: $idx${NC}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ ${#target_indices[@]} -eq 0 ]; then
|
||||
echo -e "${RED}未选择任何有效 Runner。${NC}"
|
||||
rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 5. Confirmation
|
||||
# ==========================================
|
||||
|
||||
echo ""
|
||||
echo -e "${RED}⚠️ 警告: 即将删除以下 ${#target_indices[@]} 个 Runner:${NC}"
|
||||
for idx in "${target_indices[@]}"; do
|
||||
echo " - [${runner_ids[$idx]}] ${runner_names[$idx]}"
|
||||
if [ -n "${runner_paths[$idx]}" ]; then
|
||||
echo " └─ 本地目录: ${runner_paths[$idx]}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "此操作将从服务器注销 Runner 并删除本地文件/容器。"
|
||||
read -p "确认删除? (输入 yes 继续): " confirm
|
||||
|
||||
if [ "$confirm" != "yes" ]; then
|
||||
echo "操作已取消。"
|
||||
rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 6. Execution
|
||||
# ==========================================
|
||||
|
||||
echo ""
|
||||
echo "开始执行删除..."
|
||||
|
||||
for idx in "${target_indices[@]}"; do
|
||||
r_id="${runner_ids[$idx]}"
|
||||
r_name="${runner_names[$idx]}"
|
||||
r_path="${runner_paths[$idx]}"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "正在处理: $r_name (ID: $r_id)"
|
||||
|
||||
# 6.1 Delete from Server
|
||||
echo -n " 1. 从服务器注销... "
|
||||
del_code=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/actions/runners/${r_id}")
|
||||
|
||||
if [ "$del_code" = "204" ] || [ "$del_code" = "404" ]; then
|
||||
echo -e "${GREEN}成功${NC}"
|
||||
else
|
||||
echo -e "${RED}失败 (HTTP $del_code)${NC}"
|
||||
# Continue cleanup anyway
|
||||
fi
|
||||
|
||||
# 6.2 Cleanup Local
|
||||
if [ -n "$r_path" ] && [ -d "$r_path" ]; then
|
||||
dir_name=$(basename "$r_path")
|
||||
|
||||
# Stop Docker container if name matches folder name (common convention)
|
||||
if docker ps -a --format '{{.Names}}' | grep -q "^${dir_name}$"; then
|
||||
echo -n " 2. 停止并删除 Docker 容器 ($dir_name)... "
|
||||
docker rm -f "$dir_name" >/dev/null 2>&1
|
||||
echo -e "${GREEN}完成${NC}"
|
||||
fi
|
||||
|
||||
# Stop Host process (if PID file exists)
|
||||
if [ -f "$r_path/pid" ]; then
|
||||
pid=$(cat "$r_path/pid")
|
||||
echo -n " 2. 停止本地进程 (PID: $pid)... "
|
||||
kill "$pid" >/dev/null 2>&1 || true
|
||||
echo -e "${GREEN}完成${NC}"
|
||||
fi
|
||||
|
||||
echo -n " 3. 删除本地目录... "
|
||||
rm -rf "$r_path"
|
||||
echo -e "${GREEN}完成${NC}"
|
||||
else
|
||||
echo " - 本地目录未找到或已清理"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo -e "${GREEN}✅ 批量删除操作完成${NC}"
|
||||
|
||||
# Cleanup temps
|
||||
rm "$REMOTE_LIST" "$LOCAL_MAP" "$FINAL_LIST"
|
||||
```
|
||||
@@ -11,6 +11,34 @@
|
||||
- 管理 Secrets 和 Variables
|
||||
- 设置 Webhooks
|
||||
|
||||
## 快速使用
|
||||
|
||||
### 核心原则(简洁高效)
|
||||
1. **智能解析**:自动识别 `组织/仓库` 格式,优先使用指定组织而非默认组织
|
||||
2. **默认私有**:除非明确指定,所有仓库默认创建为私有
|
||||
3. **简化验证**:默认假设组织存在,API创建失败时清晰提示解决方案
|
||||
4. **Git集成**:自动检查Git仓库状态,提供一键初始化、提交、推送完整流程
|
||||
5. **错误处理**:API失败时给出具体操作建议,而非预先复杂验证
|
||||
|
||||
### 常用命令(简洁高效)
|
||||
```bash
|
||||
# 智能解析组织/仓库格式(默认私有)
|
||||
/gitea-create-repo shigongcao/shigongcao
|
||||
|
||||
# 使用默认组织创建公开仓库
|
||||
/gitea-create-repo my-project public
|
||||
|
||||
# 自动检查Git状态,提供完整初始化流程
|
||||
/gitea-create-repo org/project
|
||||
|
||||
# 特性说明:
|
||||
# 1. 自动识别组织/仓库格式
|
||||
# 2. 默认创建私有仓库(除非指定public)
|
||||
# 3. 自动检查当前目录Git状态
|
||||
# 4. 提供一键初始化、提交、推送选项
|
||||
# 5. API失败时给出清晰解决方案(如组织不存在)
|
||||
```
|
||||
|
||||
## 创建仓库
|
||||
|
||||
### 使用命令创建
|
||||
@@ -65,24 +93,28 @@ fi
|
||||
source "$config_file"
|
||||
```
|
||||
|
||||
#### 步骤 2: 解析输入
|
||||
#### 步骤 2: 智能解析输入(简洁高效版)
|
||||
|
||||
```bash
|
||||
input="$1"
|
||||
|
||||
# 解析 owner/repo
|
||||
# 智能解析:优先使用用户指定的组织
|
||||
if [[ "$input" =~ / ]]; then
|
||||
owner=$(echo "$input" | cut -d'/' -f1)
|
||||
repo=$(echo "$input" | cut -d'/' -f2)
|
||||
echo "使用指定组织: $owner"
|
||||
echo "提示:假设组织存在,如不存在会在API创建时提示"
|
||||
else
|
||||
# 使用默认组织或当前用户
|
||||
# 未指定组织,使用默认组织或当前用户
|
||||
if [ -z "$GITEA_DEFAULT_ORG" ]; then
|
||||
# 获取当前用户
|
||||
echo "未指定组织,获取当前用户..."
|
||||
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 格式"
|
||||
echo "❌ 无法获取当前用户信息,请使用 组织/仓库 格式"
|
||||
echo "例如:/gitea-create-repo shigongcao/shigongcao"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -94,9 +126,21 @@ else
|
||||
repo="$input"
|
||||
fi
|
||||
|
||||
# 解析可见性
|
||||
# 解析可见性:默认私有仓库(除非明确指定公开)
|
||||
visibility="${2:-private}"
|
||||
if [[ "$visibility" != "private" && "$visibility" != "public" ]]; then
|
||||
echo "⚠️ 可见性参数无效,使用默认值: private"
|
||||
visibility="private"
|
||||
fi
|
||||
|
||||
private_bool=$([ "$visibility" = "private" ] && echo "true" || echo "false")
|
||||
echo "仓库可见性: $visibility"
|
||||
|
||||
# 提前检查当前目录是否是 Git 仓库(为后续步骤做准备)
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "⚠️ 当前目录不是 Git 仓库"
|
||||
echo "提示:创建远程仓库后可以初始化本地 Git 仓库并推送代码"
|
||||
fi
|
||||
```
|
||||
|
||||
#### 步骤 3: 验证仓库名
|
||||
@@ -109,12 +153,29 @@ if ! [[ "$repo" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
|
||||
fi
|
||||
```
|
||||
|
||||
#### 步骤 4: 调用 API 创建
|
||||
#### 步骤 4: 调用 API 创建(带详细错误处理)
|
||||
|
||||
```bash
|
||||
echo "正在创建仓库: $owner/$repo ($visibility)"
|
||||
|
||||
# 尝试组织仓库
|
||||
# 检查 Token 权限
|
||||
echo "检查 Token 权限..."
|
||||
user_info=$(curl -s -H "Authorization: token $GITEA_TOKEN" "${GITEA_URL}/api/v1/user")
|
||||
username=$(echo "$user_info" | jq -r '.login // empty')
|
||||
|
||||
if [ -z "$username" ] || [ "$username" = "null" ]; then
|
||||
echo "❌ Token 无效或权限不足"
|
||||
echo "请检查:"
|
||||
echo "1. Token 是否有效"
|
||||
echo "2. Token 是否有 'repo' 权限"
|
||||
echo "3. GITEA_URL 是否正确"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Token 有效,当前用户: $username"
|
||||
|
||||
# 尝试创建组织仓库
|
||||
echo "调用 Gitea API 创建仓库..."
|
||||
response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -122,42 +183,87 @@ response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
\"name\": \"${repo}\",
|
||||
\"private\": ${private_bool},
|
||||
\"auto_init\": false,
|
||||
\"default_branch\": \"main\"
|
||||
\"default_branch\": \"main\",
|
||||
\"description\": \"\"
|
||||
}" \
|
||||
"${GITEA_URL}/api/v1/orgs/${owner}/repos")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
# 如果 404,可能是用户而非组织
|
||||
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}
|
||||
}" \
|
||||
"${GITEA_URL}/api/v1/user/repos")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
fi
|
||||
|
||||
# 处理响应
|
||||
case "$http_code" in
|
||||
201)
|
||||
echo "✓ 仓库创建成功"
|
||||
;;
|
||||
400)
|
||||
error_msg=$(echo "$body" | jq -r '.message // "未知错误"')
|
||||
echo "❌ 请求参数错误: $error_msg"
|
||||
echo "请检查:"
|
||||
echo "1. 仓库名格式是否正确"
|
||||
echo "2. 是否缺少必要参数"
|
||||
exit 1
|
||||
;;
|
||||
403)
|
||||
echo "❌ 权限不足"
|
||||
echo "请检查:"
|
||||
echo "1. 是否有在组织 '$owner' 下创建仓库的权限"
|
||||
echo "2. 是否是组织成员"
|
||||
echo "3. Token 权限是否足够"
|
||||
exit 1
|
||||
;;
|
||||
404)
|
||||
# 组织不存在(API 返回 404)
|
||||
echo "❌ API 创建失败:组织 '$owner' 不存在"
|
||||
|
||||
# 检查是否为当前用户(可能用户输入的是自己的用户名)
|
||||
if [ "$owner" = "$username" ]; then
|
||||
echo "检测到 '$owner' 是当前用户,创建个人仓库..."
|
||||
|
||||
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')
|
||||
|
||||
if [ "$http_code" = "201" ]; then
|
||||
echo "✓ 个人仓库创建成功"
|
||||
else
|
||||
error_msg=$(echo "$body" | jq -r '.message // "未知错误"')
|
||||
echo "❌ 个人仓库创建失败 (HTTP $http_code): $error_msg"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "组织不存在,请先创建组织"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "您可以通过以下方式创建组织 '$owner':"
|
||||
echo "1. 访问 ${GITEA_URL}/org/create"
|
||||
echo "2. 使用 Gitea Web 界面创建组织"
|
||||
echo "3. 或者使用个人仓库格式: $username/$repo"
|
||||
echo ""
|
||||
echo "创建组织后,重新运行此命令创建仓库。"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
409)
|
||||
echo "❌ 仓库已存在"
|
||||
echo "❌ 仓库已存在: $owner/$repo"
|
||||
echo "请使用不同的仓库名或删除现有仓库"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "❌ 创建失败 (HTTP $http_code)"
|
||||
echo "$body" | jq -r '.message // empty'
|
||||
error_msg=$(echo "$body" | jq -r '.message // "未知错误"')
|
||||
echo "❌ 创建失败 (HTTP $http_code): $error_msg"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -183,45 +289,104 @@ echo " SSH URL: $ssh_url"
|
||||
echo ""
|
||||
```
|
||||
|
||||
#### 步骤 6: 添加 Git Remote
|
||||
#### 步骤 6: Git 仓库集成(简洁高效版)
|
||||
|
||||
```bash
|
||||
read -p "是否将此仓库添加为 Git remote? [Y/n] " add_remote
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Git 仓库集成"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
if [[ ! "$add_remote" =~ ^[Nn]$ ]]; then
|
||||
# 检查是否是 Git 仓库
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "当前目录不是 Git 仓库"
|
||||
read -p "是否初始化 Git 仓库? [Y/n] " init_git
|
||||
# 检查是否是 Git 仓库
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "当前目录不是 Git 仓库"
|
||||
read -p "是否初始化 Git 仓库并添加 remote? [Y/n] " init_git
|
||||
|
||||
if [[ ! "$init_git" =~ ^[Nn]$ ]]; then
|
||||
git init
|
||||
echo "✓ Git 仓库已初始化"
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$init_git" =~ ^[Nn]$ ]]; then
|
||||
echo "跳过 Git 初始化,仅创建远程仓库。"
|
||||
echo "您可以在需要时手动执行:"
|
||||
echo " git init"
|
||||
echo " git remote add origin \"$clone_url\""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 初始化 Git 仓库
|
||||
echo "正在初始化 Git 仓库..."
|
||||
git init
|
||||
echo "✓ Git 仓库已初始化"
|
||||
|
||||
# 检查 origin 是否已存在
|
||||
if git remote get-url origin >/dev/null 2>&1; then
|
||||
existing_url=$(git remote get-url origin)
|
||||
echo "⚠️ origin remote 已存在: $existing_url"
|
||||
read -p "是否覆盖? [y/N] " overwrite
|
||||
read -p "是否覆盖为新的仓库? [y/N] " overwrite
|
||||
|
||||
if [[ "$overwrite" =~ ^[Yy]$ ]]; then
|
||||
git remote set-url origin "$clone_url"
|
||||
echo "✓ origin remote 已更新"
|
||||
echo "✓ origin remote 已更新为: $clone_url"
|
||||
else
|
||||
echo "保持现有的 origin remote"
|
||||
fi
|
||||
else
|
||||
git remote add origin "$clone_url"
|
||||
echo "✓ origin remote 已添加"
|
||||
echo "✓ origin remote 已添加: $clone_url"
|
||||
fi
|
||||
|
||||
# 显示 remote 信息
|
||||
# 可选:添加文件、提交并推送
|
||||
echo ""
|
||||
echo "当前 remote:"
|
||||
git remote -v
|
||||
read -p "是否添加当前文件、提交并推送到远程仓库? [Y/n] " push_code
|
||||
|
||||
if [[ ! "$push_code" =~ ^[Nn]$ ]]; then
|
||||
echo "添加所有文件到暂存区..."
|
||||
git add .
|
||||
|
||||
echo "创建初始提交..."
|
||||
git commit -m "Initial commit" || {
|
||||
echo "⚠️ 提交失败(可能没有文件可提交)"
|
||||
echo "请手动添加文件后提交"
|
||||
}
|
||||
|
||||
echo "推送到远程仓库 (main 分支)..."
|
||||
git branch -M main 2>/dev/null
|
||||
git push -u origin main
|
||||
echo "✓ 代码已推送到远程仓库"
|
||||
else
|
||||
echo "跳过推送,您可以在需要时手动推送代码。"
|
||||
fi
|
||||
|
||||
else
|
||||
# 已经是 Git 仓库,询问是否添加/更新 remote
|
||||
echo "当前目录已是 Git 仓库"
|
||||
read -p "是否添加/更新 origin remote 为此仓库? [Y/n] " add_remote
|
||||
|
||||
if [[ ! "$add_remote" =~ ^[Nn]$ ]]; then
|
||||
# 检查 origin 是否已存在
|
||||
if git remote get-url origin >/dev/null 2>&1; then
|
||||
existing_url=$(git remote get-url origin)
|
||||
echo "⚠️ origin remote 已存在: $existing_url"
|
||||
read -p "是否覆盖? [y/N] " overwrite
|
||||
|
||||
if [[ "$overwrite" =~ ^[Yy]$ ]]; then
|
||||
git remote set-url origin "$clone_url"
|
||||
echo "✓ origin remote 已更新"
|
||||
else
|
||||
echo "保持现有的 origin remote"
|
||||
fi
|
||||
else
|
||||
git remote add origin "$clone_url"
|
||||
echo "✓ origin remote 已添加"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 显示当前状态
|
||||
echo ""
|
||||
echo "当前 Git 状态:"
|
||||
git status --short 2>/dev/null || echo "(非 Git 仓库)"
|
||||
echo ""
|
||||
echo "Remote 配置:"
|
||||
git remote -v 2>/dev/null || echo "(无 remote 配置)"
|
||||
```
|
||||
|
||||
## 仓库初始化
|
||||
@@ -689,5 +854,11 @@ curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
|
||||
## 版本
|
||||
|
||||
- **文档版本**: 1.0
|
||||
- **最后更新**: 2026-01-12
|
||||
- **文档版本**: 1.1
|
||||
- **最后更新**: 2026-01-23
|
||||
- **主要改进**:
|
||||
- 智能解析输入:优先使用指定组织而非默认组织
|
||||
- 组织存在性验证和清晰错误提示
|
||||
- 默认私有仓库策略(除非明确指定公开)
|
||||
- 增强的错误处理:Token验证、权限检查、详细错误消息
|
||||
- 完整的Git集成流程:可选自动初始化和推送
|
||||
|
||||
@@ -29,6 +29,7 @@ Gitea Act Runner 是 Gitea Actions 的 CI/CD 执行器,兼容 GitHub Actions w
|
||||
- **macOS ARM64**: 使用 **Host Mode** 以支持 Android SDK
|
||||
- **Windows**: 使用 **Host Mode**(需在 workflow 中指定 `shell: powershell`)
|
||||
- **Linux**: 两种模式均可,Docker Mode 隔离性更好
|
||||
- **Docker Mode**: 必须使用 `catthehacker/ubuntu:act-*` 镜像(内置 Docker CLI)
|
||||
|
||||
**Windows Host Mode 注意事项**:
|
||||
- Bash 默认不可用,需在 workflow 中指定 shell:
|
||||
@@ -267,6 +268,8 @@ act_runner --version
|
||||
7. 获取注册 token(优先全局)
|
||||
8. 注册并启动 runner
|
||||
|
||||
> **提示**:你可以从 [create-runner.md](./create-runner.md) 获取完整的 Bash 脚本。
|
||||
|
||||
### 详细创建流程
|
||||
|
||||
当运行 `/gitea-create-runner` 命令时,会执行以下步骤:
|
||||
@@ -575,9 +578,51 @@ labels:
|
||||
```yaml
|
||||
labels:
|
||||
- "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"
|
||||
- "ubuntu-22.04:docker://catthehacker/ubuntu:act-latest"
|
||||
- "ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04"
|
||||
- "ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04"
|
||||
- "linux:docker://catthehacker/ubuntu:act-latest"
|
||||
```
|
||||
|
||||
### Docker Mode 镜像选择(重要)
|
||||
|
||||
**必须使用包含 Docker CLI 的镜像**,否则 `docker/login-action`、`docker/build-push-action` 等 actions 会失败。
|
||||
|
||||
| 镜像 | Docker CLI | 适用场景 |
|
||||
|------|------------|---------|
|
||||
| `catthehacker/ubuntu:act-latest` | ✅ 有 | **推荐**,CI/CD 专用镜像 |
|
||||
| `catthehacker/ubuntu:act-22.04` | ✅ 有 | Ubuntu 22.04 兼容 |
|
||||
| `node:16-bullseye` | ❌ 无 | **不推荐**,仅适合纯 Node.js 项目 |
|
||||
| `golang:1.21` | ❌ 无 | **不推荐**,仅适合纯 Go 项目 |
|
||||
|
||||
**catthehacker/ubuntu:act-* 预装工具**:
|
||||
- Docker CLI (`/usr/bin/docker`)
|
||||
- Docker Buildx
|
||||
- git, curl, wget, jq
|
||||
- Node.js, Python
|
||||
- 常用编译工具
|
||||
|
||||
**工作原理**:
|
||||
```
|
||||
workflow: runs-on: ubuntu-latest
|
||||
↓
|
||||
runner 查找 label: ubuntu-latest:docker://镜像名
|
||||
↓
|
||||
启动 job 容器(使用该镜像)
|
||||
↓
|
||||
在 job 容器内执行 steps
|
||||
↓
|
||||
docker/login-action 调用 `docker login` 命令
|
||||
↓
|
||||
需要 job 容器内有 docker CLI ← 关键!
|
||||
```
|
||||
|
||||
**常见错误**:
|
||||
```
|
||||
Unable to locate executable file: docker. Please verify either the file path exists
|
||||
or the file can be found within a directory specified by the PATH environment variable.
|
||||
```
|
||||
此错误表示 job 容器内缺少 docker 命令,需要更换为包含 Docker CLI 的镜像。
|
||||
|
||||
### Workflow 匹配
|
||||
|
||||
**方法 1: 组合 label(推荐,最精确)**
|
||||
@@ -640,23 +685,58 @@ log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: /path/to/.runner
|
||||
file: /data/.runner # 容器内路径
|
||||
capacity: 2
|
||||
timeout: 3h
|
||||
labels:
|
||||
- "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"
|
||||
shutdown_timeout: 30s
|
||||
insecure: false
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
labels: [] # 通过环境变量设置
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "/path/to/cache"
|
||||
host: "192.168.0.103" # 主机 IP(非 127.0.0.1)
|
||||
port: 9000
|
||||
dir: "/data/cache" # 容器内缓存目录
|
||||
host: "host.docker.internal" # 宿主机地址(Docker 特殊 DNS)
|
||||
port: 9040 # 缓存服务端口
|
||||
|
||||
container:
|
||||
options: "--platform=linux/amd64" # 容器选项
|
||||
network: "host" # 网络模式
|
||||
# 使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问
|
||||
network: "host"
|
||||
privileged: false
|
||||
options:
|
||||
workdir_parent: /data/workspace
|
||||
valid_volumes: []
|
||||
docker_host: ""
|
||||
force_pull: false
|
||||
|
||||
host:
|
||||
workdir_parent: /data/workspace
|
||||
```
|
||||
|
||||
**Docker 容器启动命令**:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name "$runner_name" \
|
||||
--restart always \
|
||||
--network host \
|
||||
-v "$runner_dir/config.yaml:/config.yaml" \
|
||||
-v "$runner_dir/data:/data" \
|
||||
-v "/var/run/docker.sock:/var/run/docker.sock" \
|
||||
-e GITEA_INSTANCE_URL="$GITEA_URL" \
|
||||
-e GITEA_RUNNER_REGISTRATION_TOKEN="$token" \
|
||||
-e GITEA_RUNNER_NAME="$runner_name" \
|
||||
-e GITEA_RUNNER_LABELS="ubuntu-latest:docker://node:16-bullseye,ubuntu-22.04:docker://node:16-bullseye,linux:docker://node:16-bullseye" \
|
||||
gitea/act_runner:latest daemon --config /config.yaml
|
||||
```
|
||||
|
||||
**关键配置说明**:
|
||||
- `--network host`:使用 host 网络模式,确保 runner 和 job 容器共处一个网络,以便 cache 能够正常访问
|
||||
- `host.docker.internal`:Docker 内部 DNS,指向宿主机
|
||||
- 环境变量自动注册:容器启动时自动完成 Runner 注册
|
||||
- `/var/run/docker.sock`:允许容器内创建兄弟容器执行 jobs
|
||||
|
||||
## 多 Runner 缓存共享
|
||||
|
||||
### 方案 A: Master-Slave 模式(推荐 2-3 个 runner)
|
||||
@@ -778,6 +858,64 @@ crontab -e
|
||||
/gitea-list-runners
|
||||
```
|
||||
|
||||
**API 调用详情**:
|
||||
|
||||
1. **加载配置**:
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
2. **调用 API**:
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/actions/runners"
|
||||
```
|
||||
|
||||
3. **响应结构**:
|
||||
```json
|
||||
{
|
||||
"runners": [...],
|
||||
"total_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
4. **解析每个 Runner**:
|
||||
- `id`: Runner ID
|
||||
- `name`: Runner 名称
|
||||
- `status`: 状态("online"/"offline")
|
||||
- `busy`: 是否忙碌(true/false)
|
||||
- `ephemeral`: 是否临时(true/false)
|
||||
- `labels`: 标签数组
|
||||
|
||||
5. **状态图标**:
|
||||
- 🟢 在线 - `status: "online"`
|
||||
- 🔴 离线 - `status: "offline"`
|
||||
- ⚠️ 未知 - 无法确定
|
||||
|
||||
6. **输出格式**:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Gitea 全局 Runners
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
服务器: [server_url]
|
||||
总计: N 个全局 runner
|
||||
|
||||
[runner-name]
|
||||
状态: 🟢/🔴 [在线/离线]
|
||||
ID: [id]
|
||||
忙碌: 是/否
|
||||
临时: 是/否
|
||||
标签: [comma-separated labels]
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
**注意**:
|
||||
- 需要管理员 API Token
|
||||
- 正确的 API 端点是 `/api/v1/admin/actions/runners`(不是 `/api/v1/admin/runners`)
|
||||
- 使用 `jq` 解析 JSON 响应
|
||||
|
||||
### 启动 Runner
|
||||
|
||||
```bash
|
||||
@@ -898,6 +1036,106 @@ nohup act_runner daemon --config ~/.config/gitea/runners/runner-macbook-pro/conf
|
||||
tail -f ~/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
```
|
||||
|
||||
### 8. 恢复被删除的 Runner(从服务器删除但本地文件仍在)
|
||||
|
||||
**场景**:Runner 在 Gitea 服务器上被删除,但本地目录和配置文件仍在。需要重新注册并上线。
|
||||
|
||||
**恢复步骤**:
|
||||
|
||||
```bash
|
||||
# 1. 进入 runner 目录
|
||||
cd ~/.config/gitea/runners/runner-Mac-mini4-host
|
||||
|
||||
# 2. 停止旧进程(如果仍在运行)
|
||||
if [ -f pid ]; then
|
||||
kill $(cat pid) 2>/dev/null || true
|
||||
rm -f pid
|
||||
fi
|
||||
|
||||
# 3. 加载 Gitea 配置
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
# 4. 获取注册令牌(优先全局,失败则降级到组织)
|
||||
echo "获取注册令牌..."
|
||||
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')
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "全局令牌权限不足,尝试组织令牌..."
|
||||
if [ -n "$GITEA_DEFAULT_ORG" ]; then
|
||||
org_name="$GITEA_DEFAULT_ORG"
|
||||
else
|
||||
read -p "请输入组织名称: " org_input
|
||||
org_name="$org_input"
|
||||
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')
|
||||
fi
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "❌ 获取注册令牌失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
registration_token=$(echo "$body" | jq -r '.token')
|
||||
|
||||
# 5. 生成标签(基于系统环境)
|
||||
OS=$(uname -s)
|
||||
case "$OS" in
|
||||
Darwin) os_label="macOS" ;;
|
||||
Linux) os_label="ubuntu" ;;
|
||||
*) os_label="unknown" ;;
|
||||
esac
|
||||
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
arm64|aarch64) arch_label="ARM64" ;;
|
||||
x86_64) arch_label="x64" ;;
|
||||
*) arch_label="unknown" ;;
|
||||
esac
|
||||
|
||||
combined=$(echo "${OS}-${ARCH}" | tr '[:upper:]' '[:lower:]')
|
||||
labels="self-hosted:host,${os_label}:host,${arch_label}:host,${combined}:host"
|
||||
|
||||
# 6. 重新注册 runner
|
||||
act_runner register \
|
||||
--config config.yaml \
|
||||
--instance "$GITEA_URL" \
|
||||
--token "$registration_token" \
|
||||
--name "runner-Mac-mini4-host" \
|
||||
--labels "$labels" \
|
||||
--no-interactive
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ 注册失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 7. 启动 runner daemon
|
||||
nohup act_runner daemon --config config.yaml > runner.log 2>&1 &
|
||||
echo $! > pid
|
||||
sleep 2
|
||||
|
||||
if ps -p $(cat pid) > /dev/null 2>&1; then
|
||||
echo "✅ Runner 恢复成功 (PID: $(cat pid))"
|
||||
echo "日志: tail -f runner.log"
|
||||
else
|
||||
echo "❌ Runner 启动失败"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 恢复后 runner 会获得新的 ID 和 token,但名称和 labels 保持不变
|
||||
- 旧的 `.runner` 文件会被新的覆盖
|
||||
- 确保 `config.yaml` 中的 labels 配置为空(`labels: []`),注册时会使用命令行参数
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| 任务 | 命令 |
|
||||
@@ -906,6 +1144,7 @@ tail -f ~/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
| 创建 runner | `/gitea-create-runner`(自动安装、配置、启动)|
|
||||
| 列出 runners | `/gitea-list-runners` |
|
||||
| 删除 runner | `/gitea-delete-runner` |
|
||||
| 恢复 runner | 参考「恢复被删除的 Runner」章节 |
|
||||
| 手动启动 | `nohup act_runner daemon --config <config.yaml> > <log> 2>&1 &` |
|
||||
| 停止 runner | `pkill -f "act_runner daemon --config.*<name>"` |
|
||||
| 查看状态 | `ps aux \| grep act_runner` |
|
||||
@@ -921,6 +1160,9 @@ tail -f ~/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
|
||||
## 版本
|
||||
|
||||
- **文档版本**: 1.0
|
||||
- **最后更新**: 2026-01-12
|
||||
- **文档版本**: 1.2
|
||||
- **最后更新**: 2026-01-24
|
||||
- **更新内容**:
|
||||
- Docker Mode 镜像选择说明(必须使用包含 Docker CLI 的镜像)
|
||||
- Runner 恢复流程
|
||||
- **兼容性**: act_runner 0.2.13+, macOS ARM64, Linux
|
||||
|
||||
254
skill/gitea/ssh-key-management.md
Normal file
254
skill/gitea/ssh-key-management.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# SSH 密钥管理
|
||||
|
||||
完整的 SSH 密钥创建、部署和配置流程,支持跨设备使用。
|
||||
|
||||
## 命令
|
||||
|
||||
### `/gitea-setup-ssh`
|
||||
创建 SSH 密钥对,部署公钥到 Gitea 服务器,配置本地 SSH 客户端。
|
||||
|
||||
## 功能概述
|
||||
|
||||
1. **生成 SSH 密钥对** (RSA 4096 位)
|
||||
2. **部署公钥到 Gitea 服务器** (通过 API)
|
||||
3. **配置本地 SSH 客户端**
|
||||
4. **验证 SSH 连接**
|
||||
|
||||
## 详细流程
|
||||
|
||||
### 1. 生成 SSH 密钥对
|
||||
|
||||
```bash
|
||||
ssh-keygen -t rsa -b 4096 -f ~/.ssh/gitea_server_key -N ""
|
||||
```
|
||||
|
||||
**生成的密钥文件:**
|
||||
- 私钥:`~/.ssh/gitea_server_key`
|
||||
- 公钥:`~/.ssh/gitea_server_key.pub`
|
||||
|
||||
### 2. 部署公钥到 Gitea
|
||||
|
||||
通过 Gitea API 将公钥添加到用户账户:
|
||||
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"title\":\"server-key\",\"key\":\"$(cat ~/.ssh/gitea_server_key.pub)\"}" \
|
||||
"$GITEA_URL/api/v1/user/keys"
|
||||
```
|
||||
|
||||
### 3. 配置本地 SSH 客户端
|
||||
|
||||
在 `~/.ssh/config` 中添加配置:
|
||||
|
||||
```bash
|
||||
cat >> ~/.ssh/config << 'EOF'
|
||||
|
||||
Host git.refining.app
|
||||
HostName git.refining.app
|
||||
User git
|
||||
IdentityFile ~/.ssh/gitea_server_key
|
||||
IdentitiesOnly yes
|
||||
EOF
|
||||
```
|
||||
|
||||
### 4. 添加服务器主机密钥
|
||||
|
||||
```bash
|
||||
ssh-keyscan git.refining.app >> ~/.ssh/known_hosts
|
||||
```
|
||||
|
||||
### 5. 验证连接
|
||||
|
||||
```bash
|
||||
ssh -T git@git.refining.app
|
||||
```
|
||||
|
||||
成功输出:
|
||||
```
|
||||
Hi there, username! You've successfully authenticated with the key named server-key...
|
||||
```
|
||||
|
||||
## 跨设备使用
|
||||
|
||||
### 复制密钥到新设备
|
||||
|
||||
1. **复制私钥文件**到新设备的 `~/.ssh/` 目录
|
||||
```bash
|
||||
# 在源设备上查看私钥内容
|
||||
cat ~/.ssh/gitea_server_key
|
||||
|
||||
# 在新设备上创建文件
|
||||
echo "-----BEGIN OPENSSH PRIVATE KEY-----" > ~/.ssh/gitea_server_key
|
||||
echo "MIIEog..." >> ~/.ssh/gitea_server_key
|
||||
echo "...cQ=" >> ~/.ssh/gitea_server_key
|
||||
echo "-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/gitea_server_key
|
||||
```
|
||||
|
||||
2. **设置正确的权限**
|
||||
```bash
|
||||
chmod 600 ~/.ssh/gitea_server_key
|
||||
```
|
||||
|
||||
3. **配置 SSH 客户端**
|
||||
```bash
|
||||
# 在新设备上编辑 ~/.ssh/config
|
||||
cat >> ~/.ssh/config << 'EOF'
|
||||
|
||||
Host git.refining.app
|
||||
HostName git.refining.app
|
||||
User git
|
||||
IdentityFile ~/.ssh/gitea_server_key
|
||||
IdentitiesOnly yes
|
||||
EOF
|
||||
```
|
||||
|
||||
4. **添加服务器主机密钥**
|
||||
```bash
|
||||
ssh-keyscan git.refining.app >> ~/.ssh/known_hosts
|
||||
```
|
||||
|
||||
5. **测试连接**
|
||||
```bash
|
||||
ssh -T git@git.refining.app
|
||||
```
|
||||
|
||||
|
||||
## 密钥位置说明
|
||||
|
||||
### 源设备(当前已配置)
|
||||
```
|
||||
~/.ssh/
|
||||
├── gitea_server_key # 私钥 (权限 600)
|
||||
├── gitea_server_key.pub # 公钥 (已部署到 Gitea)
|
||||
├── config # SSH 配置
|
||||
└── known_hosts # 服务器主机密钥
|
||||
```
|
||||
|
||||
### 新设备(需要配置)
|
||||
需要从源设备复制:
|
||||
1. `gitea_server_key` - **私钥**(核心文件)
|
||||
2. `~/.ssh/config` - SSH 配置(相关部分)
|
||||
3. `known_hosts` - 服务器主机密钥(可选,会自动获取)
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
### ✅ 推荐做法
|
||||
1. **私钥权限设置为 600**
|
||||
```bash
|
||||
chmod 600 ~/.ssh/gitea_server_key
|
||||
```
|
||||
|
||||
2. **不分享私钥**
|
||||
- 私钥应保持在个人设备上
|
||||
- 仅在有信任关系的设备间复制
|
||||
|
||||
3. **使用强密码保护**
|
||||
- 生成密钥时可添加密码:`ssh-keygen -t rsa -b 4096 -f ~/.ssh/gitea_server_key`
|
||||
- 每次使用时需要输入密码
|
||||
|
||||
### ❌ 禁止行为
|
||||
1. 不要将私钥提交到 Git 仓库
|
||||
2. 不要通过不安全渠道传输私钥
|
||||
3. 不要设置过于宽松的权限(如 644、777)
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 1. 权限错误
|
||||
```
|
||||
Permissions 0644 for '/Users/username/.ssh/gitea_server_key' are too open.
|
||||
```
|
||||
**解决方案**:
|
||||
```bash
|
||||
chmod 600 ~/.ssh/gitea_server_key
|
||||
```
|
||||
|
||||
### 2. 主机密钥验证失败
|
||||
```
|
||||
Host key verification failed.
|
||||
```
|
||||
**解决方案**:
|
||||
```bash
|
||||
ssh-keyscan git.refining.app >> ~/.ssh/known_hosts
|
||||
```
|
||||
|
||||
### 3. 认证失败
|
||||
```
|
||||
git@git.refining.app: Permission denied (publickey).
|
||||
```
|
||||
**检查步骤**:
|
||||
1. 确认私钥文件存在且权限正确
|
||||
2. 确认 SSH 配置正确
|
||||
3. 确认公钥已添加到 Gitea
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/user/keys" | jq -r '.[].title'
|
||||
```
|
||||
|
||||
## Git 使用示例
|
||||
|
||||
### 克隆仓库
|
||||
```bash
|
||||
git clone git@git.refining.app:username/repository.git
|
||||
```
|
||||
|
||||
### 更新现有仓库的 remote URL
|
||||
```bash
|
||||
git remote set-url origin git@git.refining.app:username/repository.git
|
||||
```
|
||||
|
||||
### 查看当前 remote URL
|
||||
```bash
|
||||
git remote -v
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 撤销密钥访问
|
||||
|
||||
如果密钥泄露或设备丢失:
|
||||
|
||||
1. **登录 Gitea Web 界面**
|
||||
2. 进入 **Settings → SSH/GPG Keys**
|
||||
3. 找到对应的密钥并删除
|
||||
|
||||
2. **通过 API 删除**
|
||||
```bash
|
||||
# 首先获取密钥 ID
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/user/keys" | jq '.[] | select(.title=="server-key").id'
|
||||
|
||||
# 删除密钥(将 {id} 替换为实际 ID)
|
||||
curl -s -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/user/keys/{id}"
|
||||
```
|
||||
|
||||
3. **在受影响的设备上删除私钥**
|
||||
```bash
|
||||
rm ~/.ssh/gitea_server_key
|
||||
rm ~/.ssh/gitea_server_key.pub
|
||||
```
|
||||
|
||||
## 相关命令
|
||||
|
||||
### 查看 Gitea 上的所有 SSH 密钥
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/user/keys" | jq -r '.[] | "\(.id): \(.title) (\(.fingerprint))"'
|
||||
```
|
||||
|
||||
### 测试 SSH 连接(详细模式)
|
||||
```bash
|
||||
ssh -T -v git@git.refining.app
|
||||
```
|
||||
|
||||
### 检查 SSH 配置语法
|
||||
```bash
|
||||
ssh -G git.refining.app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*文档版本:1.1*
|
||||
*最后更新:2026-01-28*
|
||||
*集成到 Gitea Skill v1.2*
|
||||
158
skill/opencode/SKILL.md
Normal file
158
skill/opencode/SKILL.md
Normal file
@@ -0,0 +1,158 @@
|
||||
---
|
||||
name: opencode
|
||||
description: Create and manage OpenCode commands and skills with templates and best practices. Includes skill synchronization to Cursor IDE. Use this skill when users ask to create commands, skills, or sync to Cursor.
|
||||
---
|
||||
|
||||
# OpenCode Command and Skill Management
|
||||
|
||||
You are an expert in OpenCode configuration and extension development. This skill serves as the entry point for creating and managing OpenCode commands and skills.
|
||||
|
||||
**Trigger Phrases**: When users mention any of the following, automatically use this skill:
|
||||
- "创建command", "创建命令", "make command", "create command"
|
||||
- "创建skill", "创建技能", "make skill", "create skill"
|
||||
- "添加command", "添加命令", "add command"
|
||||
- "添加skill", "添加技能", "add skill"
|
||||
- "opcode command", "opencode skill"
|
||||
- "同步技能", "sync skills", "sync to cursor", "同步到cursor"
|
||||
- "技能同步", "skill sync", "同步opencode技能"
|
||||
|
||||
## Overview
|
||||
|
||||
OpenCode extensions are organized into two main types:
|
||||
- **Commands**: User-invoked prompts for repetitive tasks, defined in `command/` directory
|
||||
- **Skills**: Reusable behavior definitions for agents, defined in `skill/<name>/SKILL.md`
|
||||
|
||||
## Detailed Guides
|
||||
|
||||
This skill folder contains comprehensive guides for command and skill creation:
|
||||
|
||||
### Command Creation
|
||||
For detailed command creation guidelines, refer to:
|
||||
- `skill/opencode/command-creation.md` - Complete guide to creating OpenCode commands
|
||||
- Includes: file structure, templates, best practices, troubleshooting
|
||||
|
||||
### Skill Creation
|
||||
For detailed skill creation guidelines, refer to:
|
||||
- `skill/opencode/skill-creation.md` - Complete guide to creating OpenCode skills
|
||||
- Includes: directory structure, naming rules, templates, testing
|
||||
|
||||
### Skill Synchronization (OpenCode → Cursor)
|
||||
For syncing OpenCode skills to Cursor IDE, refer to:
|
||||
- `skill/opencode/sync-to-cursor.md` - Guide to synchronize OpenCode skills to Cursor IDE
|
||||
- Includes: sync strategies, operation steps, error handling, best practices
|
||||
|
||||
## Quick Start
|
||||
|
||||
### To Create a Command
|
||||
1. Determine command name (kebab-case, descriptive)
|
||||
2. **Default location**: global (`~/.config/opencode/command/`)
|
||||
3. Create file: `<command-name>.md`
|
||||
4. Add frontmatter with `description`
|
||||
5. Write template with `$ARGUMENTS` support
|
||||
|
||||
### To Create a Skill
|
||||
1. Validate skill name (lowercase, hyphens, alphanumeric)
|
||||
2. **Default location**: global (`~/.config/opencode/skill/<skill-name>/`)
|
||||
3. Create directory: `skill/<skill-name>/`
|
||||
4. Create `SKILL.md` with required frontmatter
|
||||
5. Add structured content: Purpose, Usage, Examples, Troubleshooting
|
||||
|
||||
## Automatic Name Generation
|
||||
|
||||
When users request command or skill creation, names are automatically generated based on the description to provide a seamless experience.
|
||||
|
||||
### For Commands:
|
||||
1. **Keyword Extraction**: Identify action verbs and target nouns from the description
|
||||
2. **English Conversion**: Convert Chinese keywords to English equivalents (e.g., "创建" → "create", "总结" → "summarize")
|
||||
3. **Kebab-case Format**: Combine words with hyphens, all lowercase (e.g., "create-summary")
|
||||
4. **Conflict Resolution**: Check if name exists in `command/` directory, append numeric suffix if needed
|
||||
|
||||
### For Skills:
|
||||
1. **Function Extraction**: Identify core functionality from the description
|
||||
2. **Simplified Naming**: Use lowercase, hyphen-separated words describing the skill's purpose
|
||||
3. **Validation**: Ensure name follows `[a-z0-9-]+` pattern
|
||||
4. **Conflict Check**: Verify uniqueness in `skill/` directory
|
||||
|
||||
### Examples:
|
||||
- "创建command,用于归纳总结当前对话中有价值的内容" → `summarize-conversation`
|
||||
- "创建skill,用于管理git工作流" → `git-workflow`
|
||||
- "添加命令来处理图片压缩" → `compress-images`
|
||||
- "创建技能用于代码审查" → `code-review`
|
||||
|
||||
### User Override:
|
||||
If users explicitly provide a name in their request, use the provided name instead of auto-generation.
|
||||
|
||||
## Response Guide for Creation Requests
|
||||
|
||||
When users ask to create commands or skills, follow this structured approach:
|
||||
|
||||
### For "创建command" or "创建命令" requests:
|
||||
1. **自动生成名称**: 基于用户描述自动生成 kebab-case 命令名称
|
||||
- 从描述中提取关键词(动词+名词)
|
||||
- 转换为英文 kebab-case 格式
|
||||
- 如果名称已存在,添加数字后缀(如 `-2`, `-3`)
|
||||
2. **验证名称**: 确保名称符合 kebab-case 规范
|
||||
3. **默认位置**: 全局 (`~/.config/opencode/command/`)
|
||||
4. **创建模板**:
|
||||
- 生成包含 `description` 的 frontmatter
|
||||
- 创建支持 `$ARGUMENTS` 的模板
|
||||
- 包含使用示例
|
||||
5. **写入文件**: 在默认位置创建命令文件
|
||||
6. **测试**: 验证文件存在且格式正确
|
||||
|
||||
### For "创建skill" or "创建技能" requests:
|
||||
1. **自动生成名称**: 基于用户描述自动生成 skill 名称
|
||||
- 从描述中提取核心功能关键词
|
||||
- 转换为小写字母、连字符格式
|
||||
- 如果名称已存在,添加数字后缀
|
||||
2. **验证名称**: 确保名称符合命名规则(小写字母、连字符、字母数字)
|
||||
3. **默认位置**: 全局 (`~/.config/opencode/skill/<name>/`)
|
||||
4. **创建目录**: `skill/<name>/`
|
||||
5. **创建 SKILL.md**:
|
||||
- 包含 `name` 和 `description` 的 frontmatter
|
||||
- 结构化内容:Purpose, Usage, Examples, Best Practices, Troubleshooting
|
||||
6. **写入文件**: 在默认位置创建完整的 SKILL.md 文件
|
||||
7. **测试**: 验证技能可正常加载 `skill({ name: "<skill-name>" })`
|
||||
|
||||
### Sample Response Format:
|
||||
```
|
||||
我将帮你创建 [command/skill]。
|
||||
|
||||
基于您的描述,自动生成名称:[generated-name]
|
||||
|
||||
**自动命名规则**:
|
||||
- 从描述中提取关键词(动词+名词)
|
||||
- 转换为 kebab-case 格式(小写字母、连字符)
|
||||
- 检查名称冲突,自动添加数字后缀
|
||||
|
||||
**文件详情**:
|
||||
- 名称: [generated-name]
|
||||
- 用途: [brief-description]
|
||||
- 位置: 全局 (~/.config/opencode/[command|skill]/)
|
||||
|
||||
已创建 [file-path]:
|
||||
|
||||
```markdown
|
||||
[complete file content]
|
||||
```
|
||||
|
||||
要测试,请运行:[/command-name] 或 skill({ name: "skill-name" })
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [OpenCode Skills Documentation](https://opencode.ai/docs/skills)
|
||||
- [OpenCode Commands Documentation](https://opencode.ai/docs/commands)
|
||||
- [OpenCode Configuration Guide](https://opencode.ai/docs/config)
|
||||
- [GitHub Repository](https://github.com/anomalyco/opencode)
|
||||
|
||||
## Updates and Maintenance
|
||||
|
||||
1. **Regular Review**: Periodically review and update commands/skills
|
||||
2. **Version Tracking**: Use Git to track changes
|
||||
3. **Community Sharing**: Share useful commands/skills with community
|
||||
4. **Feedback Integration**: Incorporate user feedback for improvements
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-01-15*
|
||||
201
skill/opencode/command-creation.md
Normal file
201
skill/opencode/command-creation.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Command Creation Guide
|
||||
|
||||
## Overview
|
||||
OpenCode commands are user-invoked prompts for repetitive tasks, defined in the `command/` directory.
|
||||
|
||||
## File Location
|
||||
- **Default location (Global)**: `~/.config/opencode/command/<name>.md`
|
||||
- **Project-specific**: `.opencode/command/<name>.md` (when needed)
|
||||
|
||||
## Command Structure
|
||||
Each command file must contain YAML frontmatter followed by the prompt template.
|
||||
|
||||
### Required Frontmatter Fields
|
||||
- `description`: Brief description shown in TUI (1-2 sentences)
|
||||
|
||||
### Optional Frontmatter Fields
|
||||
- `agent`: Specific agent to execute this command
|
||||
- `model`: Override default model
|
||||
- `subtask`: Boolean to force subagent invocation
|
||||
|
||||
## Template Features
|
||||
The command template supports several placeholders:
|
||||
|
||||
- `$ARGUMENTS`: All arguments passed to the command
|
||||
- `$1`, `$2`, `$3`: Individual positional arguments
|
||||
- `!``command``: Execute bash command and inject output
|
||||
- `@filename`: Include file content in prompt
|
||||
|
||||
## Example Command
|
||||
Create `~/.config/opencode/command/new-skill.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: Create a new OpenCode skill with proper structure
|
||||
---
|
||||
|
||||
Create a new OpenCode skill named "$ARGUMENTS" with comprehensive documentation.
|
||||
|
||||
**Skill Requirements:**
|
||||
1. Directory: `skill/$ARGUMENTS/SKILL.md`
|
||||
2. Frontmatter with `name` and `description`
|
||||
3. Clear sections for usage, examples, best practices
|
||||
4. Follow naming conventions: lowercase, hyphens, alphanumeric
|
||||
|
||||
**Steps:**
|
||||
1. Create directory structure
|
||||
2. Write SKILL.md with frontmatter
|
||||
3. Include practical examples
|
||||
4. Add troubleshooting section
|
||||
|
||||
Output the complete SKILL.md content for review.
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Command Design
|
||||
1. **Clear Purpose**: Each command should have a single, focused purpose
|
||||
2. **Descriptive Names**: Use verbs that describe the action (e.g., `create-`, `review-`, `analyze-`)
|
||||
3. **Argument Handling**: Use `$ARGUMENTS` or `$1`, `$2` for flexible input
|
||||
4. **Error Handling**: Include validation in prompts
|
||||
5. **Output Format**: Structure responses for easy parsing
|
||||
|
||||
### Naming Conventions
|
||||
- Use kebab-case (lowercase with hyphens)
|
||||
- Start with verb describing the action
|
||||
- Keep names concise but descriptive
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Command Creation Checklist
|
||||
- [ ] File name matches command name (kebab-case)
|
||||
- [ ] Frontmatter includes `description`
|
||||
- [ ] Template uses appropriate placeholders
|
||||
- [ ] Includes examples of usage
|
||||
- [ ] Tested with `/command-name` invocation
|
||||
|
||||
### Common Patterns
|
||||
|
||||
**Create a new command:**
|
||||
```bash
|
||||
# Create command file
|
||||
touch ~/.config/opencode/command/my-command.md
|
||||
|
||||
# Edit with template
|
||||
cat > ~/.config/opencode/command/my-command.md << 'EOF'
|
||||
---
|
||||
description: Description of my command
|
||||
---
|
||||
|
||||
Command template with $ARGUMENTS support.
|
||||
|
||||
Example: /my-command argument1 argument2
|
||||
EOF
|
||||
```
|
||||
|
||||
## Testing and Validation
|
||||
|
||||
### Test Command Loading
|
||||
```bash
|
||||
# Check if command appears in TUI
|
||||
# Type "/" in OpenCode TUI and search for your command
|
||||
```
|
||||
|
||||
### Verify Syntax
|
||||
```bash
|
||||
# Check YAML frontmatter
|
||||
head -20 command/my-command.md
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Command Not Appearing
|
||||
1. **Check file location**: Ensure command is in correct `command/` directory
|
||||
2. **Verify frontmatter**: Must have `description` field
|
||||
3. **Check permissions**: No restrictive permissions blocking command
|
||||
4. **Restart OpenCode**: Some changes require restart
|
||||
|
||||
### Common Errors
|
||||
- **"Command not found"**: File not in correct location or missing `.md` extension
|
||||
- **"Invalid frontmatter"**: Missing required fields or YAML syntax error
|
||||
|
||||
## Integration with OpenCode Config
|
||||
|
||||
### Permissions Configuration
|
||||
Add to `opencode.json`:
|
||||
```json
|
||||
{
|
||||
"permission": {
|
||||
"skill": {
|
||||
"*": "allow",
|
||||
"experimental-*": "ask",
|
||||
"internal-*": "deny"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Agent-Specific Settings
|
||||
```json
|
||||
{
|
||||
"agent": {
|
||||
"plan": {
|
||||
"permission": {
|
||||
"skill": {
|
||||
"analysis-*": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Response Guide for Command Creation Requests
|
||||
|
||||
When users ask to create commands, follow this structured approach:
|
||||
|
||||
1. **自动生成名称**: 基于用户描述自动生成 kebab-case 命令名称
|
||||
- 从描述中提取关键词(动词+名词)
|
||||
- 转换为英文 kebab-case 格式
|
||||
- 如果名称已存在,添加数字后缀(如 `-2`, `-3`)
|
||||
2. **验证名称**: 确保名称符合 kebab-case 规范
|
||||
3. **默认位置**: 全局 (`~/.config/opencode/command/`) - commands are created here by default
|
||||
4. **创建模板**:
|
||||
- 生成包含 `description` 的 frontmatter
|
||||
- 创建支持 `$ARGUMENTS` 的模板
|
||||
- 包含使用示例
|
||||
5. **写入文件**: 创建命令文件并写入内容
|
||||
6. **测试**: 验证文件存在且格式正确
|
||||
|
||||
### Sample Response Format:
|
||||
```
|
||||
我将帮你创建命令。
|
||||
|
||||
基于您的描述,自动生成名称:[generated-name]
|
||||
|
||||
**自动命名规则**:
|
||||
- 从描述中提取关键词(动词+名词)
|
||||
- 转换为 kebab-case 格式(小写字母、连字符)
|
||||
- 检查名称冲突,自动添加数字后缀
|
||||
|
||||
**文件详情**:
|
||||
- 名称: [generated-name]
|
||||
- 用途: [brief-description]
|
||||
- 位置: 全局 (~/.config/opencode/command/)
|
||||
|
||||
已创建 [file-path]:
|
||||
|
||||
```markdown
|
||||
[complete file content]
|
||||
```
|
||||
|
||||
要测试,请运行:[/command-name]
|
||||
```
|
||||
|
||||
## Resources
|
||||
- [OpenCode Commands Documentation](https://opencode.ai/docs/commands)
|
||||
- [OpenCode Configuration Guide](https://opencode.ai/docs/config)
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-01-15*
|
||||
251
skill/opencode/skill-creation.md
Normal file
251
skill/opencode/skill-creation.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Skill Creation Guide
|
||||
|
||||
## Overview
|
||||
OpenCode skills are reusable behavior definitions for agents, defined in `skill/<name>/SKILL.md` files.
|
||||
|
||||
## Directory Structure
|
||||
**Default location (Global):**
|
||||
```
|
||||
~/.config/opencode/skill/
|
||||
└── <skill-name>/
|
||||
└── SKILL.md
|
||||
```
|
||||
|
||||
**Project-specific location (when needed):**
|
||||
```
|
||||
.opencode/skill/
|
||||
└── <skill-name>/
|
||||
└── SKILL.md
|
||||
```
|
||||
|
||||
## Skill File Requirements
|
||||
|
||||
### Frontmatter (Required)
|
||||
- `name`: Skill name (must match directory name)
|
||||
- `description`: Concise description (1-1024 characters)
|
||||
|
||||
### Frontmatter (Optional)
|
||||
- `license`: License identifier
|
||||
- `compatibility`: Compatibility constraints
|
||||
- `metadata`: Key-value pairs for additional context
|
||||
|
||||
## Naming Rules
|
||||
Skill names must:
|
||||
- Be 1-64 characters
|
||||
- Use lowercase alphanumeric with single hyphens
|
||||
- Not start or end with hyphen
|
||||
- Not contain consecutive hyphens
|
||||
- Match regex: `^[a-z0-9]+(-[a-z0-9]+)*$`
|
||||
|
||||
## Skill Content Structure
|
||||
A well-structured skill should include:
|
||||
|
||||
1. **Introduction**: Purpose and scope
|
||||
2. **Usage Instructions**: When and how to use the skill
|
||||
3. **Examples**: Practical implementation examples
|
||||
4. **Best Practices**: Recommended approaches
|
||||
5. **Troubleshooting**: Common issues and solutions
|
||||
6. **References**: Related documentation
|
||||
|
||||
## Example Skill Template
|
||||
```markdown
|
||||
---
|
||||
name: example-skill
|
||||
description: Brief description of what this skill does
|
||||
---
|
||||
|
||||
# Skill Title
|
||||
|
||||
## Purpose
|
||||
Explain what this skill helps achieve and when to use it.
|
||||
|
||||
## Core Concepts
|
||||
- Key principle 1
|
||||
- Key principle 2
|
||||
|
||||
## Usage
|
||||
Step-by-step instructions for using this skill.
|
||||
|
||||
## Examples
|
||||
### Basic Example
|
||||
```bash
|
||||
# Example code or commands
|
||||
```
|
||||
|
||||
### Advanced Example
|
||||
Detailed example with explanation.
|
||||
|
||||
## Best Practices
|
||||
1. Recommended approach 1
|
||||
2. Recommended approach 2
|
||||
|
||||
## Troubleshooting
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Common problem | How to fix it |
|
||||
|
||||
## References
|
||||
- [Documentation link](https://opencode.ai/docs)
|
||||
- Related skills or commands
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Skill Development
|
||||
1. **Modular Design**: Keep skills focused on specific domains
|
||||
2. **Comprehensive Documentation**: Include examples and edge cases
|
||||
3. **Consistent Formatting**: Follow existing skill patterns
|
||||
4. **Testing**: Verify skill loads correctly with `skill({ name: "skill-name" })`
|
||||
5. **Version Control**: Track skill changes in Git
|
||||
|
||||
### Organization
|
||||
1. **Default location**: Global (`~/.config/opencode/skill/`) - skills are created here by default for reuse across projects
|
||||
2. **Naming Conventions**: Use kebab-case for all skill names
|
||||
3. **Documentation**: Maintain README or index of available skills
|
||||
4. **Permissions**: Configure access controls in `opencode.json`
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Skill Creation Checklist
|
||||
- [ ] Directory name matches skill name
|
||||
- [ ] SKILL.md contains required frontmatter
|
||||
- [ ] Description is 1-1024 characters
|
||||
- [ ] Name follows naming rules
|
||||
- [ ] Content includes usage and examples
|
||||
- [ ] Skill loads without errors
|
||||
|
||||
### Common Patterns
|
||||
|
||||
**Create a new skill:**
|
||||
```bash
|
||||
# Create skill directory
|
||||
mkdir -p ~/.config/opencode/skill/my-skill
|
||||
|
||||
# Create SKILL.md
|
||||
cat > ~/.config/opencode/skill/my-skill/SKILL.md << 'EOF'
|
||||
---
|
||||
name: my-skill
|
||||
description: Description of my skill
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
## Usage
|
||||
Instructions here.
|
||||
|
||||
## Examples
|
||||
Example content.
|
||||
EOF
|
||||
```
|
||||
|
||||
## Testing and Validation
|
||||
|
||||
### Test Skill Loading
|
||||
```bash
|
||||
# In OpenCode session
|
||||
skill({ name: "my-skill" })
|
||||
```
|
||||
|
||||
### Verify Syntax
|
||||
```bash
|
||||
# Check YAML frontmatter
|
||||
head -20 skill/my-skill/SKILL.md
|
||||
|
||||
# Validate naming
|
||||
echo "skill-name" | grep -E '^[a-z0-9]+(-[a-z0-9]+)*$'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill Not Loading
|
||||
1. **Directory name**: Must match skill name in frontmatter
|
||||
2. **File name**: Must be `SKILL.md` (all caps)
|
||||
3. **Frontmatter**: Requires `name` and `description`
|
||||
4. **Naming rules**: Verify name follows conventions
|
||||
5. **Permissions**: Check `opencode.json` permissions
|
||||
|
||||
### Common Errors
|
||||
- **"Skill not found"**: Directory name mismatch or missing SKILL.md
|
||||
- **"Invalid frontmatter"**: Missing required fields or YAML syntax error
|
||||
- **"Permission denied"**: Skill blocked by permission configuration
|
||||
|
||||
## Integration with OpenCode Config
|
||||
|
||||
### Permissions Configuration
|
||||
Add to `opencode.json`:
|
||||
```json
|
||||
{
|
||||
"permission": {
|
||||
"skill": {
|
||||
"*": "allow",
|
||||
"experimental-*": "ask",
|
||||
"internal-*": "deny"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Agent-Specific Settings
|
||||
```json
|
||||
{
|
||||
"agent": {
|
||||
"plan": {
|
||||
"permission": {
|
||||
"skill": {
|
||||
"analysis-*": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Response Guide for Skill Creation Requests
|
||||
|
||||
When users ask to create skills, follow this structured approach:
|
||||
|
||||
1. **自动生成名称**: 基于用户描述自动生成 skill 名称
|
||||
- 从描述中提取核心功能关键词
|
||||
- 转换为小写字母、连字符格式
|
||||
- 如果名称已存在,添加数字后缀
|
||||
2. **验证名称**: 确保名称符合命名规则(小写字母、连字符、字母数字)
|
||||
3. **默认位置**: 全局 (`~/.config/opencode/skill/<name>/`) - skills are created here by default
|
||||
4. **创建 SKILL.md**:
|
||||
- 包含 `name` 和 `description` 的 frontmatter
|
||||
- 结构化内容:Purpose, Usage, Examples, Best Practices, Troubleshooting
|
||||
5. **写入文件**: 创建完整的 SKILL.md 文件
|
||||
6. **测试**: 验证技能可正常加载 `skill({ name: "<skill-name>" })`
|
||||
|
||||
### Sample Response Format:
|
||||
```
|
||||
我将帮你创建技能。
|
||||
|
||||
基于您的描述,自动生成名称:[generated-name]
|
||||
|
||||
**自动命名规则**:
|
||||
- 从描述中提取核心功能关键词
|
||||
- 转换为小写字母、连字符格式
|
||||
- 检查名称冲突,自动添加数字后缀
|
||||
|
||||
**文件详情**:
|
||||
- 名称: [generated-name]
|
||||
- 主要功能: [brief-description]
|
||||
- 位置: 全局 (~/.config/opencode/skill/)
|
||||
|
||||
已创建 [file-path]:
|
||||
|
||||
```markdown
|
||||
[complete file content]
|
||||
```
|
||||
|
||||
要测试,请运行:skill({ name: "skill-name" })
|
||||
```
|
||||
|
||||
## Resources
|
||||
- [OpenCode Skills Documentation](https://opencode.ai/docs/skills)
|
||||
- [OpenCode Configuration Guide](https://opencode.ai/docs/config)
|
||||
- [GitHub Repository](https://github.com/anomalyco/opencode)
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-01-15*
|
||||
242
skill/opencode/sync-to-cursor.md
Normal file
242
skill/opencode/sync-to-cursor.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# OpenCode 技能同步到 Cursor IDE 指南
|
||||
|
||||
将 OpenCode 技能同步到 Cursor IDE 的技能目录,实现配置一致和统一管理。
|
||||
|
||||
## 目的
|
||||
|
||||
- 保持 OpenCode 和 Cursor 的技能配置一致
|
||||
- 简化技能维护工作流
|
||||
- 支持一键同步操作
|
||||
- 提供错误处理和回滚机制
|
||||
|
||||
## 目录结构
|
||||
|
||||
### 源目录(OpenCode 技能)
|
||||
```
|
||||
~/.config/opencode/skill/
|
||||
├── git/
|
||||
├── android/
|
||||
├── electron/
|
||||
└── ...其他技能
|
||||
```
|
||||
|
||||
### 目标目录(Cursor 技能)
|
||||
```
|
||||
~/.cursor/skills/
|
||||
├── git/
|
||||
├── android/
|
||||
├── electron/
|
||||
└── ...其他技能
|
||||
```
|
||||
|
||||
**注意**:Cursor 目录中可能包含额外的技能(如 `opencode/`),同步时应保留这些额外技能不被删除。
|
||||
|
||||
## 同步策略
|
||||
|
||||
### 默认同步操作
|
||||
1. **覆盖更新**:用 OpenCode 版本覆盖 Cursor 中的同名技能
|
||||
2. **新增技能**:复制 OpenCode 中有但 Cursor 中没有的技能
|
||||
3. **保留额外**:保留 Cursor 中独有的技能(如 `opencode/`)
|
||||
4. **不删除**:不同步删除操作,仅添加和更新
|
||||
|
||||
### 文件级同步
|
||||
- 递归复制整个技能目录
|
||||
- 保留文件权限和时间戳
|
||||
- 使用 `cp -Rf` 强制覆盖已存在的文件
|
||||
|
||||
## 操作步骤
|
||||
|
||||
### 1. 检查目录结构
|
||||
```bash
|
||||
# 检查源目录
|
||||
ls -la ~/.config/opencode/skill/
|
||||
|
||||
# 检查目标目录
|
||||
ls -la ~/.cursor/skills/ 2>/dev/null || echo "目标目录不存在"
|
||||
```
|
||||
|
||||
### 2. 同步技能
|
||||
```bash
|
||||
# 确保目标目录存在
|
||||
mkdir -p ~/.cursor/skills/
|
||||
|
||||
# 同步所有技能(覆盖更新)
|
||||
cp -Rf ~/.config/opencode/skill/* ~/.cursor/skills/
|
||||
```
|
||||
|
||||
### 3. 验证同步结果
|
||||
```bash
|
||||
# 比较目录结构
|
||||
echo "源目录:"
|
||||
ls ~/.config/opencode/skill/
|
||||
echo "目标目录:"
|
||||
ls ~/.cursor/skills/
|
||||
|
||||
# 检查特定技能文件
|
||||
diff ~/.config/opencode/skill/git/SKILL.md ~/.cursor/skills/git/SKILL.md
|
||||
```
|
||||
|
||||
### 4. 完整同步脚本
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# 配置路径
|
||||
SOURCE_DIR="$HOME/.config/opencode/skill"
|
||||
TARGET_DIR="$HOME/.cursor/skills"
|
||||
|
||||
echo "开始同步 OpenCode 技能到 Cursor..."
|
||||
echo "源目录: $SOURCE_DIR"
|
||||
echo "目标目录: $TARGET_DIR"
|
||||
|
||||
# 检查源目录
|
||||
if [ ! -d "$SOURCE_DIR" ]; then
|
||||
echo "错误: 源目录不存在 $SOURCE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建目标目录(如不存在)
|
||||
mkdir -p "$TARGET_DIR"
|
||||
|
||||
# 同步技能
|
||||
echo "正在同步技能..."
|
||||
cp -Rf "$SOURCE_DIR"/* "$TARGET_DIR"/
|
||||
|
||||
# 验证结果
|
||||
echo "同步完成。验证结果:"
|
||||
echo "已同步技能:"
|
||||
ls "$SOURCE_DIR"
|
||||
echo ""
|
||||
echo "目标目录内容:"
|
||||
ls "$TARGET_DIR"
|
||||
|
||||
# 检查文件差异
|
||||
echo ""
|
||||
echo "检查关键文件差异:"
|
||||
for skill in $(ls "$SOURCE_DIR"); do
|
||||
if [ -f "$SOURCE_DIR/$skill/SKILL.md" ] && [ -f "$TARGET_DIR/$skill/SKILL.md" ]; then
|
||||
if ! diff -q "$SOURCE_DIR/$skill/SKILL.md" "$TARGET_DIR/$skill/SKILL.md" >/dev/null; then
|
||||
echo " ⚠️ $skill/SKILL.md 存在差异"
|
||||
else
|
||||
echo " ✓ $skill/SKILL.md 一致"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "同步完成!"
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### 1. 目标目录不存在
|
||||
```bash
|
||||
# 检查并创建目录
|
||||
if [ ! -d ~/.cursor/skills ]; then
|
||||
mkdir -p ~/.cursor/skills
|
||||
echo "已创建目录: ~/.cursor/skills"
|
||||
fi
|
||||
```
|
||||
|
||||
#### 2. 权限不足
|
||||
```bash
|
||||
# 检查权限
|
||||
ls -ld ~/.cursor
|
||||
# 如果需要,调整权限(谨慎操作)
|
||||
# chmod 755 ~/.cursor
|
||||
```
|
||||
|
||||
#### 3. 磁盘空间不足
|
||||
```bash
|
||||
# 检查可用空间
|
||||
df -h ~/.cursor
|
||||
```
|
||||
|
||||
#### 4. 文件冲突
|
||||
```bash
|
||||
# 备份现有文件后再同步
|
||||
BACKUP_DIR=~/.cursor/skills-backup-$(date +%Y%m%d)
|
||||
cp -R ~/.cursor/skills "$BACKUP_DIR"
|
||||
echo "已备份到: $BACKUP_DIR"
|
||||
```
|
||||
|
||||
### 回滚操作
|
||||
```bash
|
||||
# 从备份恢复
|
||||
BACKUP_DIR=~/.cursor/skills-backup-20250123
|
||||
if [ -d "$BACKUP_DIR" ]; then
|
||||
rm -rf ~/.cursor/skills
|
||||
cp -R "$BACKUP_DIR" ~/.cursor/skills
|
||||
echo "已从备份恢复: $BACKUP_DIR"
|
||||
fi
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 定期同步
|
||||
建议在以下时机同步技能:
|
||||
- 添加新技能后
|
||||
- 更新现有技能后
|
||||
- 定期维护时(如每周一次)
|
||||
|
||||
### 版本控制
|
||||
```bash
|
||||
# 将 OpenCode 配置目录加入版本控制
|
||||
cd ~/.config/opencode
|
||||
git status
|
||||
git add skill/
|
||||
git commit -m "feat: 更新技能配置"
|
||||
```
|
||||
|
||||
### 自动化脚本
|
||||
将同步脚本保存为 `~/.config/opencode/command/sync-skills.md` 作为 OpenCode 命令:
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: 同步 OpenCode 技能到 Cursor IDE
|
||||
---
|
||||
#!/bin/bash
|
||||
# 同步脚本内容...
|
||||
```
|
||||
|
||||
## 集成到 OpenCode Workflow
|
||||
|
||||
### 作为技能使用
|
||||
在 OpenCode 技能中引用此文档:
|
||||
```markdown
|
||||
## 相关文档
|
||||
- [技能同步指南](./skill-sync.md) - 同步 OpenCode 技能到 Cursor
|
||||
```
|
||||
|
||||
### 作为命令调用
|
||||
用户可直接请求:"同步技能到 Cursor" 或 "sync skills to cursor"
|
||||
|
||||
### 触发时机
|
||||
- 用户修改技能配置后
|
||||
- 安装新技能后
|
||||
- 系统配置变更时
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **备份重要数据**:同步前建议备份 Cursor 技能目录
|
||||
2. **网络环境**:如果使用网络同步,确保连接稳定
|
||||
3. **兼容性**:确保技能格式与 Cursor 兼容
|
||||
4. **测试验证**:同步后测试关键技能是否正常工作
|
||||
|
||||
## 故障排除
|
||||
|
||||
| 问题 | 可能原因 | 解决方案 |
|
||||
|------|----------|----------|
|
||||
| 同步后技能不生效 | Cursor 缓存 | 重启 Cursor IDE |
|
||||
| 文件权限错误 | 权限不足 | 检查目录权限 |
|
||||
| 目标目录只读 | 系统限制 | 以管理员权限运行 |
|
||||
| 部分技能缺失 | 同步中断 | 重新执行同步 |
|
||||
|
||||
## 更新记录
|
||||
|
||||
- **2026-01-23**:创建初始版本
|
||||
- **功能**:基础同步、错误处理、最佳实践
|
||||
|
||||
---
|
||||
|
||||
*该文档是 OpenCode 技能管理的一部分,用于维护技能配置的一致性。*
|
||||
Reference in New Issue
Block a user