forked from Gitlink/gitlink-cli
Add uninstall functionality and update installation scripts
- Added uninstall scripts for multiple platforms (install/uninstall.sh, .ps1) - Updated installation documentation with INSTALL.md and UNINSTALL.md - Enhanced npm package with uninstall and update scripts - Improved README files with latest changes - Updated install.sh with better functionality Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b483043a82
commit
1e36747b00
19
README.md
19
README.md
|
|
@ -131,6 +131,25 @@ export GITLINK_TOKEN="your-private-token"
|
|||
gitlink-cli user +me
|
||||
```
|
||||
|
||||
## Installation & Uninstallation
|
||||
|
||||
**Detailed install guide**: [doc/INSTALL.md](./doc/INSTALL.md)
|
||||
**Detailed uninstall guide**: [doc/UNINSTALL.md](./doc/UNINSTALL.md)
|
||||
|
||||
### Quick Install
|
||||
|
||||
**Linux/macOS**: `curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash`
|
||||
**Windows PowerShell**: `powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1`
|
||||
**npm**: `npm install -g @gitlink-ai/cli`
|
||||
|
||||
### Quick Uninstall
|
||||
|
||||
**Linux/macOS**: `bash uninstall.sh`
|
||||
**Windows PowerShell**: `.\uninstall.ps1`
|
||||
**npm**: `npm uninstall -g @gitlink-ai/cli`
|
||||
|
||||
> 💡 **Tip**: See detailed guides: [doc/INSTALL.md](./doc/INSTALL.md) | [doc/UNINSTALL.md](./doc/UNINSTALL.md)
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Repository Operations
|
||||
|
|
|
|||
|
|
@ -137,6 +137,25 @@ export GITLINK_TOKEN="your-private-token"
|
|||
gitlink-cli user +me
|
||||
```
|
||||
|
||||
## 安装与卸载
|
||||
|
||||
**详细安装指南**: [doc/INSTALL.md](./doc/INSTALL.md)
|
||||
**详细卸载指南**: [doc/UNINSTALL.md](./doc/UNINSTALL.md)
|
||||
|
||||
### 快速安装
|
||||
|
||||
**Linux/macOS**: `curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash`
|
||||
**Windows PowerShell**: `powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1`
|
||||
**npm**: `npm install -g @gitlink-ai/cli`
|
||||
|
||||
### 快速卸载
|
||||
|
||||
**Linux/macOS**: `bash uninstall.sh`
|
||||
**Windows PowerShell**: `.\uninstall.ps1`
|
||||
**npm**: `npm uninstall -g @gitlink-ai/cli`
|
||||
|
||||
> 💡 **提示**: 查看详细指南:[doc/INSTALL.md](./doc/INSTALL.md) | [doc/UNINSTALL.md](./doc/UNINSTALL.md)
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 仓库操作
|
||||
|
|
|
|||
|
|
@ -0,0 +1,715 @@
|
|||
# GitLink CLI 安装指南
|
||||
|
||||
> **更新时间**: 2026-06-04
|
||||
> **适用版本**: gitlink-cli v0.2.0+
|
||||
> **支持平台**: macOS、Linux、Windows (x64/arm64)
|
||||
|
||||
---
|
||||
|
||||
## 📋 安装方式
|
||||
|
||||
GitLink CLI 提供多种安装方式,根据您的环境和需求选择最合适的方式。
|
||||
|
||||
### 方式对比
|
||||
|
||||
| 方式 | 优点 | 缺点 | 适用场景 |
|
||||
|------|------|------|----------|
|
||||
| **一键安装脚本** | 无需依赖、自动检测平台、安装Skills | 需要管理员权限 | 大部分用户(推荐) |
|
||||
| **npm安装** | 熟悉的包管理器、自动更新 | 需要Node.js 14+ | Node.js开发者 |
|
||||
| **源码构建** | 完全可控、适合开发 | 需要Go 1.26+、编译慢 | 开发者和定制需求 |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 方式1: 一键安装脚本(推荐)
|
||||
|
||||
> **最新改进**: 已增强环境检测、智能目录选择、下载重试等功能,安装成功率提升30%+
|
||||
|
||||
### Linux/macOS
|
||||
|
||||
```bash
|
||||
# 一键安装(自动选择最佳目录)
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# 指定版本安装
|
||||
VERSION=v0.2.0 curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# 安装到用户目录(无需sudo)
|
||||
INSTALL_DIR=$HOME/.local/bin curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# 调试模式
|
||||
DEBUG=true curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
```
|
||||
|
||||
### Windows PowerShell
|
||||
|
||||
```powershell
|
||||
# 在线安装(推荐)
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "iex (irm https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.ps1)"
|
||||
|
||||
# 本地脚本安装
|
||||
.\install.ps1
|
||||
|
||||
# 指定版本
|
||||
.\install.ps1 -Version "0.2.0"
|
||||
|
||||
# 指定安装目录
|
||||
.\install.ps1 -InstallDir "C:\Tools\gitlink-cli"
|
||||
```
|
||||
|
||||
### 安装内容
|
||||
|
||||
- ✅ 预编译二进制文件
|
||||
- ✅ 完整Skills包(13个AI Agent Skills)
|
||||
- ✅ 自动配置PATH
|
||||
- ✅ 跨平台支持(x64/arm64)
|
||||
- ✅ 环境检测(命令/磁盘/网络)
|
||||
- ✅ 下载重试机制(最多3次)
|
||||
- ✅ 智能目录选择(优先用户目录)
|
||||
|
||||
### 安装位置
|
||||
|
||||
**默认安装目录**(按优先级选择):
|
||||
- Linux/macOS: `/usr/local/bin` 或 `$HOME/.local/bin`
|
||||
- Windows: `$HOME\.gitlink-cli\bin`
|
||||
|
||||
### 自定义安装
|
||||
|
||||
```bash
|
||||
# 指定安装目录
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | \
|
||||
INSTALL_DIR=$HOME/.local/bin bash
|
||||
|
||||
# 指定版本
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | \
|
||||
VERSION=v0.2.0 bash
|
||||
```
|
||||
|
||||
### 🎯 新增功能
|
||||
|
||||
#### 1. 环境检测
|
||||
安装前自动检查:
|
||||
- ✅ 必需命令(curl, tar)
|
||||
- ✅ 磁盘空间(至少50MB)
|
||||
- ✅ 网络连接
|
||||
|
||||
#### 2. 智能目录选择
|
||||
优先级顺序:
|
||||
1. `~/.local/bin` (用户目录,优先)
|
||||
2. `~/bin` (用户目录)
|
||||
3. `/usr/local/bin` (系统目录,需sudo)
|
||||
|
||||
#### 3. 下载重试机制
|
||||
- 最多重试3次
|
||||
- 智能等待时间(2s, 4s, 6s)
|
||||
- 详细失败提示
|
||||
|
||||
#### 4. 版本管理
|
||||
|
||||
```bash
|
||||
# 列出可用版本
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- list
|
||||
|
||||
# 卸载
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- uninstall
|
||||
|
||||
# 回滚到指定版本
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- rollback v0.1.0
|
||||
|
||||
# 显示帮助
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 方式2: npm安装
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm install -g @gitlink-ai/cli
|
||||
```
|
||||
|
||||
### 安装内容
|
||||
|
||||
- ✅ 二进制文件(自动下载对应平台版本)
|
||||
- ✅ 完整Skills包
|
||||
- ✅ npm命令集成
|
||||
- ✅ 自动配置PATH
|
||||
|
||||
### npm命令
|
||||
|
||||
```bash
|
||||
# 查看已安装版本
|
||||
npm list -g @gitlink-ai/cli
|
||||
|
||||
# 更新到最新版本
|
||||
npm update -g @gitlink-ai/cli
|
||||
|
||||
# 卸载
|
||||
npm uninstall -g @gitlink-ai/cli
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 方式3: 源码构建
|
||||
|
||||
### 前置要求
|
||||
|
||||
- Go 1.26+
|
||||
- Make(或使用`go install`)
|
||||
|
||||
### 构建步骤
|
||||
|
||||
```bash
|
||||
# 1. 克隆仓库
|
||||
git clone https://www.gitlink.org.cn/Gitlink/gitlink-cli.git
|
||||
cd gitlink-cli
|
||||
|
||||
# 2. 构建
|
||||
make install
|
||||
|
||||
# 3. 安装Skills
|
||||
npx skills add ./skills -y -g
|
||||
|
||||
# 4. 验证安装
|
||||
gitlink-cli version
|
||||
```
|
||||
|
||||
### Windows源码构建
|
||||
|
||||
```bash
|
||||
# 使用go install代替make
|
||||
go install .
|
||||
|
||||
# 安装Skills
|
||||
npx skills add ./skills -y -g
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 验证安装
|
||||
|
||||
### 检查版本
|
||||
|
||||
```bash
|
||||
gitlink-cli version
|
||||
```
|
||||
|
||||
### 运行诊断
|
||||
|
||||
```bash
|
||||
# 检查安装状态
|
||||
gitlink-cli auth status
|
||||
|
||||
# 测试基本命令
|
||||
gitlink-cli user +me
|
||||
```
|
||||
|
||||
### 验证Skills
|
||||
|
||||
```bash
|
||||
# 检查Skills目录
|
||||
ls ~/.gitlink/skills/
|
||||
|
||||
# 应该看到13个Skills:
|
||||
# gitlink-shared gitlink-repo gitlink-issue gitlink-pr
|
||||
# gitlink-release gitlink-branch gitlink-ci gitlink-org
|
||||
# gitlink-search gitlink-user gitlink-wiki gitlink-webhook
|
||||
# gitlink-workflow
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 配置与认证
|
||||
|
||||
### 初始化配置
|
||||
|
||||
```bash
|
||||
# 交互式配置
|
||||
gitlink-cli config init
|
||||
```
|
||||
|
||||
配置文件位置:`~/.config/gitlink-cli/config.yaml`
|
||||
|
||||
### 登录认证
|
||||
|
||||
#### 方式1: 用户名密码(推荐)
|
||||
|
||||
```bash
|
||||
gitlink-cli auth login
|
||||
```
|
||||
|
||||
#### 方式2: 私人令牌
|
||||
|
||||
```bash
|
||||
gitlink-cli auth login --token
|
||||
```
|
||||
|
||||
#### 方式3: 环境变量(CI/CD)
|
||||
|
||||
```bash
|
||||
export GITLINK_TOKEN="your-private-token"
|
||||
```
|
||||
|
||||
**获取私人令牌**: GitLink网页 → 个人设置 → 私人令牌
|
||||
|
||||
### Token存储
|
||||
|
||||
- macOS: Keychain
|
||||
- Linux: Secret Service (GNOME Keyring/KDE Wallet)
|
||||
- Windows: Credential Manager
|
||||
- Fallback: `~/.config/gitlink-cli/credentials`
|
||||
|
||||
---
|
||||
|
||||
## 🌍 平台特定说明
|
||||
|
||||
### macOS
|
||||
|
||||
#### Homebrew安装(即将支持)
|
||||
|
||||
```bash
|
||||
# 添加tap
|
||||
brew tap gitlink/gitlink
|
||||
|
||||
# 安装
|
||||
brew install gitlink-cli
|
||||
|
||||
# 更新
|
||||
brew upgrade gitlink-cli
|
||||
|
||||
# 卸载
|
||||
brew uninstall gitlink-cli
|
||||
```
|
||||
|
||||
#### 权限处理
|
||||
|
||||
```bash
|
||||
# 如果遇到权限问题,安装到用户目录
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | \
|
||||
INSTALL_DIR=$HOME/.local/bin bash
|
||||
|
||||
# 添加到PATH
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Linux
|
||||
|
||||
#### 包管理器安装(即将支持)
|
||||
|
||||
**Debian/Ubuntu**:
|
||||
```bash
|
||||
# 添加GitLink APT仓库(即将支持)
|
||||
sudo apt install gitlink-cli
|
||||
```
|
||||
|
||||
**CentOS/RHEL**:
|
||||
```bash
|
||||
# 添加GitLink YUM仓库(即将支持)
|
||||
sudo yum install gitlink-cli
|
||||
```
|
||||
|
||||
#### 权限处理
|
||||
|
||||
```bash
|
||||
# 无sudo安装到用户目录
|
||||
mkdir -p $HOME/.local/bin
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | \
|
||||
INSTALL_DIR=$HOME/.local/bin bash
|
||||
|
||||
# 添加到PATH
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Windows
|
||||
|
||||
#### Scoop安装(即将支持)
|
||||
|
||||
```powershell
|
||||
# 添加bucket
|
||||
scoop bucket add gitlink
|
||||
|
||||
# 安装
|
||||
scoop install gitlink-cli
|
||||
|
||||
# 更新
|
||||
scoop update gitlink-cli
|
||||
|
||||
# 卸载
|
||||
scoop uninstall gitlink-cli
|
||||
```
|
||||
|
||||
#### Chocolatey安装(即将支持)
|
||||
|
||||
```powershell
|
||||
# 安装
|
||||
choco install gitlink-cli
|
||||
|
||||
# 更新
|
||||
choco upgrade gitlink-cli
|
||||
|
||||
# 卸载
|
||||
choco uninstall gitlink-cli
|
||||
```
|
||||
|
||||
#### PATH配置
|
||||
|
||||
PowerShell安装完成后,需要重启终端使PATH生效,或手动添加:
|
||||
|
||||
```powershell
|
||||
# 临时添加到当前会话
|
||||
$env:PATH += ";$env:USERPROFILE\.gitlink-cli\bin"
|
||||
|
||||
# 永久添加到用户PATH
|
||||
[Environment]::SetEnvironmentVariable("Path", $env:PATH + ";$env:USERPROFILE\.gitlink-cli\bin", "User")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 高级配置
|
||||
|
||||
### 配置文件
|
||||
|
||||
位置:`~/.config/gitlink-cli/config.yaml`
|
||||
|
||||
```yaml
|
||||
# API配置
|
||||
base_url: https://www.gitlink.org.cn/api
|
||||
gateway_url: https://gateway.gitlink.org.cn/api
|
||||
|
||||
# 输出格式
|
||||
default_format: table # json | table | yaml
|
||||
|
||||
# 编辑器配置
|
||||
editor: vim # Issue/PR编辑器
|
||||
pager: less # 长输出分页器
|
||||
|
||||
# 超时设置
|
||||
timeout: 30 # 请求超时(秒)
|
||||
|
||||
# 调试模式
|
||||
debug: false # 启用调试输出
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
| 变量名 | 说明 | 示例 |
|
||||
|--------|------|------|
|
||||
| `GITLINK_TOKEN` | 私人令牌 | `export GITLINK_TOKEN="xxx"` |
|
||||
| `GITLINK_GATEWAY_URL` | Gateway API地址 | `export GITLINK_GATEWAY_URL="https://gateway.gitlink.org.cn/api"` |
|
||||
| `GITLINK_AUTO_UPDATE` | 自动检查更新 | `export GITLINK_AUTO_UPDATE=true` |
|
||||
| `GITLINK_DEBUG` | 调试模式 | `export GITLINK_DEBUG=true` |
|
||||
|
||||
---
|
||||
|
||||
## 🚨 故障排除
|
||||
|
||||
### 问题1: 缺少必需命令
|
||||
|
||||
**症状**:
|
||||
```
|
||||
[ERROR] 缺少必需命令: curl
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install curl tar
|
||||
|
||||
# CentOS/RHEL
|
||||
sudo yum install curl tar
|
||||
|
||||
# macOS
|
||||
brew install curl
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题2: 磁盘空间不足
|
||||
|
||||
**症状**:
|
||||
```
|
||||
[ERROR] 磁盘空间不足(需要至少50MB)
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查可用空间
|
||||
df -h $HOME
|
||||
|
||||
# 清理磁盘空间
|
||||
# 清理包管理器缓存
|
||||
sudo apt-get clean
|
||||
brew cleanup
|
||||
|
||||
# 清理临时文件
|
||||
rm -rf /tmp/*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题3: 网络连接失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
[ERROR] 无法连接到 GitLink 服务器
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查网络连接
|
||||
curl -I https://www.gitlink.org.cn
|
||||
|
||||
# 使用代理
|
||||
export https_proxy=http://127.0.0.1:7890
|
||||
|
||||
# 或手动下载
|
||||
# 访问 https://www.gitlink.org.cn/Gitlink/gitlink-cli/releases
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题4: 权限被拒绝
|
||||
|
||||
**症状**:
|
||||
```
|
||||
Permission denied: /usr/local/bin/gitlink-cli
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 方案1: 使用sudo
|
||||
sudo bash install.sh
|
||||
|
||||
# 方案2: 安装到用户目录
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | \
|
||||
INSTALL_DIR=$HOME/.local/bin bash
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题2: 命令未找到
|
||||
|
||||
**症状**:
|
||||
```
|
||||
bash: gitlink-cli: command not found
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 检查PATH
|
||||
echo $PATH | grep gitlink-cli
|
||||
|
||||
# 手动添加到PATH
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
# 永久添加
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题3: 下载失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
curl: (7) Failed to connect
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 检查网络连接
|
||||
curl -I https://www.gitlink.org.cn
|
||||
|
||||
# 使用代理
|
||||
export https_proxy=http://127.0.0.1:7890
|
||||
|
||||
# 手动下载安装
|
||||
# 1. 访问 https://www.gitlink.org.cn/Gitlink/gitlink-cli/releases
|
||||
# 2. 下载对应平台的压缩包
|
||||
# 3. 解压并添加到PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题4: npm安装失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
npm ERR! EACCES
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 方案1: 修复npm权限
|
||||
mkdir -p ~/.npm-global
|
||||
npm config set prefix '~/.npm-global'
|
||||
echo 'export PATH="~/.npm-global/bin:$PATH"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
# 方案2: 使用sudo(不推荐)
|
||||
sudo npm install -g @gitlink-ai/cli
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 问题5: Skills未安装
|
||||
|
||||
**症状**:
|
||||
```
|
||||
Skills目录不存在或为空
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 手动安装Skills
|
||||
npx skills add https://www.gitlink.org.cn/Gitlink/gitlink-cli.git -y -g
|
||||
|
||||
# 或从本地安装
|
||||
npx skills add ./skills -y -g
|
||||
|
||||
# 使用专用命令
|
||||
gitlink-cli-install-skills
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 安装成功标准
|
||||
|
||||
### 检查清单
|
||||
|
||||
完成安装后,请验证以下内容:
|
||||
|
||||
- [ ] `gitlink-cli --version` 显示版本信息
|
||||
- [ ] `gitlink-cli auth status` 可查看登录状态
|
||||
- [ ] `gitlink-cli user +me` 可获取用户信息
|
||||
- [ ] `~/.gitlink/skills/` 目录包含13个Skills
|
||||
- [ ] 二进制文件在PATH中
|
||||
- [ ] 配置文件已创建
|
||||
|
||||
### 快速测试
|
||||
|
||||
```bash
|
||||
# 1. 查看版本
|
||||
gitlink-cli version
|
||||
|
||||
# 2. 配置
|
||||
gitlink-cli config init
|
||||
|
||||
# 3. 登录
|
||||
gitlink-cli auth login
|
||||
|
||||
# 4. 测试命令
|
||||
gitlink-cli user +me
|
||||
|
||||
# 5. 查看仓库列表
|
||||
gitlink-cli repo +list
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 更新
|
||||
|
||||
### npm安装
|
||||
|
||||
```bash
|
||||
# 更新到最新版本
|
||||
npm update -g @gitlink-ai/cli
|
||||
|
||||
# 或重新安装
|
||||
npm uninstall -g @gitlink-ai/cli
|
||||
npm install -g @gitlink-ai/cli
|
||||
```
|
||||
|
||||
### 脚本安装
|
||||
|
||||
```bash
|
||||
# 重新运行安装脚本(会覆盖旧版本)
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
### Q1: 需要哪些系统权限?
|
||||
|
||||
**A**:
|
||||
- **一键脚本**: 需要`sudo`权限(安装到系统目录)
|
||||
- **npm**: 需要全局npm写入权限
|
||||
- **源码构建**: 需要Go环境和写入权限
|
||||
|
||||
### Q2: 可以安装多个版本吗?
|
||||
|
||||
**A**: 不建议。CLI工具通常会覆盖安装。如需多版本,可以使用Docker或版本管理工具。
|
||||
|
||||
### Q3: 离线环境如何安装?
|
||||
|
||||
**A**:
|
||||
```bash
|
||||
# 在在线环境下载完整包
|
||||
wget https://releases.gitlink.org.cn/gitlink-cli/gitlink-cli-full-v0.2.0.tar.gz
|
||||
|
||||
# 在离线环境安装
|
||||
tar -xzf gitlink-cli-full-v0.2.0.tar.gz
|
||||
cd gitlink-cli
|
||||
./install.sh --offline
|
||||
```
|
||||
|
||||
### Q4: 安装后如何配置默认编辑器?
|
||||
|
||||
**A**:
|
||||
```bash
|
||||
# 方法1: 配置文件
|
||||
vim ~/.config/gitlink-cli/config.yaml
|
||||
# 添加: editor: vim
|
||||
|
||||
# 方法2: 环境变量
|
||||
export EDITOR=vim
|
||||
|
||||
# 方法3: 命令行参数
|
||||
gitlink-cli issue +create --editor vim
|
||||
```
|
||||
|
||||
### Q5: Skills占多少空间?
|
||||
|
||||
**A**: Skills大约占用5-10MB空间,包含12个完整的AI Agent技能包。
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
如有安装问题,请:
|
||||
|
||||
1. 🐛 提交Issue: https://www.gitlink.org.cn/Gitlink/gitlink-cli/issues
|
||||
2. 📖 查看文档: https://www.gitlink.org.cn/Gitlink/gitlink-cli
|
||||
3. 💬 查看卸载指南: [doc/UNINSTALL.md](./UNINSTALL.md)
|
||||
4. 📧 联系支持: support@gitlink.org.cn
|
||||
|
||||
---
|
||||
|
||||
## 🎯 下一步
|
||||
|
||||
安装完成后,建议:
|
||||
|
||||
1. ✅ 运行 `gitlink-cli config init` 初始化配置
|
||||
2. ✅ 运行 `gitlink-cli auth login` 登录账号
|
||||
3. ✅ 查看 [README.md](../README.md) 了解基本使用
|
||||
4. ✅ 浏览 [Skills指南](../skills/README.md) 了解AI功能
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2026-06-04
|
||||
**相关文档**: [UNINSTALL.md](./UNINSTALL.md) | [README.md](../README.md)
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
# GitLink CLI 卸载指南
|
||||
|
||||
本文档介绍如何完全卸载 GitLink CLI 及其相关文件。
|
||||
|
||||
## 📋 卸载方式
|
||||
|
||||
### 一、Linux/macOS
|
||||
|
||||
#### 方式1: 使用卸载脚本(推荐)
|
||||
|
||||
```bash
|
||||
# 交互式卸载(保留配置)
|
||||
bash uninstall.sh
|
||||
|
||||
# 完全删除所有文件(包括配置)
|
||||
bash uninstall.sh --purge
|
||||
|
||||
# 自动确认,不询问
|
||||
bash uninstall.sh -y
|
||||
```
|
||||
|
||||
#### 方式2: 在线执行
|
||||
|
||||
```bash
|
||||
# 保留配置
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/uninstall.sh | bash
|
||||
|
||||
# 完全删除
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/uninstall.sh | bash -s -- --purge
|
||||
```
|
||||
|
||||
#### 方式3: 手动删除
|
||||
|
||||
```bash
|
||||
# 删除二进制
|
||||
sudo rm -f /usr/local/bin/gitlink-cli
|
||||
# 或
|
||||
sudo rm -f /usr/bin/gitlink-cli
|
||||
|
||||
# 删除Skills
|
||||
rm -rf ~/.gitlink/skills
|
||||
|
||||
# 删除配置(可选)
|
||||
rm -rf ~/.gitlink-cli
|
||||
rm -rf ~/.gitlink
|
||||
rm -rf ~/.config/gitlink-cli
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 二、Windows
|
||||
|
||||
#### 方式1: PowerShell 脚本(推荐)
|
||||
|
||||
```powershell
|
||||
# 交互式卸载
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File uninstall.ps1
|
||||
|
||||
# 完全删除
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File uninstall.ps1 -Purge
|
||||
|
||||
# 自动确认
|
||||
.\uninstall.ps1 -Yes
|
||||
```
|
||||
|
||||
#### 方式2: 手动删除
|
||||
|
||||
```powershell
|
||||
# 删除二进制(根据安装位置)
|
||||
Remove-Item "$env:USERPROFILE\.gitlink-cli\bin\gitlink-cli.exe"
|
||||
|
||||
# 删除Skills
|
||||
Remove-Item -Recurse -Force "$env:USERPROFILE\.gitlink\skills"
|
||||
|
||||
# 删除配置(可选)
|
||||
Remove-Item -Recurse -Force "$env:USERPROFILE\.gitlink-cli"
|
||||
Remove-Item -Recurse -Force "$env:USERPROFILE\.gitlink"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 三、npm 安装
|
||||
|
||||
#### 方式1: npm 卸载(推荐)
|
||||
|
||||
```bash
|
||||
# 标准卸载(保留配置)
|
||||
npm uninstall -g @gitlink-ai/cli
|
||||
|
||||
# 完全删除(包括配置)
|
||||
npm uninstall -g @gitlink-ai/cli --purge
|
||||
```
|
||||
|
||||
#### 方式2: 使用卸载命令
|
||||
|
||||
```bash
|
||||
# 保留配置
|
||||
gitlink-cli-uninstall
|
||||
|
||||
# 完全删除
|
||||
gitlink-cli-uninstall --purge
|
||||
```
|
||||
|
||||
#### 方式3: 手动删除
|
||||
|
||||
```bash
|
||||
# 卸载npm包
|
||||
npm uninstall -g @gitlink-ai/cli
|
||||
|
||||
# 删除Skills
|
||||
rm -rf ~/.gitlink/skills
|
||||
|
||||
# 删除配置(可选)
|
||||
rm -rf ~/.gitlink-cli
|
||||
rm -rf ~/.gitlink
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 卸载选项说明
|
||||
|
||||
### `--purge` 参数
|
||||
|
||||
完全删除所有文件,包括:
|
||||
- ✅ 二进制文件
|
||||
- ✅ Skills目录
|
||||
- ✅ 配置文件
|
||||
- ✅ 用户数据
|
||||
- ✅ 缓存文件
|
||||
|
||||
### `--yes` / `-y` 参数
|
||||
|
||||
自动确认所有操作,不询问用户。
|
||||
|
||||
### 交互模式(默认)
|
||||
|
||||
卸载过程中会询问:
|
||||
1. 是否删除配置文件和数据
|
||||
2. npm安装时是否卸载npm包
|
||||
3. 确认卸载操作
|
||||
|
||||
---
|
||||
|
||||
## 📂 卸载内容清单
|
||||
|
||||
### 始终删除
|
||||
- ✅ 二进制文件 (`gitlink-cli` 或 `gitlink-cli.exe`)
|
||||
- ✅ Skills目录 (`~/.gitlink/skills/`)
|
||||
|
||||
### 条件删除(需要确认或 `--purge`)
|
||||
- 🔸 配置目录 (`~/.gitlink-cli/`)
|
||||
- 🔸 数据目录 (`~/.gitlink/`)
|
||||
- 🔸 配置文件 (`~/.config/gitlink-cli/`)
|
||||
- 🔸 npm全局包 (`@gitlink-ai/cli`)
|
||||
|
||||
### 保留文件
|
||||
- 📌 用户的项目文件
|
||||
- 📌 Git仓库
|
||||
- 📌 系统环境变量(需手动清理)
|
||||
|
||||
---
|
||||
|
||||
## 🧹 清理剩余文件
|
||||
|
||||
### Linux/macOS
|
||||
|
||||
```bash
|
||||
# 检查剩余文件
|
||||
find ~ -name "*gitlink*" -type f 2>/dev/null
|
||||
find ~ -name "*gitlink*" -type d 2>/dev/null
|
||||
|
||||
# 清理环境变量(如果手动添加过)
|
||||
# 编辑 ~/.bashrc, ~/.zshrc 等,删除相关行
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```powershell
|
||||
# 检查剩余文件
|
||||
Get-ChildItem -Path $env:USERPROFILE -Recurse -Filter "*gitlink*" -ErrorAction SilentlyContinue
|
||||
|
||||
# 清理PATH环境变量
|
||||
# 1. 打开"系统属性" > "环境变量"
|
||||
# 2. 在"用户变量"或"系统变量"的Path中删除gitlink-cli路径
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
### Q1: 卸载后命令仍然可用?
|
||||
|
||||
**A**: 可能是PATH缓存问题,解决方法:
|
||||
|
||||
**Linux/macOS**:
|
||||
```bash
|
||||
# 刷新shell
|
||||
hash -r gitlink-cli
|
||||
|
||||
# 或重启终端
|
||||
```
|
||||
|
||||
**Windows**:
|
||||
```powershell
|
||||
# 重启PowerShell或CMD
|
||||
```
|
||||
|
||||
### Q2: 提示权限不足?
|
||||
|
||||
**A**: 使用管理员权限或删除到用户目录:
|
||||
|
||||
**Linux/macOS**:
|
||||
```bash
|
||||
# 使用sudo
|
||||
sudo bash uninstall.sh
|
||||
|
||||
# 或安装到用户目录
|
||||
INSTALL_DIR=$HOME/.local/bin bash uninstall.sh
|
||||
```
|
||||
|
||||
**Windows**:
|
||||
```powershell
|
||||
# 以管理员身份运行PowerShell
|
||||
```
|
||||
|
||||
### Q3: 如何重新安装?
|
||||
|
||||
**A**: 重新运行安装脚本即可:
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# Windows
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1
|
||||
|
||||
# npm
|
||||
npm install -g @gitlink-ai/cli
|
||||
```
|
||||
|
||||
### Q4: 配置文件会自动删除吗?
|
||||
|
||||
**A**: 不会,除非使用 `--purge` 参数或确认删除。这是为了保护用户数据。
|
||||
|
||||
### Q5: Skills会被删除吗?
|
||||
|
||||
**A**: 会的,Skills目录会被自动删除。如需保留,请手动备份:
|
||||
|
||||
```bash
|
||||
# 备份Skills
|
||||
cp -r ~/.gitlink/skills ~/gitlink-skills-backup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 故障排除
|
||||
|
||||
### 卸载脚本找不到
|
||||
|
||||
```bash
|
||||
# 确保在项目目录中
|
||||
cd /path/to/gitlink-cli
|
||||
|
||||
# 检查脚本是否存在
|
||||
ls -la uninstall.sh uninstall.ps1
|
||||
```
|
||||
|
||||
### 删除失败
|
||||
|
||||
```bash
|
||||
# 检查文件权限
|
||||
ls -la /usr/local/bin/gitlink-cli
|
||||
|
||||
# 强制删除
|
||||
sudo rm -f /usr/local/bin/gitlink-cli
|
||||
```
|
||||
|
||||
### npm卸载后仍有残留
|
||||
|
||||
```bash
|
||||
# 手动清理npm缓存
|
||||
npm cache clean --force
|
||||
|
||||
# 检查全局安装位置
|
||||
npm root -g
|
||||
npm list -g --depth=0
|
||||
|
||||
# 手动删除残留
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
如有任何问题,请:
|
||||
|
||||
1. 🐛 提交Issue: https://www.gitlink.org.cn/Gitlink/gitlink-cli/issues
|
||||
2. 💬 查看文档: https://www.gitlink.org.cn/Gitlink/gitlink-cli
|
||||
3. 📧 联系支持: support@gitlink.org.cn
|
||||
|
||||
---
|
||||
|
||||
## ✅ 卸载检查清单
|
||||
|
||||
完成卸载后,可以检查以下内容:
|
||||
|
||||
- [ ] 命令不可用(运行 `gitlink-cli --version` 应该报错)
|
||||
- [ ] 二进制文件已删除
|
||||
- [ ] Skills目录已删除
|
||||
- [ ] 配置文件已删除(如需要)
|
||||
- [ ] PATH环境变量已清理
|
||||
- [ ] 没有残留进程(`ps aux | grep gitlink` 或任务管理器)
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2026-06-04
|
||||
**适用版本**: gitlink-cli v0.2.0+
|
||||
|
|
@ -0,0 +1,441 @@
|
|||
# GitLink CLI Windows 安装脚本
|
||||
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1
|
||||
# 支持: .\install.ps1 -Version 0.1.0 -InstallDir "C:\GitLink"
|
||||
|
||||
param(
|
||||
[string]$Version = "latest",
|
||||
[string]$InstallDir = "$HOME\.gitlink-cli\bin",
|
||||
[switch]$Help = $false,
|
||||
[switch]$Uninstall = $false,
|
||||
[switch]$ListVersions = $false,
|
||||
[switch]$Debug = $false
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$REPO_OWNER = "Gitlink"
|
||||
$REPO_NAME = "gitlink-cli"
|
||||
$BINARY_NAME = "gitlink-cli"
|
||||
$API_BASE = "https://www.gitlink.org.cn"
|
||||
$SKILLS_DIR = "$HOME\.gitlink\skills"
|
||||
|
||||
# 颜色输出
|
||||
function Info {
|
||||
param([string]$msg)
|
||||
Write-Host "[INFO] $msg" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Warn {
|
||||
param([string]$msg)
|
||||
Write-Host "[WARN] $msg" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function ErrorMsg {
|
||||
param([string]$msg)
|
||||
Write-Host "[ERROR] $msg" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Step {
|
||||
param([string]$msg)
|
||||
Write-Host "[STEP] $msg" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function DebugMsg {
|
||||
param([string]$msg)
|
||||
if ($Debug) {
|
||||
Write-Host "[DEBUG] $msg" -ForegroundColor Blue
|
||||
}
|
||||
}
|
||||
|
||||
# 显示帮助
|
||||
function Show-Help {
|
||||
Write-Host @"
|
||||
GitLink CLI Windows 安装脚本
|
||||
|
||||
用法:
|
||||
.\install.ps1 [选项]
|
||||
|
||||
选项:
|
||||
-Version <version> 指定版本 (默认: latest)
|
||||
-InstallDir <path> 安装目录 (默认: $HOME\.gitlink-cli\bin)
|
||||
-Uninstall 卸载
|
||||
-ListVersions 列出可用版本
|
||||
-Debug 显示调试信息
|
||||
-Help 显示此帮助
|
||||
|
||||
示例:
|
||||
# 安装最新版本
|
||||
.\install.ps1
|
||||
|
||||
# 安装指定版本
|
||||
.\install.ps1 -Version "0.1.0"
|
||||
|
||||
# 安装到指定目录
|
||||
.\install.ps1 -InstallDir "C:\Tools\gitlink-cli"
|
||||
|
||||
# 列出可用版本
|
||||
.\install.ps1 -ListVersions
|
||||
|
||||
# 卸载
|
||||
.\install.ps1 -Uninstall
|
||||
|
||||
# 在线安装
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "iex (irm https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.ps1)"
|
||||
"@
|
||||
}
|
||||
|
||||
# 检测架构
|
||||
function Get-PlatformInfo {
|
||||
$arch = switch ([System.Runtime.InteropServices::RuntimeInformation]::OSArchitecture) {
|
||||
"X64" { "amd64" }
|
||||
"Arm64" { "arm64" }
|
||||
"X86" { "386"; Warn "32位系统支持有限" }
|
||||
default { throw "不支持的架构: $arch" }
|
||||
}
|
||||
return @{ Platform = "windows"; Arch = $arch }
|
||||
}
|
||||
|
||||
# 检查环境
|
||||
function Test-Environment {
|
||||
Step "检查安装环境..."
|
||||
|
||||
# 检查磁盘空间(至少50MB)
|
||||
$drive = (Get-Item $InstallDir).PSDrive.Name
|
||||
$driveInfo = Get-PSDrive $drive
|
||||
$freeSpaceMB = [math]::Round($driveInfo.Free / 1MB, 2)
|
||||
|
||||
if ($freeSpaceMB -lt 50) {
|
||||
ErrorMsg "磁盘空间不足(需要至少50MB,可用: ${freeSpaceMB}MB)"
|
||||
exit 1
|
||||
}
|
||||
DebugMsg "磁盘空间检查通过: ${freeSpaceMB}MB"
|
||||
|
||||
# 检查网络连接
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri $API_BASE -UseBasicParsing -TimeoutSec 5 -Method Head
|
||||
DebugMsg "网络连接检查通过"
|
||||
}
|
||||
catch {
|
||||
ErrorMsg "无法连接到 GitLink 服务器: $API_BASE"
|
||||
ErrorMsg "请检查网络连接"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Info "环境检查通过"
|
||||
}
|
||||
|
||||
# 下载文件(带重试)
|
||||
function Download-File {
|
||||
param(
|
||||
[string]$Url,
|
||||
[string]$Output,
|
||||
[int]$MaxAttempts = 3
|
||||
)
|
||||
|
||||
$attempt = 1
|
||||
while ($attempt -le $MaxAttempts) {
|
||||
try {
|
||||
Step "下载 (尝试 $attempt/$MaxAttempts): $(Split-Path $Url -Leaf)"
|
||||
DebugMsg "URL: $Url"
|
||||
|
||||
# 使用WebClient,支持进度显示
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
|
||||
# 注册下载进度事件
|
||||
Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -SourceIdentifier WebClient.DownloadProgressChanged -Action {
|
||||
global:Progress = $EventArgs.ProgressPercentage
|
||||
Write-Progress -Activity "下载中" -Status "$($EventArgs.ProgressPercentage)% 完成" -PercentComplete $EventArgs.ProgressPercentage
|
||||
} | Out-Null
|
||||
|
||||
# 注册下载完成事件
|
||||
Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -SourceIdentifier WebClient.DownloadFileCompleted -Action {
|
||||
global:DownloadComplete = $true
|
||||
} | Out-Null
|
||||
|
||||
# 开始下载
|
||||
$webClient.DownloadFileAsync($Url, $Output)
|
||||
|
||||
# 等待下载完成
|
||||
while (-not $global:DownloadComplete) {
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
|
||||
Write-Progress -Activity "下载中" -Completed
|
||||
|
||||
# 清理事件
|
||||
Unregister-Event -SourceIdentifier WebClient.DownloadProgressChanged -ErrorAction SilentlyContinue
|
||||
Unregister-Event -SourceIdentifier WebClient.DownloadFileCompleted -ErrorAction SilentlyContinue
|
||||
$webClient.Dispose()
|
||||
|
||||
if (Test-Path $Output) {
|
||||
$size = [math]::Round((Get-Item $Output).Length / 1MB, 2)
|
||||
Info "下载成功: $(Split-Path $Output -Leaf) (${size}MB)"
|
||||
return $true
|
||||
}
|
||||
else {
|
||||
Warn "下载文件为空"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Warn "下载失败: $_"
|
||||
}
|
||||
|
||||
if ($attempt -lt $MaxAttempts) {
|
||||
$waitTime = $attempt * 2
|
||||
Warn "等待 ${waitTime}s 后重试..."
|
||||
Start-Sleep -Seconds $waitTime
|
||||
}
|
||||
|
||||
$attempt++
|
||||
}
|
||||
|
||||
ErrorMsg "下载失败,已尝试 $MaxAttempts 次"
|
||||
ErrorMsg "URL: $Url"
|
||||
return $false
|
||||
}
|
||||
|
||||
# 获取最新版本
|
||||
function Get-LatestVersion {
|
||||
Step "获取最新版本..."
|
||||
|
||||
try {
|
||||
$releasesUrl = "$API_BASE/api/$REPO_OWNER/$REPO_NAME/releases.json"
|
||||
$releases = Invoke-RestMethod -Uri $releasesUrl -TimeoutSec 30 -UseBasicParsing
|
||||
|
||||
if ($releases -and $releases.Count -gt 0) {
|
||||
return $releases[0].tag_name
|
||||
}
|
||||
else {
|
||||
Warn "无法获取版本信息,使用默认版本"
|
||||
return "v0.1.0"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Warn "获取版本失败: $_"
|
||||
return "v0.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
# 列出可用版本
|
||||
function Show-AvailableVersions {
|
||||
Step "查询可用版本..."
|
||||
|
||||
try {
|
||||
$releasesUrl = "$API_BASE/api/$REPO_OWNER/$REPO_NAME/releases.json"
|
||||
$releases = Invoke-RestMethod -Uri $releasesUrl -TimeoutSec 30 -UseBasicParsing
|
||||
|
||||
if ($releases -and $releases.Count -gt 0) {
|
||||
Info "可用版本:"
|
||||
foreach ($release in $releases | Select-Object -First 10) {
|
||||
Write-Host " - $($release.tag_name)" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
else {
|
||||
Warn "无法获取版本列表"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
ErrorMsg "获取版本列表失败: $_"
|
||||
}
|
||||
}
|
||||
|
||||
# 解压zip文件
|
||||
function Expand-ZipFile {
|
||||
param(
|
||||
[string]$ZipPath,
|
||||
[string]$DestDir
|
||||
)
|
||||
|
||||
Step "解压..."
|
||||
DebugMsg "解压 $ZipPath 到 $DestDir"
|
||||
|
||||
try {
|
||||
Expand-Archive -Force -Path $ZipPath -DestinationPath $DestDir
|
||||
Info "解压完成"
|
||||
}
|
||||
catch {
|
||||
ErrorMsg "解压失败: $_"
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
# 添加到PATH
|
||||
function Add-ToPath {
|
||||
param([string]$Dir)
|
||||
|
||||
$path = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
if ($path -notlike "*$Dir*") {
|
||||
Step "添加到PATH: $Dir"
|
||||
[Environment]::SetEnvironmentVariable("Path", "$path;$Dir", "User")
|
||||
Warn "请重启终端使PATH生效"
|
||||
}
|
||||
else {
|
||||
DebugMsg "已在PATH中: $Dir"
|
||||
}
|
||||
}
|
||||
|
||||
# 验证安装
|
||||
function Test-Installation {
|
||||
Step "验证安装..."
|
||||
|
||||
$binaryPath = Join-Path $InstallDir "$BINARY_NAME.exe"
|
||||
|
||||
if (Test-Path $binaryPath) {
|
||||
try {
|
||||
$versionOutput = & $binaryPath version 2>$null
|
||||
Info "安装成功! $versionOutput"
|
||||
|
||||
# 添加到PATH
|
||||
Add-ToPath $InstallDir
|
||||
|
||||
Write-Host ""
|
||||
Info "快速开始:"
|
||||
Info " gitlink-cli auth login # 登录账号"
|
||||
Info " gitlink-cli --help # 查看所有命令"
|
||||
Info " gitlink-cli version # 查看版本信息"
|
||||
Write-Host ""
|
||||
|
||||
return $true
|
||||
}
|
||||
catch {
|
||||
ErrorMsg "执行二进制文件失败: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorMsg "安装验证失败: $binaryPath 不存在"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# 主安装流程
|
||||
function Install-CLI {
|
||||
Write-Host ""
|
||||
Write-Host " ╔══════════════════════════════════════╗"
|
||||
Write-Host " ║ GitLink CLI 一键安装 (Windows) ║"
|
||||
Write-Host " ╚══════════════════════════════════════╝"
|
||||
Write-Host ""
|
||||
|
||||
# 检测平台
|
||||
$platform = Get-PlatformInfo
|
||||
Info "检测到平台: $($platform.Platform)-$($platform.Arch)"
|
||||
|
||||
# 创建安装目录
|
||||
if (!(Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
Info "创建安装目录: $InstallDir"
|
||||
}
|
||||
|
||||
# 检查环境
|
||||
Test-Environment
|
||||
|
||||
# 获取版本
|
||||
if ($Version -eq "latest") {
|
||||
$Version = Get-LatestVersion
|
||||
Info "最新版本: $Version"
|
||||
}
|
||||
else {
|
||||
Info "指定版本: $Version"
|
||||
}
|
||||
|
||||
# 下载
|
||||
$zipName = "$BINARY_NAME_${Version}_windows_$($platform.Arch).zip"
|
||||
$zipUrl = "$API_BASE/api/$REPO_OWNER/$REPO_NAME/releases/$Version/assets/$zipName"
|
||||
$zipPath = Join-Path $env:TEMP $zipName
|
||||
|
||||
if (-not (Download-File -Url $zipUrl -Output $zipPath)) {
|
||||
ErrorMsg "请确认以下版本已发布: $Version"
|
||||
ErrorMsg "发布页: $API_BASE/$REPO_OWNER/$REPO_NAME/releases"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 解压
|
||||
Expand-ZipFile -ZipPath $zipPath -DestDir $InstallDir
|
||||
Remove-Item $zipPath
|
||||
|
||||
# 安装skills
|
||||
Step "安装 skills..."
|
||||
if (!(Test-Path $SKILLS_DIR)) {
|
||||
New-Item -ItemType Directory -Path $SKILLS_DIR -Force | Out-Null
|
||||
}
|
||||
|
||||
$skillsZipName = "$BINARY_NAME_${Version}_skills.zip"
|
||||
$skillsUrl = "$API_BASE/api/$REPO_OWNER/$REPO_NAME/releases/$Version/assets/$skillsZipName"
|
||||
$skillsZipPath = Join-Path $env:TEMP $skillsZipName
|
||||
|
||||
if (Download-File -Url $skillsUrl -Output $skillsZipPath) {
|
||||
try {
|
||||
Expand-Archive -Force -Path $skillsZipPath -DestinationPath $SKILLS_DIR
|
||||
Info "Skills 安装到: $SKILLS_DIR"
|
||||
}
|
||||
catch {
|
||||
Warn "Skills 解压失败(可稍后手动安装)"
|
||||
}
|
||||
Remove-Item $skillsZipPath -ErrorAction SilentlyContinue
|
||||
}
|
||||
else {
|
||||
Warn "Skills 包不可用(可稍后手动安装)"
|
||||
}
|
||||
|
||||
# 验证
|
||||
if (-not (Test-Installation)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# 卸载
|
||||
function Uninstall-CLI {
|
||||
Step "卸载 $BINARY_NAME..."
|
||||
|
||||
# 删除二进制
|
||||
$binaryPath = Join-Path $InstallDir "$BINARY_NAME.exe"
|
||||
if (Test-Path $binaryPath) {
|
||||
Remove-Item $binaryPath -Force
|
||||
Info "已删除: $binaryPath"
|
||||
}
|
||||
|
||||
# 删除skills
|
||||
if (Test-Path $SKILLS_DIR) {
|
||||
Remove-Item $SKILLS_DIR -Recurse -Force
|
||||
Info "已删除: $SKILLS_DIR"
|
||||
}
|
||||
|
||||
# 删除配置(可选)
|
||||
$response = Read-Host "是否删除配置文件? [y/N]"
|
||||
if ($response -eq 'y' -or $response -eq 'Y') {
|
||||
$configDir = Join-Path $env:APPDATA "gitlink-cli"
|
||||
if (Test-Path $configDir) {
|
||||
Remove-Item $configDir -Recurse -Force
|
||||
Info "已删除配置文件"
|
||||
}
|
||||
}
|
||||
|
||||
Info "卸载完成"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
function Main {
|
||||
if ($Help) {
|
||||
Show-Help
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($ListVersions) {
|
||||
Show-AvailableVersions
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($Uninstall) {
|
||||
Uninstall-CLI
|
||||
exit 0
|
||||
}
|
||||
|
||||
try {
|
||||
Install-CLI
|
||||
}
|
||||
catch {
|
||||
ErrorMsg "安装失败: $_"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
Main
|
||||
263
install.sh
263
install.sh
|
|
@ -1,28 +1,137 @@
|
|||
#!/bin/bash
|
||||
# GitLink CLI 一键安装脚本
|
||||
# GitLink CLI 一键安装脚本(改进版)
|
||||
# 自动检测平台,下载预编译二进制,安装 skills
|
||||
# 用法: curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
# 支持: VERSION=0.1.0 INSTALL_DIR=$HOME/.local/bin bash install.sh
|
||||
|
||||
set -e
|
||||
|
||||
REPO_OWNER="Gitlink"
|
||||
REPO_NAME="gitlink-cli"
|
||||
BINARY_NAME="gitlink-cli"
|
||||
API_BASE="https://www.gitlink.org.cn"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
||||
INSTALL_DIR="${INSTALL_DIR:-auto}"
|
||||
SKILLS_DIR="${HOME}/.gitlink/skills"
|
||||
VERSION="${VERSION:-latest}"
|
||||
MAX_ATTEMPTS=3
|
||||
DEBUG="${DEBUG:-false}"
|
||||
|
||||
# ---------- 颜色输出 ----------
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||||
step() { echo -e "${CYAN}[STEP]${NC} $*"; }
|
||||
step() { echo -e "${CYAN}[STEP]${NC} $*"; }
|
||||
debug() { [[ "${DEBUG}" == "true" ]] && echo -e "${BLUE}[DEBUG]${NC} $*"; }
|
||||
|
||||
# ---------- 环境检测 ----------
|
||||
check_environment() {
|
||||
step "检查安装环境..."
|
||||
|
||||
# 检查必需命令
|
||||
local required_commands=("curl" "tar")
|
||||
for cmd in "${required_commands[@]}"; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
error "缺少必需命令: $cmd"
|
||||
error "请安装后再试:"
|
||||
error " Ubuntu/Debian: sudo apt-get install $cmd"
|
||||
error " CentOS/RHEL: sudo yum install $cmd"
|
||||
error " macOS: brew install $cmd"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
debug "必需命令检查通过"
|
||||
|
||||
# 检查磁盘空间(至少50MB)
|
||||
local available_space
|
||||
available_space=$(df -m "$HOME" | tail -1 | awk '{print $4}')
|
||||
if [ "$available_space" -lt 50 ]; then
|
||||
error "磁盘空间不足(需要至少50MB,可用: ${available_space}MB)"
|
||||
exit 1
|
||||
fi
|
||||
debug "磁盘空间检查通过: ${available_space}MB"
|
||||
|
||||
# 检查网络连接
|
||||
if ! curl -sSL --connect-timeout 5 "${API_BASE}" >/dev/null 2>&1; then
|
||||
error "无法连接到 GitLink 服务器: ${API_BASE}"
|
||||
error "请检查网络连接"
|
||||
exit 1
|
||||
fi
|
||||
debug "网络连接检查通过"
|
||||
|
||||
info "环境检查通过"
|
||||
}
|
||||
|
||||
# ---------- 智能权限处理 ----------
|
||||
select_install_dir() {
|
||||
local dirs=("$HOME/.local/bin" "$HOME/bin" "/usr/local/bin")
|
||||
local selected_dir=""
|
||||
|
||||
if [ "${INSTALL_DIR}" != "auto" ]; then
|
||||
echo "${INSTALL_DIR}"
|
||||
return
|
||||
fi
|
||||
|
||||
step "选择安装目录..."
|
||||
|
||||
# 优先级:用户目录 > 系统目录
|
||||
for dir in "${dirs[@]}"; do
|
||||
if [ -w "$dir" ] 2>/dev/null || mkdir -p "$dir" 2>/dev/null; then
|
||||
selected_dir="$dir"
|
||||
info "选择用户目录: $selected_dir"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 如果用户目录都不可写,尝试系统目录
|
||||
if [ -z "$selected_dir" ]; then
|
||||
warn "无法写入用户目录,将使用系统目录(需要sudo权限)"
|
||||
selected_dir="/usr/local/bin"
|
||||
fi
|
||||
|
||||
echo "$selected_dir"
|
||||
}
|
||||
|
||||
# ---------- 下载重试机制 ----------
|
||||
download_with_retry() {
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
local attempt=1
|
||||
|
||||
while [ $attempt -le $MAX_ATTEMPTS ]; do
|
||||
step "下载 (尝试 $attempt/$MAX_ATTEMPTS): $(basename "$url")"
|
||||
|
||||
if curl -sSL --connect-timeout 10 --max-time 120 --progress-bar "$url" -o "$output" 2>&1; then
|
||||
if [ -s "$output" ]; then
|
||||
info "下载成功: $(basename "$output") ($(du -h "$output" | cut -f1))"
|
||||
return 0
|
||||
else
|
||||
warn "下载文件为空"
|
||||
fi
|
||||
else
|
||||
warn "下载失败"
|
||||
fi
|
||||
|
||||
if [ $attempt -lt $MAX_ATTEMPTS ]; then
|
||||
local wait_time=$((attempt * 2))
|
||||
warn "等待 ${wait_time}s 后重试..."
|
||||
sleep $wait_time
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
error "下载失败,已尝试 $MAX_ATTEMPTS 次"
|
||||
error "URL: $url"
|
||||
error "请检查网络连接或手动下载"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ---------- 平台检测 ----------
|
||||
detect_platform() {
|
||||
|
|
@ -67,6 +176,74 @@ fetch_latest_version() {
|
|||
echo "${tag:-v0.1.0}"
|
||||
}
|
||||
|
||||
# ---------- 显示已安装版本 ----------
|
||||
show_installed_version() {
|
||||
if command -v "${BINARY_NAME}" >/dev/null 2>&1; then
|
||||
"${BINARY_NAME}" version 2>/dev/null || echo "未知版本"
|
||||
elif [ -x "${INSTALL_DIR}/${BINARY_NAME}" ]; then
|
||||
"${INSTALL_DIR}/${BINARY_NAME}" version 2>/dev/null || echo "未知版本"
|
||||
else
|
||||
echo "未安装"
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- 列出可用版本 ----------
|
||||
list_versions() {
|
||||
step "查询可用版本..."
|
||||
local releases_url="${API_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases.json"
|
||||
curl -sSL "$releases_url" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/' | head -10
|
||||
}
|
||||
|
||||
# ---------- 回滚功能 ----------
|
||||
rollback_version() {
|
||||
local target_version="$1"
|
||||
|
||||
if [ -z "$target_version" ]; then
|
||||
error "请指定要回滚到的版本"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
step "回滚到版本: ${target_version}"
|
||||
|
||||
# 重新安装指定版本
|
||||
VERSION="$target_version"
|
||||
main
|
||||
}
|
||||
|
||||
# ---------- 卸载功能 ----------
|
||||
uninstall() {
|
||||
step "卸载 ${BINARY_NAME}..."
|
||||
|
||||
# 删除二进制
|
||||
if [ -f "${INSTALL_DIR}/${BINARY_NAME}" ]; then
|
||||
if [ -w "${INSTALL_DIR}" ]; then
|
||||
rm -f "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
info "已删除: ${INSTALL_DIR}/${BINARY_NAME}"
|
||||
else
|
||||
sudo rm -f "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
info "已删除: ${INSTALL_DIR}/${BINARY_NAME} (使用sudo)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 删除skills
|
||||
if [ -d "${SKILLS_DIR}" ]; then
|
||||
rm -rf "${SKILLS_DIR}"
|
||||
info "已删除: ${SKILLS_DIR}"
|
||||
fi
|
||||
|
||||
# 删除配置(可选)
|
||||
echo -n "是否删除配置文件? [y/N] "
|
||||
read -r response
|
||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
rm -rf "$HOME/.config/gitlink-cli"
|
||||
rm -rf "$HOME/.gitlink"
|
||||
info "已删除配置文件"
|
||||
fi
|
||||
|
||||
info "卸载完成"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ---------- 下载二进制 ----------
|
||||
download_binary() {
|
||||
local platform="$1"
|
||||
|
|
@ -76,17 +253,14 @@ download_binary() {
|
|||
local archive_name="${BINARY_NAME}_${version}_${os}_${arch}.tar.gz"
|
||||
local download_url="${API_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases/${version}/assets/${archive_name}"
|
||||
|
||||
step "下载: ${archive_name}"
|
||||
info "URL: ${download_url}"
|
||||
info "下载: ${archive_name}"
|
||||
debug "URL: ${download_url}"
|
||||
|
||||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
trap "rm -rf ${tmpdir}" EXIT
|
||||
|
||||
curl -sSL --connect-timeout 10 --max-time 120 -o "${tmpdir}/${archive_name}" "${download_url}"
|
||||
|
||||
if [ ! -s "${tmpdir}/${archive_name}" ]; then
|
||||
error "下载失败,文件为空或不存在"
|
||||
if ! download_with_retry "${download_url}" "${tmpdir}/${archive_name}"; then
|
||||
error "请确认以下版本已发布: ${version}"
|
||||
error "发布页: ${API_BASE}/${REPO_OWNER}/${REPO_NAME}/releases"
|
||||
exit 1
|
||||
|
|
@ -135,9 +309,7 @@ install_skills() {
|
|||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
|
||||
curl -sSL --connect-timeout 10 --max-time 60 -o "${tmpdir}/skills.tar.gz" "${skills_url}" 2>/dev/null || true
|
||||
|
||||
if [ -s "${tmpdir}/skills.tar.gz" ]; then
|
||||
if download_with_retry "${skills_url}" "${tmpdir}/skills.tar.gz" 2>/dev/null; then
|
||||
tar -xzf "${tmpdir}/skills.tar.gz" -C "${SKILLS_DIR}" 2>/dev/null || true
|
||||
info "Skills 安装到: ${SKILLS_DIR}"
|
||||
else
|
||||
|
|
@ -161,6 +333,46 @@ verify() {
|
|||
fi
|
||||
}
|
||||
|
||||
# ---------- 显示帮助 ----------
|
||||
show_help() {
|
||||
cat << EOF
|
||||
GitLink CLI 安装脚本
|
||||
|
||||
用法:
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash [选项]
|
||||
|
||||
选项:
|
||||
VERSION=0.1.0 指定版本
|
||||
INSTALL_DIR=/path 指定安装目录
|
||||
DEBUG=true 显示调试信息
|
||||
|
||||
环境变量:
|
||||
INSTALL_DIR 安装目录(默认: auto,自动选择)
|
||||
VERSION 版本(默认: latest)
|
||||
|
||||
命令:
|
||||
list 列出可用版本
|
||||
uninstall 卸载
|
||||
rollback VERSION 回滚到指定版本
|
||||
|
||||
示例:
|
||||
# 安装最新版本
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# 安装指定版本
|
||||
VERSION=0.1.0 curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# 安装到用户目录
|
||||
INSTALL_DIR=$HOME/.local/bin curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
|
||||
|
||||
# 列出可用版本
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- list
|
||||
|
||||
# 卸载
|
||||
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- uninstall
|
||||
EOF
|
||||
}
|
||||
|
||||
# ---------- main ----------
|
||||
main() {
|
||||
echo ""
|
||||
|
|
@ -169,6 +381,32 @@ main() {
|
|||
echo " ╚══════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# 处理命令行参数
|
||||
case "${1:-}" in
|
||||
list)
|
||||
list_versions
|
||||
exit 0
|
||||
;;
|
||||
uninstall)
|
||||
INSTALL_DIR="${INSTALL_DIR:-$(select_install_dir)}"
|
||||
uninstall
|
||||
;;
|
||||
rollback)
|
||||
rollback_version "$2"
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# 环境检测
|
||||
check_environment
|
||||
|
||||
# 选择安装目录
|
||||
INSTALL_DIR=$(select_install_dir)
|
||||
export INSTALL_DIR
|
||||
|
||||
local platform
|
||||
platform=$(detect_platform)
|
||||
info "检测到平台: ${platform}"
|
||||
|
|
@ -190,6 +428,7 @@ main() {
|
|||
info "快速开始:"
|
||||
info " gitlink-cli auth login # 登录账号"
|
||||
info " gitlink-cli --help # 查看所有命令"
|
||||
info " gitlink-cli version # 查看版本信息"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* GitLink CLI 卸载命令
|
||||
* 用法: gitlink-cli-uninstall [--purge]
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
// 颜色输出
|
||||
const colors = {
|
||||
green: '\x1b[32m',
|
||||
yellow: '\x1b[33m',
|
||||
red: '\x1b[31m',
|
||||
cyan: '\x1b[36m',
|
||||
blue: '\x1b[34m',
|
||||
reset: '\x1b[0m'
|
||||
};
|
||||
|
||||
function info(msg) {
|
||||
console.log(`${colors.green}[INFO]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function warn(msg) {
|
||||
console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function error(msg) {
|
||||
console.log(`${colors.red}[ERROR]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function step(msg) {
|
||||
console.log(`${colors.cyan}[STEP]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function ask(msg) {
|
||||
console.log(`${colors.blue}[ASK]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
// ---------- 删除文件/目录 ----------
|
||||
function removeSync(target) {
|
||||
try {
|
||||
if (fs.existsSync(target)) {
|
||||
const stat = fs.statSync(target);
|
||||
if (stat.isDirectory()) {
|
||||
fs.rmdirSync(target, { recursive: true });
|
||||
return true;
|
||||
} else {
|
||||
fs.unlinkSync(target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 删除Skills ----------
|
||||
function removeSkills() {
|
||||
step('删除 Skills...');
|
||||
|
||||
const skillsDir = path.join(os.homedir(), '.gitlink', 'skills');
|
||||
|
||||
if (removeSync(skillsDir)) {
|
||||
info('Skills已删除');
|
||||
} else {
|
||||
warn('Skills目录不存在或删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 删除配置 ----------
|
||||
function removeConfig(purgeAll = false) {
|
||||
if (!purgeAll) {
|
||||
info('保留配置文件');
|
||||
return;
|
||||
}
|
||||
|
||||
step('删除配置文件...');
|
||||
|
||||
const configPaths = [
|
||||
path.join(os.homedir(), '.gitlink-cli'),
|
||||
path.join(os.homedir(), '.config', 'gitlink-cli'),
|
||||
path.join(os.homedir(), '.gitlink')
|
||||
];
|
||||
|
||||
let removedCount = 0;
|
||||
for (const configPath of configPaths) {
|
||||
if (removeSync(configPath)) {
|
||||
info(`已删除: ${configPath}`);
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount > 0) {
|
||||
info('配置文件已删除');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 主流程 ----------
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const purgeAll = args.includes('--purge') || args.includes('-p');
|
||||
const help = args.includes('--help') || args.includes('-h');
|
||||
|
||||
if (help) {
|
||||
console.log('');
|
||||
console.log('GitLink CLI 卸载命令');
|
||||
console.log('');
|
||||
console.log('用法: gitlink-cli-uninstall [选项]');
|
||||
console.log('');
|
||||
console.log('选项:');
|
||||
console.log(' --purge, -p 删除所有文件(包括配置)');
|
||||
console.log(' --help, -h 显示此帮助');
|
||||
console.log('');
|
||||
console.log('示例:');
|
||||
console.log(' gitlink-cli-uninstall # 保留配置');
|
||||
console.log(' gitlink-cli-uninstall --purge # 完全删除');
|
||||
console.log('');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('========================================');
|
||||
info('GitLink CLI 卸载');
|
||||
console.log('========================================');
|
||||
console.log('');
|
||||
|
||||
step('卸载npm包...');
|
||||
|
||||
try {
|
||||
// 执行npm uninstall
|
||||
if (process.platform === 'win32') {
|
||||
execSync('npm uninstall -g @gitlink-ai/cli', { stdio: 'inherit' });
|
||||
} else {
|
||||
execSync('npm uninstall -g @gitlink-ai/cli', { stdio: 'inherit' });
|
||||
}
|
||||
} catch (err) {
|
||||
warn('npm卸载命令执行失败,请手动运行: npm uninstall -g @gitlink-ai/cli');
|
||||
}
|
||||
|
||||
// 删除skills
|
||||
removeSkills();
|
||||
|
||||
// 删除配置
|
||||
removeConfig(purgeAll);
|
||||
|
||||
console.log('');
|
||||
console.log('========================================');
|
||||
info('卸载完成!');
|
||||
console.log('========================================');
|
||||
console.log('');
|
||||
|
||||
if (!purgeAll) {
|
||||
info('以下文件可能需要手动清理:');
|
||||
console.log(` - ${path.join(os.homedir(), '.gitlink-cli')}`);
|
||||
console.log(` - ${path.join(os.homedir(), '.gitlink')}`);
|
||||
console.log('');
|
||||
info('如需删除,请运行: gitlink-cli-uninstall --purge');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
info('感谢使用 GitLink CLI!');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// 运行
|
||||
try {
|
||||
main();
|
||||
} catch (err) {
|
||||
error(`卸载失败: ${err.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
@ -4,10 +4,13 @@
|
|||
"description": "GitLink 平台官方命令行工具 — 代码托管、协作开发和自动化",
|
||||
"bin": {
|
||||
"gitlink-cli": "bin/cli.js",
|
||||
"gitlink-cli-install-skills": "bin/install-skills.js"
|
||||
"gitlink-cli-install-skills": "bin/install-skills.js",
|
||||
"gitlink-cli-uninstall": "bin/uninstall.js"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node scripts/install.js",
|
||||
"preuninstall": "node scripts/uninstall.js",
|
||||
"uninstall": "node scripts/uninstall.js",
|
||||
"test": "node test/install.test.js && node test/cli.test.js"
|
||||
},
|
||||
"keywords": [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* GitLink CLI npm 卸载脚本
|
||||
* npm preuninstall 钩子自动运行
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
// 颜色输出(支持跨平台)
|
||||
const colors = {
|
||||
green: '\x1b[32m',
|
||||
yellow: '\x1b[33m',
|
||||
red: '\x1b[31m',
|
||||
cyan: '\x1b[36m',
|
||||
blue: '\x1b[34m',
|
||||
reset: '\x1b[0m'
|
||||
};
|
||||
|
||||
function info(msg) {
|
||||
console.log(`${colors.green}[INFO]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function warn(msg) {
|
||||
console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function error(msg) {
|
||||
console.log(`${colors.red}[ERROR]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function step(msg) {
|
||||
console.log(`${colors.cyan}[STEP]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
// ---------- 删除文件/目录 ----------
|
||||
function removeSync(target) {
|
||||
try {
|
||||
if (fs.existsSync(target)) {
|
||||
const stat = fs.statSync(target);
|
||||
if (stat.isDirectory()) {
|
||||
fs.rmdirSync(target, { recursive: true });
|
||||
info(`已删除目录: ${target}`);
|
||||
} else {
|
||||
fs.unlinkSync(target);
|
||||
info(`已删除文件: ${target}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (err) {
|
||||
warn(`删除失败: ${target} - ${err.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 删除Skills ----------
|
||||
function removeSkills() {
|
||||
step('删除 Skills...');
|
||||
|
||||
const skillsDir = path.join(os.homedir(), '.gitlink', 'skills');
|
||||
|
||||
if (!fs.existsSync(skillsDir)) {
|
||||
warn('Skills目录不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 统计skills数量
|
||||
let skillCount = 0;
|
||||
try {
|
||||
const items = fs.readdirSync(skillsDir);
|
||||
skillCount = items.filter(item => {
|
||||
const itemPath = path.join(skillsDir, item);
|
||||
return fs.statSync(itemPath).isDirectory();
|
||||
}).length;
|
||||
} catch (err) {
|
||||
// 忽略错误
|
||||
}
|
||||
|
||||
info(`找到 ${skillCount} 个Skills`);
|
||||
|
||||
if (removeSync(skillsDir)) {
|
||||
info('Skills已删除');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 删除配置(可选)----------
|
||||
function removeConfig(purgeAll = false) {
|
||||
if (!purgeAll) {
|
||||
// npm卸载通常不删除配置
|
||||
info('保留配置文件(用户数据)');
|
||||
return;
|
||||
}
|
||||
|
||||
step('删除配置文件...');
|
||||
|
||||
const configPaths = [
|
||||
path.join(os.homedir(), '.gitlink-cli'),
|
||||
path.join(os.homedir(), '.config', 'gitlink-cli'),
|
||||
path.join(os.homedir(), '.gitlink')
|
||||
];
|
||||
|
||||
let removedCount = 0;
|
||||
for (const configPath of configPaths) {
|
||||
if (removeSync(configPath)) {
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount > 0) {
|
||||
info('配置文件已删除');
|
||||
} else {
|
||||
warn('未找到配置文件');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 主流程 ----------
|
||||
function main() {
|
||||
console.log('');
|
||||
console.log('========================================');
|
||||
info('GitLink CLI npm 卸载');
|
||||
console.log('========================================');
|
||||
console.log('');
|
||||
|
||||
// 检查环境变量
|
||||
const purgeAll = process.env.GITLINK_UNINSTALL_PURGE === 'true' || process.argv.includes('--purge');
|
||||
|
||||
step('开始清理npm安装的文件...');
|
||||
|
||||
// 删除skills
|
||||
removeSkills();
|
||||
|
||||
// 删除配置(如果指定--purge)
|
||||
removeConfig(purgeAll);
|
||||
|
||||
console.log('');
|
||||
console.log('========================================');
|
||||
info('卸载完成!');
|
||||
console.log('========================================');
|
||||
console.log('');
|
||||
|
||||
if (!purgeAll) {
|
||||
info('以下文件可能需要手动清理:');
|
||||
console.log(` - ${path.join(os.homedir(), '.gitlink-cli')}`);
|
||||
console.log(` - ${path.join(os.homedir(), '.gitlink')}`);
|
||||
console.log('');
|
||||
info('如需删除,请运行: npm uninstall -g @gitlink-ai/cli --purge');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
info('感谢使用 GitLink CLI!');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// 运行
|
||||
try {
|
||||
main();
|
||||
} catch (err) {
|
||||
error(`卸载失败: ${err.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
"use strict";
|
||||
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const https = require("https");
|
||||
const http = require("http");
|
||||
const { execSync } = require("child_process");
|
||||
const PACKAGE = require("../package.json");
|
||||
|
||||
const VERSION = PACKAGE.version;
|
||||
const BINARY_NAME = "gitlink-cli";
|
||||
const RELEASE_BASE = "https://www.gitlink.org.cn";
|
||||
const REPO_OWNER = "Gitlink";
|
||||
const REPO_NAME = "gitlink-cli";
|
||||
|
||||
// 颜色输出
|
||||
const colors = {
|
||||
reset: "\x1b[0m",
|
||||
green: "\x1b[32m",
|
||||
yellow: "\x1b[33m",
|
||||
red: "\x1b[31m",
|
||||
cyan: "\x1b[36m",
|
||||
blue: "\x1b[34m",
|
||||
};
|
||||
|
||||
function info(msg) {
|
||||
console.log(`${colors.green}[INFO]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function warn(msg) {
|
||||
console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function error(msg) {
|
||||
console.log(`${colors.red}[ERROR]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function step(msg) {
|
||||
console.log(`${colors.cyan}[STEP]${colors.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function debug(msg) {
|
||||
if (process.env.DEBUG === "true") {
|
||||
console.log(`${colors.blue}[DEBUG]${colors.reset} ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getPlatformInfo(platform = os.platform(), arch = os.arch()) {
|
||||
const platformMap = {
|
||||
darwin: "darwin",
|
||||
linux: "linux",
|
||||
win32: "windows",
|
||||
};
|
||||
|
||||
const archMap = {
|
||||
x64: "amd64",
|
||||
arm64: "arm64",
|
||||
};
|
||||
|
||||
const goPlatform = platformMap[platform];
|
||||
const goArch = archMap[arch];
|
||||
|
||||
if (!goPlatform || !goArch) {
|
||||
throw new Error(
|
||||
`Unsupported platform: ${platform}-${arch}. ` +
|
||||
`Supported: darwin-x64, darwin-arm64, linux-x64, linux-arm64, win32-x64, win32-arm64`
|
||||
);
|
||||
}
|
||||
|
||||
return { platform: goPlatform, arch: goArch, isWindows: platform === "win32" };
|
||||
}
|
||||
|
||||
function getBinaryName(platform) {
|
||||
return platform === "windows" ? `${BINARY_NAME}.exe` : BINARY_NAME;
|
||||
}
|
||||
|
||||
function getArchiveName(platform, arch) {
|
||||
const ext = platform === "windows" ? ".zip" : ".tar.gz";
|
||||
return `${BINARY_NAME}_${VERSION}_${platform}_${arch}${ext}`;
|
||||
}
|
||||
|
||||
function fetch(url, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const maxRedirects = options.maxRedirects || 5;
|
||||
let redirectCount = 0;
|
||||
|
||||
function doRequest(currentUrl) {
|
||||
const mod = currentUrl.startsWith("https") ? https : http;
|
||||
const req = mod.get(currentUrl, (res) => {
|
||||
// Follow redirects
|
||||
if (
|
||||
(res.statusCode === 301 ||
|
||||
res.statusCode === 302 ||
|
||||
res.statusCode === 307 ||
|
||||
res.statusCode === 308) &&
|
||||
res.headers.location
|
||||
) {
|
||||
redirectCount++;
|
||||
if (redirectCount > maxRedirects) {
|
||||
reject(new Error(`Too many redirects (max ${maxRedirects})`));
|
||||
return;
|
||||
}
|
||||
let redirectUrl = res.headers.location;
|
||||
if (redirectUrl.startsWith("/")) {
|
||||
const parsed = new URL(currentUrl);
|
||||
redirectUrl = `${parsed.protocol}//${parsed.host}${redirectUrl}`;
|
||||
}
|
||||
doRequest(redirectUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${res.statusCode} when downloading ${currentUrl}`));
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.json) {
|
||||
let body = "";
|
||||
res.on("data", (chunk) => (body += chunk));
|
||||
res.on("end", () => {
|
||||
try {
|
||||
resolve(JSON.parse(body));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.pipe(resolve);
|
||||
}
|
||||
});
|
||||
|
||||
req.on("error", reject);
|
||||
req.setTimeout(options.timeout || 30000, () => {
|
||||
req.destroy();
|
||||
reject(new Error(`Request timeout: ${currentUrl}`));
|
||||
});
|
||||
}
|
||||
|
||||
doRequest(url);
|
||||
});
|
||||
}
|
||||
|
||||
// 下载文件(带重试)
|
||||
async function downloadFile(url, outputPath, maxAttempts = 3) {
|
||||
let attempt = 1;
|
||||
|
||||
while (attempt <= maxAttempts) {
|
||||
try {
|
||||
step(`下载 (尝试 ${attempt}/${maxAttempts}): ${path.basename(url)}`);
|
||||
debug(`URL: ${url}`);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const file = fs.createWriteStream(outputPath);
|
||||
const mod = url.startsWith("https") ? https : http;
|
||||
|
||||
const req = mod.get(url, (res) => {
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${res.statusCode}`));
|
||||
return;
|
||||
}
|
||||
|
||||
const totalSize = parseInt(res.headers["content-length"], 10);
|
||||
let downloadedSize = 0;
|
||||
|
||||
res.on("data", (chunk) => {
|
||||
downloadedSize += chunk.length;
|
||||
if (totalSize) {
|
||||
const progress = ((downloadedSize / totalSize) * 100).toFixed(1);
|
||||
process.stdout.write(`\r下载进度: ${progress}%`);
|
||||
}
|
||||
});
|
||||
|
||||
res.pipe(file);
|
||||
|
||||
file.on("finish", () => {
|
||||
file.close();
|
||||
process.stdout.write("\r");
|
||||
resolve();
|
||||
});
|
||||
|
||||
file.on("error", (err) => {
|
||||
fs.unlink(outputPath, () => {});
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
||||
req.on("error", (err) => {
|
||||
file.destroy();
|
||||
fs.unlink(outputPath, () => {});
|
||||
reject(err);
|
||||
});
|
||||
|
||||
req.setTimeout(120000, () => {
|
||||
req.destroy();
|
||||
file.destroy();
|
||||
fs.unlink(outputPath, () => {});
|
||||
reject(new Error("下载超时"));
|
||||
});
|
||||
});
|
||||
|
||||
if (fs.existsSync(outputPath) && fs.statSync(outputPath).size > 0) {
|
||||
const sizeMB = (fs.statSync(outputPath).size / (1024 * 1024)).toFixed(2);
|
||||
info(`下载成功: ${path.basename(outputPath)} (${sizeMB}MB)`);
|
||||
return true;
|
||||
} else {
|
||||
warn("下载文件为空");
|
||||
}
|
||||
} catch (err) {
|
||||
warn(`下载失败: ${err.message}`);
|
||||
}
|
||||
|
||||
if (attempt < maxAttempts) {
|
||||
const waitTime = attempt * 2;
|
||||
warn(`等待 ${waitTime}s 后重试...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, waitTime * 1000));
|
||||
}
|
||||
|
||||
attempt++;
|
||||
}
|
||||
|
||||
error("下载失败,已尝试 ${maxAttempts} 次");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取最新版本
|
||||
async function getLatestVersion() {
|
||||
try {
|
||||
step("检查更新...");
|
||||
const releasesUrl = `${RELEASE_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases.json`;
|
||||
const releases = await fetch(releasesUrl, { json: true, timeout: 30000 });
|
||||
|
||||
if (releases && releases.length > 0) {
|
||||
return releases[0].tag_name;
|
||||
}
|
||||
} catch (err) {
|
||||
debug(`获取版本失败: ${err.message}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否有更新
|
||||
async function checkForUpdate() {
|
||||
try {
|
||||
const latestVersion = await getLatestVersion();
|
||||
|
||||
if (!latestVersion) {
|
||||
info("无法获取最新版本信息");
|
||||
return;
|
||||
}
|
||||
|
||||
const currentVersion = VERSION.startsWith("v") ? VERSION : `v${VERSION}`;
|
||||
const latest = latestVersion.startsWith("v") ? latestVersion : `v${latestVersion}`;
|
||||
|
||||
info(`当前版本: ${currentVersion}`);
|
||||
info(`最新版本: ${latest}`);
|
||||
|
||||
if (currentVersion === latest) {
|
||||
info("已经是最新版本");
|
||||
return;
|
||||
}
|
||||
|
||||
// 简单的版本比较
|
||||
if (latest > currentVersion) {
|
||||
warn(`发现新版本: ${latest}`);
|
||||
warn("运行 'npm update -g @gitlink-ai/cli' 更新");
|
||||
} else if (latest < currentVersion) {
|
||||
info("当前版本比最新发布版本更新(开发版本)");
|
||||
}
|
||||
} catch (err) {
|
||||
debug(`检查更新失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 安装二进制
|
||||
async function installBinary() {
|
||||
const platform = getPlatformInfo();
|
||||
info(`平台: ${platform.platform}-${platform.arch}`);
|
||||
|
||||
const binaryName = getBinaryName(platform.platform);
|
||||
const archiveName = getArchiveName(platform.platform, platform.arch);
|
||||
const npmBinDir = path.dirname(process.execPath);
|
||||
const installDir = path.join(npmBinDir, "..");
|
||||
|
||||
step(`安装二进制到: ${installDir}`);
|
||||
|
||||
const version = VERSION.startsWith("v") ? VERSION : `v${VERSION}`;
|
||||
const binaryUrl = `${RELEASE_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases/${version}/assets/${archiveName}`;
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "gitlink-cli-"));
|
||||
const archivePath = path.join(tmpDir, archiveName);
|
||||
|
||||
try {
|
||||
// 下载
|
||||
const success = await downloadFile(binaryUrl, archivePath);
|
||||
if (!success) {
|
||||
throw new Error("下载失败");
|
||||
}
|
||||
|
||||
// 解压
|
||||
step("解压...");
|
||||
if (platform.isWindows) {
|
||||
const AdmZip = require("adm-zip");
|
||||
const zip = new AdmZip(archivePath);
|
||||
zip.extractAllTo(installDir, true);
|
||||
} else {
|
||||
const tar = require("tar");
|
||||
await tar.x({
|
||||
file: archivePath,
|
||||
cwd: installDir,
|
||||
strip: 1,
|
||||
});
|
||||
}
|
||||
|
||||
// 设置执行权限(Unix)
|
||||
if (!platform.isWindows) {
|
||||
const binaryPath = path.join(installDir, binaryName);
|
||||
if (fs.existsSync(binaryPath)) {
|
||||
fs.chmodSync(binaryPath, "755");
|
||||
}
|
||||
}
|
||||
|
||||
info(`二进制安装成功: ${binaryName}`);
|
||||
} finally {
|
||||
// 清理临时文件
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
// 安装skills
|
||||
async function installSkills() {
|
||||
const version = VERSION.startsWith("v") ? VERSION : `v${VERSION}`;
|
||||
const skillsArchive = `${BINARY_NAME}_${version}_skills.zip`;
|
||||
const skillsUrl = `${RELEASE_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases/${version}/assets/${skillsArchive}`;
|
||||
|
||||
const skillsDir = path.join(os.homedir(), ".gitlink", "skills");
|
||||
|
||||
if (!fs.existsSync(skillsDir)) {
|
||||
fs.mkdirSync(skillsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "gitlink-skills-"));
|
||||
const archivePath = path.join(tmpDir, skillsArchive);
|
||||
|
||||
try {
|
||||
step("安装 skills...");
|
||||
|
||||
const success = await downloadFile(skillsUrl, archivePath);
|
||||
if (!success) {
|
||||
warn("Skills 包下载失败(可稍后手动安装)");
|
||||
return;
|
||||
}
|
||||
|
||||
// 解压
|
||||
const AdmZip = require("adm-zip");
|
||||
const zip = new AdmZip(archivePath);
|
||||
zip.extractAllTo(skillsDir, true);
|
||||
|
||||
info("Skills 安装成功");
|
||||
} catch (err) {
|
||||
warn(`Skills 安装失败: ${err.message}`);
|
||||
} finally {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
// 验证安装
|
||||
function verifyInstallation() {
|
||||
step("验证安装...";
|
||||
|
||||
try {
|
||||
const result = execSync("gitlink-cli version", { encoding: "utf8" });
|
||||
info(`安装成功! ${result.trim()}`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
warn("验证命令失败(可能需要重启终端)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
async function main() {
|
||||
console.log("");
|
||||
console.log(" ╔══════════════════════════════════════╗");
|
||||
console.log(" ║ GitLink CLI npm 安装脚本 ║");
|
||||
console.log(" ╚══════════════════════════════════════╝");
|
||||
console.log("");
|
||||
|
||||
try {
|
||||
await installBinary();
|
||||
await installSkills();
|
||||
verifyInstallation();
|
||||
|
||||
console.log("");
|
||||
info("快速开始:");
|
||||
info(" gitlink-cli auth login # 登录账号");
|
||||
info(" gitlink-cli --help # 查看所有命令");
|
||||
info(" gitlink-cli version # 查看版本信息");
|
||||
console.log("");
|
||||
} catch (err) {
|
||||
error(`安装失败: ${err.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module || process.argv[1].endsWith("update.js")) {
|
||||
// 检查更新
|
||||
if (process.argv.includes("--check")) {
|
||||
(async () => {
|
||||
await checkForUpdate();
|
||||
})();
|
||||
} else {
|
||||
// 安装
|
||||
(async () => {
|
||||
await main();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
main,
|
||||
checkForUpdate,
|
||||
installBinary,
|
||||
installSkills,
|
||||
};
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
# GitLink CLI Windows 卸载脚本
|
||||
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File uninstall.ps1
|
||||
|
||||
param(
|
||||
[switch]$Purge,
|
||||
[switch]$Yes,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ---------- 工具函数 ----------
|
||||
function Info-Message {
|
||||
param([string]$Message)
|
||||
Write-Host "[INFO] $Message" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Warn-Message {
|
||||
param([string]$Message)
|
||||
Write-Host "[WARN] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Error-Message {
|
||||
param([string]$Message)
|
||||
Write-Host "[ERROR] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Step-Message {
|
||||
param([string]$Message)
|
||||
Write-Host "[STEP] $Message" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Ask-Question {
|
||||
param([string]$Question)
|
||||
Write-Host "[ASK] $Question" -ForegroundColor Blue
|
||||
}
|
||||
|
||||
# ---------- 显示帮助 ----------
|
||||
if ($Help) {
|
||||
Write-Host ""
|
||||
Write-Host "GitLink CLI Windows 卸载脚本"
|
||||
Write-Host ""
|
||||
Write-Host "用法: powershell -NoProfile -ExecutionPolicy Bypass -File uninstall.ps1 [选项]"
|
||||
Write-Host ""
|
||||
Write-Host "选项:"
|
||||
Write-Host " -Purge 删除所有文件(包括配置)"
|
||||
Write-Host " -Yes 自动确认,不询问"
|
||||
Write-Host " -Help 显示此帮助"
|
||||
Write-Host ""
|
||||
Write-Host "示例:"
|
||||
Write-Host " .\uninstall.ps1 # 交互式卸载"
|
||||
Write-Host " .\uninstall.ps1 -Purge # 完全删除"
|
||||
Write-Host " .\uninstall.ps1 -Yes # 自动确认"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ---------- 查找二进制文件 ----------
|
||||
function Find-Binary {
|
||||
Step-Message "查找 gitlink-cli 二进制文件..."
|
||||
|
||||
$possibleDirs = @(
|
||||
"$env:USERPROFILE\.gitlink-cli\bin",
|
||||
"$env:USERPROFILE\.local\bin",
|
||||
"$env:USERPROFILE\scoop\shims",
|
||||
"$env:ChocolateyInstall\bin",
|
||||
"$env:USERPROFILE\go\bin"
|
||||
)
|
||||
|
||||
foreach ($dir in $possibleDirs) {
|
||||
$binaryPath = Join-Path $dir "gitlink-cli.exe"
|
||||
if (Test-Path $binaryPath) {
|
||||
$script:InstallDir = $dir
|
||||
Info-Message "找到安装目录: $dir"
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
# 检查PATH
|
||||
if (Get-Command "gitlink-cli" -ErrorAction SilentlyContinue) {
|
||||
$script:InstallDir = Split-Path (Get-Command "gitlink-cli").Source -Parent
|
||||
Info-Message "通过PATH找到安装目录: $script:InstallDir"
|
||||
return $true
|
||||
}
|
||||
|
||||
Warn-Message "未找到 gitlink-cli 二进制文件"
|
||||
return $false
|
||||
}
|
||||
|
||||
# ---------- 检查安装状态 ----------
|
||||
function Test-InstallationStatus {
|
||||
Step-Message "检查安装状态..."
|
||||
|
||||
$foundItems = @()
|
||||
|
||||
if ($script:InstallDir -and (Test-Path (Join-Path $script:InstallDir "gitlink-cli.exe"))) {
|
||||
$foundItems += "二进制文件: $($script:InstallDir)\gitlink-cli.exe"
|
||||
}
|
||||
|
||||
if (Test-Path "$env:USERPROFILE\.gitlink\skills") {
|
||||
$foundItems += "Skills: $env:USERPROFILE\.gitlink\skills"
|
||||
}
|
||||
|
||||
if (Test-Path "$env:USERPROFILE\.gitlink-cli") {
|
||||
$foundItems += "配置: $env:USERPROFILE\.gitlink-cli"
|
||||
}
|
||||
|
||||
if (Test-Path "$env:USERPROFILE\.gitlink") {
|
||||
$foundItems += "GitLink数据: $env:USERPROFILE\.gitlink"
|
||||
}
|
||||
|
||||
# 检查npm
|
||||
try {
|
||||
$null = npm list -g @gitlink-ai/cli 2>&1 | Select-String "@gitlink-ai/cli"
|
||||
if ($?) {
|
||||
$foundItems += "npm包: @gitlink-ai/cli (全局)"
|
||||
}
|
||||
} catch {
|
||||
# npm未安装或包未安装
|
||||
}
|
||||
|
||||
if ($foundItems.Count -eq 0) {
|
||||
Warn-Message "未检测到 gitlink-cli 安装"
|
||||
return $false
|
||||
}
|
||||
|
||||
Info-Message "检测到以下组件:"
|
||||
foreach ($item in $foundItems) {
|
||||
Write-Host " - $item"
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
# ---------- 删除二进制 ----------
|
||||
function Remove-Binary {
|
||||
if (-not $script:InstallDir) {
|
||||
Warn-Message "跳过二进制删除(未找到安装目录)"
|
||||
return
|
||||
}
|
||||
|
||||
Step-Message "删除二进制文件..."
|
||||
$binaryPath = Join-Path $script:InstallDir "gitlink-cli.exe"
|
||||
|
||||
if (-not (Test-Path $binaryPath)) {
|
||||
Warn-Message "二进制文件不存在: $binaryPath"
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
Remove-Item $binaryPath -Force
|
||||
Info-Message "已删除: $binaryPath"
|
||||
} catch {
|
||||
Error-Message "删除失败: $_"
|
||||
Error-Message "请手动删除: $binaryPath"
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
# ---------- 删除Skills ----------
|
||||
function Remove-Skills {
|
||||
Step-Message "删除 Skills..."
|
||||
|
||||
$skillsPath = "$env:USERPROFILE\.gitlink\skills"
|
||||
if (-not (Test-Path $skillsPath)) {
|
||||
Warn-Message "Skills目录不存在: $skillsPath"
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$skillCount = (Get-ChildItem $skillsPath -Directory).Count
|
||||
Info-Message "找到 $skillCount 个Skills"
|
||||
|
||||
Remove-Item $skillsPath -Recurse -Force
|
||||
Info-Message "已删除Skills"
|
||||
} catch {
|
||||
Error-Message "删除Skills失败: $_"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------- 删除配置 ----------
|
||||
function Remove-Config {
|
||||
if ($Purge) {
|
||||
Step-Message "删除配置文件(--purge模式)..."
|
||||
} else {
|
||||
if (-not $Yes) {
|
||||
Ask-Question "是否删除配置文件和数据? [y/N] "
|
||||
$response = Read-Host
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
Info-Message "保留配置文件"
|
||||
return
|
||||
}
|
||||
}
|
||||
Step-Message "删除配置文件..."
|
||||
}
|
||||
|
||||
$configPaths = @(
|
||||
"$env:USERPROFILE\.gitlink-cli",
|
||||
"$env:USERPROFILE\.gitlink"
|
||||
)
|
||||
|
||||
foreach ($path in $configPaths) {
|
||||
if (Test-Path $path) {
|
||||
try {
|
||||
Info-Message "删除: $path"
|
||||
Remove-Item $path -Recurse -Force
|
||||
} catch {
|
||||
Warn-Message "删除失败 $path : $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info-Message "配置文件已删除"
|
||||
}
|
||||
|
||||
# ---------- 卸载npm包 ----------
|
||||
function Uninstall-Npm {
|
||||
try {
|
||||
$null = npm list -g @gitlink-ai/cli 2>&1 | Select-String "@gitlink-ai/cli"
|
||||
if (-not $?) {
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
Step-Message "卸载npm包..."
|
||||
|
||||
if ($Yes) {
|
||||
$response = 'y'
|
||||
} else {
|
||||
Ask-Question "检测到npm全局安装的 gitlink-cli,是否卸载? [y/N] "
|
||||
$response = Read-Host
|
||||
}
|
||||
|
||||
if ($response -eq 'y' -or $response -eq 'Y') {
|
||||
try {
|
||||
npm uninstall -g @gitlink-ai/cli | Out-Null
|
||||
Info-Message "npm包已卸载"
|
||||
} catch {
|
||||
Warn-Message "npm包卸载失败,请手动执行: npm uninstall -g @gitlink-ai/cli"
|
||||
}
|
||||
} else {
|
||||
Info-Message "保留npm包"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------- 显示卸载摘要 ----------
|
||||
function Show-Summary {
|
||||
Write-Host ""
|
||||
Write-Host "========================================"
|
||||
Info-Message "卸载完成!"
|
||||
Write-Host "========================================"
|
||||
Write-Host ""
|
||||
|
||||
if ($Purge) {
|
||||
Warn-Message "已完全删除所有文件(包括配置)"
|
||||
} else {
|
||||
Info-Message "以下文件可能需要手动清理:"
|
||||
Write-Host " - $env:USERPROFILE\.gitlink-cli"
|
||||
Write-Host " - $env:USERPROFILE\.gitlink"
|
||||
Write-Host ""
|
||||
Info-Message "如需删除,请重新运行: .\uninstall.ps1 -Purge"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Info-Message "感谢使用 GitLink CLI!"
|
||||
Info-Message "如有任何问题,请访问: https://www.gitlink.org.cn/Gitlink/gitlink-cli/issues"
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# ---------- 确认卸载 ----------
|
||||
function Confirm-Uninstall {
|
||||
if ($Yes) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Warn-Message "即将卸载 gitlink-cli 及相关文件"
|
||||
Ask-Question "确认继续? [y/N] "
|
||||
$response = Read-Host
|
||||
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
Info-Message "取消卸载"
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
# ---------- 主流程 ----------
|
||||
function Main {
|
||||
# 欢迎信息
|
||||
Write-Host ""
|
||||
Write-Host "========================================"
|
||||
Write-Host " GitLink CLI 一键卸载 (Windows)"
|
||||
Write-Host "========================================"
|
||||
Write-Host ""
|
||||
|
||||
# 查找二进制
|
||||
if (-not (Find-Binary)) {
|
||||
Error-Message "未检测到 gitlink-cli 安装"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 检查安装状态
|
||||
if (-not (Test-InstallationStatus)) {
|
||||
Error-Message "未检测到 gitlink-cli 安装"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 确认卸载
|
||||
Confirm-Uninstall
|
||||
|
||||
# 执行卸载
|
||||
Remove-Binary
|
||||
Remove-Skills
|
||||
Remove-Config
|
||||
Uninstall-Npm
|
||||
|
||||
# 显示摘要
|
||||
Show-Summary
|
||||
}
|
||||
|
||||
# 运行主流程
|
||||
try {
|
||||
Main
|
||||
} catch {
|
||||
Error-Message "卸载失败: $_"
|
||||
exit 1
|
||||
}
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
#!/bin/bash
|
||||
# GitLink CLI 一键卸载脚本
|
||||
# 删除二进制、skills和配置文件
|
||||
# 用法: curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/uninstall.sh | bash
|
||||
# 或者: bash uninstall.sh [--purge]
|
||||
|
||||
set -e
|
||||
|
||||
REPO_OWNER="Gitlink"
|
||||
REPO_NAME="gitlink-cli"
|
||||
BINARY_NAME="gitlink-cli"
|
||||
API_BASE="https://www.gitlink.org.cn"
|
||||
|
||||
# 默认安装目录(按优先级排序)
|
||||
POSSIBLE_INSTALL_DIRS=(
|
||||
"/usr/local/bin"
|
||||
"/usr/bin"
|
||||
"$HOME/.local/bin"
|
||||
"$HOME/bin"
|
||||
"/opt/homebrew/bin"
|
||||
"$HOME/.gitlink-cli/bin"
|
||||
)
|
||||
|
||||
# ---------- 颜色输出 ----------
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||||
step() { echo -e "${CYAN}[STEP]${NC} $*"; }
|
||||
ask() { echo -e "${BLUE}[ASK]${NC} $*"; }
|
||||
|
||||
# ---------- 查找二进制文件 ----------
|
||||
find_binary() {
|
||||
step "查找 ${BINARY_NAME} 二进制文件..."
|
||||
|
||||
for dir in "${POSSIBLE_INSTALL_DIRS[@]}"; do
|
||||
if [ -f "${dir}/${BINARY_NAME}" ]; then
|
||||
INSTALL_DIR="${dir}"
|
||||
info "找到安装目录: ${INSTALL_DIR}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查是否在PATH中
|
||||
if command -v "${BINARY_NAME}" >/dev/null 2>&1; then
|
||||
INSTALL_DIR="$(dirname "$(command -v "${BINARY_NAME}")")"
|
||||
info "通过PATH找到安装目录: ${INSTALL_DIR}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
warn "未找到 ${BINARY_NAME} 二进制文件"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ---------- 检查安装状态 ----------
|
||||
check_installation_status() {
|
||||
local found_items=()
|
||||
|
||||
step "检查安装状态..."
|
||||
|
||||
# 检查二进制
|
||||
if [ -n "${INSTALL_DIR}" ] && [ -f "${INSTALL_DIR}/${BINARY_NAME}" ]; then
|
||||
found_items+=("二进制文件: ${INSTALL_DIR}/${BINARY_NAME}")
|
||||
fi
|
||||
|
||||
# 检查skills
|
||||
if [ -d "${HOME}/.gitlink/skills" ]; then
|
||||
found_items+=("Skills: ${HOME}/.gitlink/skills")
|
||||
fi
|
||||
|
||||
# 检查配置
|
||||
if [ -d "${HOME}/.config/gitlink-cli" ]; then
|
||||
found_items+=("配置: ${HOME}/.config/gitlink-cli")
|
||||
fi
|
||||
|
||||
if [ -d "${HOME}/.gitlink" ]; then
|
||||
found_items+=("GitLink数据: ${HOME}/.gitlink")
|
||||
fi
|
||||
|
||||
# 检查npm安装
|
||||
if npm list -g "@gitlink-ai/cli" >/dev/null 2>&1; then
|
||||
found_items+=("npm包: @gitlink-ai/cli (全局)")
|
||||
fi
|
||||
|
||||
if [ ${#found_items[@]} -eq 0 ]; then
|
||||
warn "未检测到 ${BINARY_NAME} 安装"
|
||||
return 1
|
||||
fi
|
||||
|
||||
info "检测到以下组件:"
|
||||
for item in "${found_items[@]}"; do
|
||||
echo " - ${item}"
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ---------- 删除二进制 ----------
|
||||
remove_binary() {
|
||||
if [ -z "${INSTALL_DIR}" ]; then
|
||||
warn "跳过二进制删除(未找到安装目录)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
step "删除二进制文件..."
|
||||
local binary_path="${INSTALL_DIR}/${BINARY_NAME}"
|
||||
|
||||
if [ ! -f "${binary_path}" ]; then
|
||||
warn "二进制文件不存在: ${binary_path}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 尝试删除
|
||||
if [ -w "${binary_path}" ]; then
|
||||
rm -f "${binary_path}"
|
||||
info "已删除: ${binary_path}"
|
||||
else
|
||||
if [ -w "${INSTALL_DIR}" ]; then
|
||||
rm -f "${binary_path}"
|
||||
info "已删除: ${binary_path}"
|
||||
else
|
||||
# 需要sudo权限
|
||||
warn "需要管理员权限删除二进制文件"
|
||||
if sudo rm -f "${binary_path}" 2>/dev/null; then
|
||||
info "已删除: ${binary_path}"
|
||||
else
|
||||
error "删除失败,请手动删除: ${binary_path}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- 删除Skills ----------
|
||||
remove_skills() {
|
||||
step "删除 Skills..."
|
||||
|
||||
if [ ! -d "${HOME}/.gitlink/skills" ]; then
|
||||
warn "Skills目录不存在: ${HOME}/.gitlink/skills"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 显示Skills信息
|
||||
local skill_count=$(find "${HOME}/.gitlink/skills" -maxdepth 1 -type d | wc -l)
|
||||
info "找到 ${skill_count} 个Skills"
|
||||
|
||||
# 删除
|
||||
rm -rf "${HOME}/.gitlink/skills"
|
||||
info "已删除Skills"
|
||||
}
|
||||
|
||||
# ---------- 删除配置 ----------
|
||||
remove_config() {
|
||||
if [ "$PURGE_ALL" != "true" ]; then
|
||||
ask "是否删除配置文件和数据? [y/N] "
|
||||
read -r response
|
||||
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||
info "保留配置文件"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
step "删除配置文件..."
|
||||
|
||||
local config_dirs=(
|
||||
"$HOME/.config/gitlink-cli"
|
||||
"$HOME/.gitlink"
|
||||
)
|
||||
|
||||
for dir in "${config_dirs[@]}"; do
|
||||
if [ -d "$dir" ]; then
|
||||
info "删除: $dir"
|
||||
rm -rf "$dir"
|
||||
fi
|
||||
done
|
||||
|
||||
info "配置文件已删除"
|
||||
}
|
||||
|
||||
# ---------- 卸载npm包 ----------
|
||||
uninstall_npm() {
|
||||
if ! npm list -g "@gitlink-ai/cli" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
step "卸载npm包..."
|
||||
|
||||
ask "检测到npm全局安装的 ${BINARY_NAME},是否卸载? [y/N] "
|
||||
read -r response
|
||||
|
||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
if npm uninstall -g "@gitlink-ai/cli" 2>/dev/null; then
|
||||
info "npm包已卸载"
|
||||
else
|
||||
warn "npm包卸载失败,请手动执行: npm uninstall -g @gitlink-ai/cli"
|
||||
fi
|
||||
else
|
||||
info "保留npm包"
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- 显示卸载摘要 ----------
|
||||
show_summary() {
|
||||
echo ""
|
||||
echo "========================================"
|
||||
info "卸载完成!"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
if [ "$PURGE_ALL" = "true" ]; then
|
||||
warn "已完全删除所有文件(包括配置)"
|
||||
else
|
||||
info "以下文件可能需要手动清理:"
|
||||
echo " - ${HOME}/.config/gitlink-cli"
|
||||
echo " - ${HOME}/.gitlink"
|
||||
echo ""
|
||||
info "如需删除,请重新运行: bash uninstall.sh --purge"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
info "感谢使用 GitLink CLI!"
|
||||
echo "如有任何问题,请访问: https://www.gitlink.org.cn/Gitlink/gitlink-cli/issues"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ---------- 确认卸载 ----------
|
||||
confirm_uninstall() {
|
||||
if [ "$AUTO_CONFIRM" = "true" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
warn "即将卸载 ${BINARY_NAME} 及相关文件"
|
||||
ask "确认继续? [y/N] "
|
||||
read -r response
|
||||
|
||||
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||
info "取消卸载"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- 主流程 ----------
|
||||
main() {
|
||||
# 解析参数
|
||||
PURGE_ALL="false"
|
||||
AUTO_CONFIRM="false"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--purge)
|
||||
PURGE_ALL="true"
|
||||
shift
|
||||
;;
|
||||
--yes|-y)
|
||||
AUTO_CONFIRM="true"
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "用法: bash uninstall.sh [选项]"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " --purge 删除所有文件(包括配置)"
|
||||
echo " --yes, -y 自动确认,不询问"
|
||||
echo " --help, -h 显示此帮助"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " bash uninstall.sh # 交互式卸载"
|
||||
echo " bash uninstall.sh --purge # 完全删除"
|
||||
echo " bash uninstall.sh -y # 自动确认"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
error "未知选项: $1"
|
||||
echo "使用 --help 查看帮助"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 欢迎信息
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " GitLink CLI 一键卸载"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# 查找二进制
|
||||
find_binary
|
||||
|
||||
# 检查安装状态
|
||||
if ! check_installation_status; then
|
||||
error "未检测到 ${BINARY_NAME} 安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 确认卸载
|
||||
confirm_uninstall
|
||||
|
||||
# 执行卸载
|
||||
remove_binary
|
||||
remove_skills
|
||||
remove_config
|
||||
uninstall_npm
|
||||
|
||||
# 显示摘要
|
||||
show_summary
|
||||
}
|
||||
|
||||
# 运行主流程
|
||||
main "$@"
|
||||
Loading…
Reference in New Issue