Merge pull request '改进安装功能,新增卸载功能' (#11) from zzx_branch into master

This commit is contained in:
zzx-coder 2026-06-04 14:47:46 +08:00
commit dc20c21790
12 changed files with 3177 additions and 13 deletions

View File

@ -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

View File

@ -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)
## 使用示例
### 仓库操作

715
doc/INSTALL.md Normal file
View File

@ -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)

317
doc/UNINSTALL.md Normal file
View File

@ -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+

441
install.ps1 Normal file
View File

@ -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

View File

@ -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 ""
}

175
npm/bin/uninstall.js Normal file
View File

@ -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);
}

View File

@ -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": [

162
npm/scripts/uninstall.js Normal file
View File

@ -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);
}

429
npm/scripts/update.js Normal file
View File

@ -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,
};

328
uninstall.ps1 Normal file
View File

@ -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
}

317
uninstall.sh Normal file
View File

@ -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 "$@"