merge: resolve conflict in Windows-Start.bat, add Linux scripts and maintain lib
This commit is contained in:
@@ -89,5 +89,6 @@ Release artifacts go to GitHub Releases, not the repo.
|
||||
|
||||
- Mac Apple Silicon (ARM64): ✅ Working
|
||||
- Windows x64: 🚧 In development
|
||||
- Linux x86_64: ✅ Working (scripts + live USB mode)
|
||||
- Linux ARM64: ✅ Working (scripts)
|
||||
- Mac Intel (x64): ❌ Not yet
|
||||
- Linux: ❌ Not yet
|
||||
|
||||
341
README.md
341
README.md
@@ -1,65 +1,107 @@
|
||||
# 🦞 U-Claw
|
||||
|
||||
**AI 助手 U 盘 — 克隆、补依赖、拷到 U 盘、双击运行**
|
||||
> **制作「插上就能用」的 AI 助手 U 盘 — 教程与源代码**
|
||||
> **Build a plug-and-play AI assistant USB drive — Tutorial & Source Code**
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
U-Claw 把 [OpenClaw](https://github.com/openclaw/openclaw) 打包成 U 盘便携版。这个代码库就是 U 盘里的全部内容,只是不上传大依赖(Node.js、node_modules)。运行 `setup.sh` 补齐依赖后,直接拷贝到 U 盘就能用。
|
||||
[中文](#中文) | [English](#english)
|
||||
|
||||
---
|
||||
|
||||
## 使用方式
|
||||
<a id="中文"></a>
|
||||
|
||||
## 中文
|
||||
|
||||
### 这是什么
|
||||
|
||||
这个仓库是一个**制作教程 + 全套源代码**,教你把 [OpenClaw](https://github.com/openclaw/openclaw)(开源 AI 助手框架)做成 U 盘——插上任意电脑,双击就能用 AI。
|
||||
|
||||
代码库本身就是 U 盘的文件骨架,运行 `setup.sh` 补齐大依赖后,整个 `portable/` 目录直接拷贝到 U 盘即可。
|
||||
|
||||
### 两种 U 盘模式
|
||||
|
||||
| | 便携版 U 盘 | Linux 启动盘 |
|
||||
|---|---|---|
|
||||
| **原理** | 在已有系统(Mac/Win/Linux)上运行 U 盘里的脚本 | 从 U 盘启动整个 Linux 系统 + OpenClaw |
|
||||
| **U 盘要求** | 4GB+ | **64GB+ USB 3.0**(USB 2.0 太慢不推荐) |
|
||||
| **依赖** | 电脑已有操作系统 | 不依赖任何已装系统 |
|
||||
| **适合** | 临时用、公共电脑、演示 | 专用 AI 工作站、无系统裸机 |
|
||||
|
||||
### 快速开始:制作便携版 U 盘
|
||||
|
||||
```bash
|
||||
# 1. 克隆代码
|
||||
git clone https://github.com/dongsheng123132/u-claw.git
|
||||
cd u-claw/portable
|
||||
bash setup.sh # 补齐大依赖(Node.js + OpenClaw,国内镜像,约 1 分钟)
|
||||
|
||||
# 2. 补齐大依赖(Node.js + OpenClaw,国内镜像,约 1 分钟)
|
||||
cd u-claw/portable && bash setup.sh
|
||||
|
||||
# 3. 拷贝到 U 盘
|
||||
cp -R portable/ /Volumes/你的U盘/U-Claw/ # Mac
|
||||
# 或 Windows 资源管理器直接拖过去
|
||||
```
|
||||
|
||||
**完成后 `portable/` 就是完整的 U 盘内容。** 拷贝到 U 盘即可:
|
||||
**完成!** 插上 U 盘,双击启动脚本就能用。
|
||||
|
||||
### 制作 Linux 启动盘
|
||||
|
||||
把整个 Linux 系统 + OpenClaw 刻在 U 盘,开机从 USB 启动直接进入 AI 助手桌面。
|
||||
|
||||
**准备:**
|
||||
- **64GB+ USB 3.0 U 盘**(推荐三星 BAR Plus、闪迪 CZ880 等高速盘)
|
||||
- Linux Mint ISO([清华镜像](https://mirrors.tuna.tsinghua.edu.cn/linuxmint-cd/stable/) / [中科大镜像](https://mirrors.ustc.edu.cn/linuxmint-cd/stable/))
|
||||
- Rufus v4.0+([rufus.ie](https://rufus.ie/zh/))
|
||||
|
||||
**步骤:**
|
||||
1. Rufus 刻录 ISO → 开启 **Persistent Storage**(8-16GB)
|
||||
2. USB 启动 → 进入 Linux Mint 桌面 → 连网
|
||||
3. 运行安装脚本:
|
||||
```bash
|
||||
# Mac
|
||||
cp -R portable/ /Volumes/你的U盘/U-Claw/
|
||||
|
||||
# 或直接在 Finder 拖过去
|
||||
curl -O https://raw.githubusercontent.com/dongsheng123132/u-claw/main/portable/setup-linux-usb.sh
|
||||
bash setup-linux-usb.sh
|
||||
```
|
||||
|
||||
## U 盘上能做什么
|
||||
详细图文教程见 [guide.html → Linux 启动盘模式](https://u-claw.org/guide.html)。
|
||||
|
||||
| 功能 | Mac | Windows | 说明 |
|
||||
|------|-----|---------|------|
|
||||
| **免安装运行** | `Mac-Start.command` | `Windows-Start.bat` | 双击直接跑,不碰电脑 |
|
||||
| **功能菜单** | `Mac-Menu.command` | `Windows-Menu.bat` | 配置、QQ、备份等 8 项 |
|
||||
| **安装到电脑** | `Mac-Install.command` | `Windows-Install.bat` | 离线优先,缺啥走国内镜像 |
|
||||
| **首次配置** | `Config.html` | `Config.html` | 浏览器打开,选模型填 Key |
|
||||
### U 盘功能一览
|
||||
|
||||
## U 盘文件结构
|
||||
| 功能 | Mac | Windows | Linux |
|
||||
|------|-----|---------|-------|
|
||||
| **免安装运行** | `Mac-Start.command` | `Windows-Start.bat` | `bash Linux-Start.sh` |
|
||||
| **功能菜单** | `Mac-Menu.command` | `Windows-Menu.bat` | `bash Linux-Menu.sh` |
|
||||
| **安装到电脑** | `Mac-Install.command` | `Windows-Install.bat` | `bash Linux-Install.sh` |
|
||||
| **首次配置** | `Config.html` | `Config.html` | `Config.html` |
|
||||
|
||||
### U 盘文件结构
|
||||
|
||||
```
|
||||
U-Claw/ ← 整个拷到 U 盘
|
||||
├── Mac-Start.command 双击 = Mac 免安装运行
|
||||
├── Mac-Menu.command 功能菜单(8 项)
|
||||
├── Mac-Start.command Mac 免安装运行
|
||||
├── Mac-Menu.command Mac 功能菜单
|
||||
├── Mac-Install.command 安装到 Mac
|
||||
├── Windows-Start.bat 双击 = Windows 免安装运行
|
||||
├── Windows-Menu.bat 功能菜单
|
||||
├── Windows-Start.bat Windows 免安装运行
|
||||
├── Windows-Menu.bat Windows 功能菜单
|
||||
├── Windows-Install.bat 安装到 Windows
|
||||
├── Linux-Start.sh Linux 免安装运行
|
||||
├── Linux-Menu.sh Linux 功能菜单
|
||||
├── Linux-Install.sh 安装到 Linux
|
||||
├── setup-linux-usb.sh Linux 启动盘内安装 OpenClaw
|
||||
├── Config.html 首次配置页面
|
||||
├── setup.sh 补齐依赖用(开发者用)
|
||||
├── setup.sh 补齐依赖(开发者用)
|
||||
├── app/ ← 大依赖(setup.sh 下载,不进 git)
|
||||
│ ├── core/ OpenClaw + QQ 插件
|
||||
│ └── runtime/
|
||||
│ ├── node-mac-arm64/ Mac Apple Silicon
|
||||
│ └── node-win-x64/ Windows 64-bit
|
||||
│ ├── node-win-x64/ Windows 64-bit
|
||||
│ └── node-linux-x64/ Linux x86_64
|
||||
└── data/ ← 用户数据(不进 git)
|
||||
├── .openclaw/ 配置文件
|
||||
├── memory/ AI 记忆
|
||||
└── backups/ 备份
|
||||
```
|
||||
|
||||
**代码库 = U 盘内容 - 大依赖。** `app/` 和 `data/` 在 `.gitignore` 里。
|
||||
|
||||
## 桌面安装版(Electron App)
|
||||
### 桌面安装版(Electron App)
|
||||
|
||||
除了 U 盘便携版,还有桌面 App 版本:
|
||||
|
||||
@@ -71,9 +113,9 @@ npm run build:mac-arm64 # 打包 → release/*.dmg
|
||||
npm run build:win # 打包 → release/*.exe
|
||||
```
|
||||
|
||||
## 支持的 AI 模型
|
||||
### 支持的 AI 模型
|
||||
|
||||
### 国产模型(无需翻墙)
|
||||
**国产模型(无需翻墙):**
|
||||
|
||||
| 模型 | 推荐场景 |
|
||||
|------|----------|
|
||||
@@ -84,11 +126,9 @@ npm run build:win # 打包 → release/*.exe
|
||||
| MiniMax | 语音多模态 |
|
||||
| 豆包 Doubao | 火山引擎 |
|
||||
|
||||
### 国际模型
|
||||
**国际模型:** Claude · GPT · Gemini(需翻墙或中转)
|
||||
|
||||
Claude · GPT · Gemini(需翻墙或中转)
|
||||
|
||||
## 支持的聊天平台
|
||||
### 支持的聊天平台
|
||||
|
||||
| 平台 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
@@ -99,7 +139,7 @@ Claude · GPT · Gemini(需翻墙或中转)
|
||||
| Discord | ✅ 内置 | — |
|
||||
| 微信 | ✅ 社区插件 | iPad 协议 |
|
||||
|
||||
## 国内镜像
|
||||
### 国内镜像
|
||||
|
||||
所有脚本默认走国内镜像,无需翻墙:
|
||||
|
||||
@@ -109,60 +149,42 @@ Claude · GPT · Gemini(需翻墙或中转)
|
||||
| Node.js | `npmmirror.com/mirrors/node` |
|
||||
| Electron | `npmmirror.com/mirrors/electron` |
|
||||
|
||||
## 开发 & 测试
|
||||
### 开发 & 贡献
|
||||
|
||||
```bash
|
||||
# 克隆
|
||||
git clone https://github.com/dongsheng123132/u-claw.git
|
||||
|
||||
# 补依赖
|
||||
cd u-claw/portable && bash setup.sh
|
||||
|
||||
# 测试启动
|
||||
bash Mac-Start.command # Mac
|
||||
# 或 Windows-Start.bat # Windows
|
||||
|
||||
# 测试没问题 → 拷到 U 盘
|
||||
# 有问题 → 修代码 → 重新测试
|
||||
bash Mac-Start.command # Mac 测试
|
||||
bash Linux-Start.sh # Linux 测试
|
||||
```
|
||||
|
||||
### 提交代码
|
||||
**平台支持:**
|
||||
|
||||
```bash
|
||||
git checkout -b feat/your-feature
|
||||
git add -A
|
||||
git commit -m "feat: your change"
|
||||
git push -u origin feat/your-feature
|
||||
```
|
||||
| 平台 | 状态 |
|
||||
|------|------|
|
||||
| Mac Apple Silicon (M1-M4) | ✅ |
|
||||
| Linux x86_64 | ✅ |
|
||||
| Linux ARM64 | ✅ |
|
||||
| Windows x64 | 🚧 开发中 |
|
||||
| Mac Intel | ❌ 暂不支持 |
|
||||
|
||||
## 待开发 / 欢迎贡献
|
||||
欢迎 PR!特别需要:Windows 脚本完善、新平台支持、教程翻译。
|
||||
|
||||
- [ ] Windows 便携版完善测试
|
||||
- [ ] Mac Intel 支持
|
||||
- [ ] Linux 支持(AppImage)
|
||||
- [ ] 桌面版自动更新
|
||||
- [ ] SkillHub 技能市场功能完善
|
||||
- [ ] 多语言支持(English UI)
|
||||
|
||||
## FAQ
|
||||
### FAQ
|
||||
|
||||
**Q: 需要翻墙吗?**
|
||||
安装不需要。运行需要联网调 API,国产模型无需翻墙。
|
||||
不需要。安装和运行全程使用国内镜像,国产模型 API 直连。
|
||||
|
||||
**Q: U 盘需要多大?**
|
||||
建议 4GB 以上(完整版约 2.3GB)。
|
||||
便携版 4GB+(完整约 2.3GB)。Linux 启动盘 64GB+ USB 3.0。
|
||||
|
||||
**Q: 能分发吗?**
|
||||
MIT 协议,随便复制。
|
||||
MIT 协议,随便复制分发。
|
||||
|
||||
**Q: Mac 提示"未验证的开发者"?**
|
||||
右键脚本 → 打开。
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
## 联系
|
||||
### 联系
|
||||
|
||||
- 微信: hecare888
|
||||
- GitHub: [@dongsheng123132](https://github.com/dongsheng123132)
|
||||
@@ -170,4 +192,185 @@ MIT 协议,随便复制。
|
||||
|
||||
---
|
||||
|
||||
<a id="english"></a>
|
||||
|
||||
## English
|
||||
|
||||
### What is this
|
||||
|
||||
This repo is a **tutorial + complete source code** for building an [OpenClaw](https://github.com/openclaw/openclaw) (open-source AI assistant framework) USB drive — plug it into any computer, double-click, and start using AI.
|
||||
|
||||
The codebase itself is the USB file skeleton. Run `setup.sh` to download large dependencies, then copy the entire `portable/` directory to a USB drive.
|
||||
|
||||
### Two USB modes
|
||||
|
||||
| | Portable USB | Linux Live USB |
|
||||
|---|---|---|
|
||||
| **How it works** | Runs scripts from USB on existing OS (Mac/Win/Linux) | Boots entire Linux system + OpenClaw from USB |
|
||||
| **USB requirement** | 4GB+ | **64GB+ USB 3.0** (USB 2.0 too slow) |
|
||||
| **Depends on** | Existing OS on computer | Nothing — boots independently |
|
||||
| **Best for** | Temporary use, public computers, demos | Dedicated AI workstation, bare metal |
|
||||
|
||||
### Quick Start: Build a Portable USB
|
||||
|
||||
```bash
|
||||
# 1. Clone
|
||||
git clone https://github.com/dongsheng123132/u-claw.git
|
||||
|
||||
# 2. Download dependencies (Node.js + OpenClaw, ~1 min)
|
||||
cd u-claw/portable && bash setup.sh
|
||||
|
||||
# 3. Copy to USB drive
|
||||
cp -R portable/ /Volumes/YOUR_USB/U-Claw/ # Mac
|
||||
# Or drag & drop on Windows/Linux
|
||||
```
|
||||
|
||||
**Done!** Plug in the USB, double-click the start script, and you're running AI.
|
||||
|
||||
### Build a Linux Live USB
|
||||
|
||||
Boot an entire Linux system + OpenClaw directly from USB — no existing OS required.
|
||||
|
||||
**You need:**
|
||||
- **64GB+ USB 3.0 drive** (recommended: Samsung BAR Plus, SanDisk Extreme)
|
||||
- Linux Mint ISO ([linuxmint.com](https://linuxmint.com/download.php))
|
||||
- Rufus v4.0+ ([rufus.ie](https://rufus.ie/en/))
|
||||
|
||||
**Steps:**
|
||||
1. Flash ISO with Rufus → enable **Persistent Storage** (8-16GB)
|
||||
2. Boot from USB → enter Linux Mint desktop → connect to internet
|
||||
3. Run the install script:
|
||||
```bash
|
||||
curl -O https://raw.githubusercontent.com/dongsheng123132/u-claw/main/portable/setup-linux-usb.sh
|
||||
bash setup-linux-usb.sh
|
||||
```
|
||||
|
||||
Full guide at [guide.html → Linux Live USB](https://u-claw.org/guide.html).
|
||||
|
||||
### USB Features
|
||||
|
||||
| Feature | Mac | Windows | Linux |
|
||||
|---------|-----|---------|-------|
|
||||
| **Run (no install)** | `Mac-Start.command` | `Windows-Start.bat` | `bash Linux-Start.sh` |
|
||||
| **Menu** | `Mac-Menu.command` | `Windows-Menu.bat` | `bash Linux-Menu.sh` |
|
||||
| **Install to PC** | `Mac-Install.command` | `Windows-Install.bat` | `bash Linux-Install.sh` |
|
||||
| **First-time config** | `Config.html` | `Config.html` | `Config.html` |
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
U-Claw/ ← Copy entire folder to USB
|
||||
├── Mac-Start.command Mac launcher
|
||||
├── Mac-Menu.command Mac menu (8 options)
|
||||
├── Mac-Install.command Install to Mac
|
||||
├── Windows-Start.bat Windows launcher
|
||||
├── Windows-Menu.bat Windows menu
|
||||
├── Windows-Install.bat Install to Windows
|
||||
├── Linux-Start.sh Linux launcher
|
||||
├── Linux-Menu.sh Linux menu
|
||||
├── Linux-Install.sh Install to Linux
|
||||
├── setup-linux-usb.sh Install OpenClaw in Linux live USB
|
||||
├── Config.html First-time config page
|
||||
├── setup.sh Download dependencies (dev use)
|
||||
├── app/ ← Large deps (downloaded by setup.sh, not in git)
|
||||
│ ├── core/ OpenClaw + QQ plugin
|
||||
│ └── runtime/
|
||||
│ ├── node-mac-arm64/ Mac Apple Silicon
|
||||
│ ├── node-win-x64/ Windows 64-bit
|
||||
│ └── node-linux-x64/ Linux x86_64
|
||||
└── data/ ← User data (not in git)
|
||||
├── .openclaw/ Config file
|
||||
├── memory/ AI memory
|
||||
└── backups/ Backups
|
||||
```
|
||||
|
||||
### Desktop App (Electron)
|
||||
|
||||
```bash
|
||||
cd u-claw-app
|
||||
bash setup.sh # One-click dev setup (China mirrors)
|
||||
npm run dev # Dev mode
|
||||
npm run build:mac-arm64 # Build → release/*.dmg
|
||||
npm run build:win # Build → release/*.exe
|
||||
```
|
||||
|
||||
### Supported AI Models
|
||||
|
||||
**Chinese models (no VPN needed):**
|
||||
|
||||
| Model | Best for |
|
||||
|-------|----------|
|
||||
| DeepSeek | Coding, extremely cheap |
|
||||
| Kimi K2.5 | Long documents, 256K context |
|
||||
| Qwen | Large free tier |
|
||||
| GLM (Zhipu) | Academic use |
|
||||
| MiniMax | Voice & multimodal |
|
||||
| Doubao | Volcengine ecosystem |
|
||||
|
||||
**International models:** Claude · GPT · Gemini (VPN or relay required in China)
|
||||
|
||||
### Supported Chat Platforms
|
||||
|
||||
| Platform | Status | Notes |
|
||||
|----------|--------|-------|
|
||||
| QQ | ✅ Pre-installed | Enter AppID + Secret |
|
||||
| Feishu (Lark) | ✅ Built-in | Enterprise favorite |
|
||||
| Telegram | ✅ Built-in | International |
|
||||
| WhatsApp | ✅ Built-in | Baileys protocol |
|
||||
| Discord | ✅ Built-in | — |
|
||||
| WeChat | ✅ Community plugin | iPad protocol |
|
||||
|
||||
### China Mirrors
|
||||
|
||||
All scripts use China mirrors by default — no VPN needed:
|
||||
|
||||
| Resource | Mirror |
|
||||
|----------|--------|
|
||||
| npm packages | `registry.npmmirror.com` |
|
||||
| Node.js | `npmmirror.com/mirrors/node` |
|
||||
| Electron | `npmmirror.com/mirrors/electron` |
|
||||
|
||||
### Development & Contributing
|
||||
|
||||
```bash
|
||||
git clone https://github.com/dongsheng123132/u-claw.git
|
||||
cd u-claw/portable && bash setup.sh
|
||||
bash Mac-Start.command # Test on Mac
|
||||
bash Linux-Start.sh # Test on Linux
|
||||
```
|
||||
|
||||
**Platform Support:**
|
||||
|
||||
| Platform | Status |
|
||||
|----------|--------|
|
||||
| Mac Apple Silicon (M1-M4) | ✅ |
|
||||
| Linux x86_64 | ✅ |
|
||||
| Linux ARM64 | ✅ |
|
||||
| Windows x64 | 🚧 In progress |
|
||||
| Mac Intel | ❌ Not yet |
|
||||
|
||||
PRs welcome! Especially: Windows scripts, new platform support, documentation.
|
||||
|
||||
### FAQ
|
||||
|
||||
**Q: Do I need a VPN?**
|
||||
No. All downloads use China mirrors. Chinese AI model APIs work directly.
|
||||
|
||||
**Q: How big should the USB drive be?**
|
||||
Portable mode: 4GB+ (~2.3GB full). Linux live USB: 64GB+ USB 3.0.
|
||||
|
||||
**Q: Can I redistribute?**
|
||||
MIT license — copy and share freely.
|
||||
|
||||
**Q: Mac says "unverified developer"?**
|
||||
Right-click the script → Open.
|
||||
|
||||
### Contact
|
||||
|
||||
- WeChat: hecare888
|
||||
- GitHub: [@dongsheng123132](https://github.com/dongsheng123132)
|
||||
- Website: [u-claw.org](https://u-claw.org)
|
||||
|
||||
---
|
||||
|
||||
**Made with 🦞 by [dongsheng](https://github.com/dongsheng123132)**
|
||||
|
||||
273
portable/Linux-Install.sh
Executable file
273
portable/Linux-Install.sh
Executable file
@@ -0,0 +1,273 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# U-Claw - Install to Linux (从 U 盘安装到电脑)
|
||||
# 优先使用 U 盘内的离线资源,缺失时从国内镜像下载
|
||||
# ============================================================
|
||||
|
||||
set -e
|
||||
|
||||
UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
APP_DIR="$UCLAW_DIR/app"
|
||||
INSTALL_TARGET="$HOME/.uclaw"
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
CYAN='\033[0;36m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
|
||||
NODE_VER="v22.14.0"
|
||||
MIRROR="https://registry.npmmirror.com"
|
||||
NODE_MIRROR="https://npmmirror.com/mirrors/node"
|
||||
|
||||
clear
|
||||
echo ""
|
||||
echo -e "${CYAN}${BOLD}"
|
||||
echo " ╔══════════════════════════════════════╗"
|
||||
echo " ║ U-Claw 安装到 Linux ║"
|
||||
echo " ║ 从 U 盘离线安装 ║"
|
||||
echo " ╚══════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- Check CPU ----
|
||||
ARCH=$(uname -m)
|
||||
if [ "$ARCH" = "x86_64" ]; then
|
||||
echo -e " ${GREEN}Linux x86_64 ✓${NC}"
|
||||
NODE_PLATFORM="node-linux-x64"
|
||||
elif [ "$ARCH" = "aarch64" ]; then
|
||||
echo -e " ${GREEN}Linux ARM64 ✓${NC}"
|
||||
NODE_PLATFORM="node-linux-arm64"
|
||||
else
|
||||
echo -e " ${RED}Unsupported architecture: $ARCH${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ---- Check existing installation ----
|
||||
if [ -d "$INSTALL_TARGET" ]; then
|
||||
echo -e " ${YELLOW}检测到已有安装: $INSTALL_TARGET${NC}"
|
||||
read -p " 覆盖安装?(y/n): " -n 1 OVERWRITE
|
||||
echo ""
|
||||
if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then
|
||||
echo -e " ${DIM}已取消${NC}"
|
||||
exit 0
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ---- Step 1: Check environment ----
|
||||
echo -e " ${BOLD}[1/4] 检查环境...${NC}"
|
||||
|
||||
NEED_DOWNLOAD_NODE=false
|
||||
NEED_DOWNLOAD_OPENCLAW=false
|
||||
|
||||
# Check Node.js - prefer USB, then system, then download
|
||||
USB_NODE="$APP_DIR/runtime/$NODE_PLATFORM/bin/node"
|
||||
USB_NPM="$APP_DIR/runtime/$NODE_PLATFORM/bin/npm"
|
||||
|
||||
if [ -f "$USB_NODE" ]; then
|
||||
echo -e " ${GREEN}Node.js: 使用 U 盘内的 ($("$USB_NODE" --version))${NC}"
|
||||
USE_NODE="usb"
|
||||
elif command -v node >/dev/null 2>&1; then
|
||||
SYS_VER=$(node --version)
|
||||
MAJOR=$(echo "$SYS_VER" | sed 's/v//' | cut -d. -f1)
|
||||
if [ "$MAJOR" -ge 20 ] 2>/dev/null; then
|
||||
echo -e " ${GREEN}Node.js: 使用系统的 ($SYS_VER)${NC}"
|
||||
USE_NODE="system"
|
||||
else
|
||||
echo -e " ${YELLOW}Node.js: 系统版本太低 ($SYS_VER),需要 v20+${NC}"
|
||||
NEED_DOWNLOAD_NODE=true
|
||||
USE_NODE="download"
|
||||
fi
|
||||
else
|
||||
echo -e " ${YELLOW}Node.js: 未安装${NC}"
|
||||
NEED_DOWNLOAD_NODE=true
|
||||
USE_NODE="download"
|
||||
fi
|
||||
|
||||
# Check OpenClaw
|
||||
USB_OPENCLAW="$APP_DIR/core/node_modules/openclaw/openclaw.mjs"
|
||||
if [ -f "$USB_OPENCLAW" ]; then
|
||||
echo -e " ${GREEN}OpenClaw: 使用 U 盘内的${NC}"
|
||||
USE_OPENCLAW="usb"
|
||||
else
|
||||
echo -e " ${YELLOW}OpenClaw: U 盘内未找到,需要在线下载${NC}"
|
||||
NEED_DOWNLOAD_OPENCLAW=true
|
||||
USE_OPENCLAW="download"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ---- Step 2: Create install directory ----
|
||||
echo -e " ${BOLD}[2/4] 安装到 $INSTALL_TARGET ...${NC}"
|
||||
|
||||
mkdir -p "$INSTALL_TARGET"
|
||||
mkdir -p "$INSTALL_TARGET/data/.openclaw"
|
||||
mkdir -p "$INSTALL_TARGET/data/memory"
|
||||
mkdir -p "$INSTALL_TARGET/data/backups"
|
||||
|
||||
# ---- Step 3: Copy/Download Node.js ----
|
||||
echo -e " ${BOLD}[3/4] 安装 Node.js...${NC}"
|
||||
|
||||
NODE_INSTALL_DIR="$INSTALL_TARGET/runtime/$NODE_PLATFORM"
|
||||
|
||||
case $USE_NODE in
|
||||
usb)
|
||||
echo -e " ${CYAN}从 U 盘复制 Node.js...${NC}"
|
||||
mkdir -p "$NODE_INSTALL_DIR"
|
||||
cp -R "$APP_DIR/runtime/$NODE_PLATFORM/"* "$NODE_INSTALL_DIR/"
|
||||
chmod +x "$NODE_INSTALL_DIR/bin/node"
|
||||
INSTALL_NODE="$NODE_INSTALL_DIR/bin/node"
|
||||
INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm"
|
||||
echo -e " ${GREEN}Node.js 安装完成 ✓${NC}"
|
||||
;;
|
||||
system)
|
||||
INSTALL_NODE="$(which node)"
|
||||
INSTALL_NPM="$(which npm)"
|
||||
echo -e " ${GREEN}使用系统 Node.js ✓${NC}"
|
||||
;;
|
||||
download)
|
||||
echo -e " ${CYAN}从国内镜像下载 Node.js $NODE_VER...${NC}"
|
||||
PLATFORM_NAME="linux-$( [ "$ARCH" = "x86_64" ] && echo "x64" || echo "arm64" )"
|
||||
TARBALL="node-${NODE_VER}-${PLATFORM_NAME}.tar.gz"
|
||||
URL="${NODE_MIRROR}/${NODE_VER}/${TARBALL}"
|
||||
|
||||
mkdir -p "$NODE_INSTALL_DIR"
|
||||
curl -# -L "$URL" -o "/tmp/$TARBALL"
|
||||
tar -xzf "/tmp/$TARBALL" -C "$NODE_INSTALL_DIR" --strip-components=1
|
||||
rm -f "/tmp/$TARBALL"
|
||||
chmod +x "$NODE_INSTALL_DIR/bin/node"
|
||||
INSTALL_NODE="$NODE_INSTALL_DIR/bin/node"
|
||||
INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm"
|
||||
echo -e " ${GREEN}Node.js 下载安装完成 ✓${NC}"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
|
||||
# ---- Step 4: Copy/Download OpenClaw ----
|
||||
echo -e " ${BOLD}[4/4] 安装 OpenClaw...${NC}"
|
||||
|
||||
CORE_INSTALL_DIR="$INSTALL_TARGET/core"
|
||||
|
||||
case $USE_OPENCLAW in
|
||||
usb)
|
||||
echo -e " ${CYAN}从 U 盘复制 OpenClaw + 插件...${NC}"
|
||||
mkdir -p "$CORE_INSTALL_DIR"
|
||||
cp -R "$APP_DIR/core/"* "$CORE_INSTALL_DIR/"
|
||||
echo -e " ${GREEN}OpenClaw 安装完成 ✓${NC}"
|
||||
;;
|
||||
download)
|
||||
echo -e " ${CYAN}从国内镜像下载 OpenClaw...${NC}"
|
||||
mkdir -p "$CORE_INSTALL_DIR"
|
||||
cat > "$CORE_INSTALL_DIR/package.json" << 'PKGEOF'
|
||||
{
|
||||
"name": "u-claw-core",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"openclaw": "latest"
|
||||
}
|
||||
}
|
||||
PKGEOF
|
||||
cd "$CORE_INSTALL_DIR"
|
||||
"$INSTALL_NODE" "$INSTALL_NPM" install --registry="$MIRROR" 2>&1 | tail -3
|
||||
"$INSTALL_NODE" "$INSTALL_NPM" install @sliverp/qqbot@latest --registry="$MIRROR" 2>&1 | tail -2
|
||||
echo -e " ${GREEN}OpenClaw 下载安装完成 ✓${NC}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# ---- Default config ----
|
||||
CONFIG_PATH="$INSTALL_TARGET/data/.openclaw/openclaw.json"
|
||||
if [ ! -f "$CONFIG_PATH" ]; then
|
||||
cat > "$CONFIG_PATH" << 'CFGEOF'
|
||||
{
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"auth": { "token": "uclaw" }
|
||||
}
|
||||
}
|
||||
CFGEOF
|
||||
fi
|
||||
|
||||
# ---- Copy HTML pages ----
|
||||
for f in Config.html U-Claw.html; do
|
||||
[ -f "$UCLAW_DIR/$f" ] && cp "$UCLAW_DIR/$f" "$INSTALL_TARGET/"
|
||||
done
|
||||
|
||||
# ---- Create launch script ----
|
||||
cat > "$INSTALL_TARGET/start.sh" << 'STARTEOF'
|
||||
#!/bin/bash
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ARCH=$(uname -m)
|
||||
NODE_PLATFORM="node-linux-$( [ "$ARCH" = "x86_64" ] && echo "x64" || echo "arm64" )"
|
||||
|
||||
NODE_BIN="$DIR/runtime/$NODE_PLATFORM/bin/node"
|
||||
[ ! -f "$NODE_BIN" ] && NODE_BIN="$(which node)"
|
||||
|
||||
CORE_DIR="$DIR/core"
|
||||
OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs"
|
||||
|
||||
export OPENCLAW_HOME="$DIR/data"
|
||||
export OPENCLAW_STATE_DIR="$DIR/data/.openclaw"
|
||||
export OPENCLAW_CONFIG_PATH="$DIR/data/.openclaw/openclaw.json"
|
||||
|
||||
PORT=18789
|
||||
while ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; do
|
||||
PORT=$((PORT + 1))
|
||||
[ $PORT -gt 18799 ] && echo "No available port" && exit 1
|
||||
done
|
||||
|
||||
cd "$CORE_DIR"
|
||||
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT &
|
||||
PID=$!
|
||||
|
||||
for i in $(seq 1 30); do
|
||||
sleep 0.5
|
||||
if curl -s -o /dev/null "http://127.0.0.1:$PORT/" 2>/dev/null; then
|
||||
xdg-open "http://127.0.0.1:$PORT/#token=uclaw" 2>/dev/null || echo "Open: http://127.0.0.1:$PORT/#token=uclaw"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
wait $PID
|
||||
STARTEOF
|
||||
chmod +x "$INSTALL_TARGET/start.sh"
|
||||
|
||||
# ---- Create desktop shortcut ----
|
||||
DESKTOP_FILE="$HOME/.local/share/applications/u-claw.desktop"
|
||||
mkdir -p "$HOME/.local/share/applications"
|
||||
cat > "$DESKTOP_FILE" << DESKEOF
|
||||
[Desktop Entry]
|
||||
Name=U-Claw
|
||||
Comment=Portable AI Agent
|
||||
Exec=bash $INSTALL_TARGET/start.sh
|
||||
Terminal=true
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
DESKEOF
|
||||
|
||||
echo ""
|
||||
|
||||
# ---- Summary ----
|
||||
INSTALL_SIZE=$(du -sh "$INSTALL_TARGET" | cut -f1)
|
||||
|
||||
echo -e " ${GREEN}${BOLD}╔══════════════════════════════════════╗"
|
||||
echo -e " ║ ✅ 安装成功! ║"
|
||||
echo -e " ╚══════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e " ${BOLD}安装位置:${NC} $INSTALL_TARGET"
|
||||
echo -e " ${BOLD}大小:${NC} $INSTALL_SIZE"
|
||||
echo ""
|
||||
echo -e " ${BOLD}启动方式:${NC}"
|
||||
echo -e " 终端运行: ${CYAN}bash ~/.uclaw/start.sh${NC}"
|
||||
echo -e " 或在应用菜单搜索 ${CYAN}U-Claw${NC}"
|
||||
echo ""
|
||||
echo -e " ${BOLD}首次使用:${NC}"
|
||||
echo -e " 启动后浏览器自动打开配置页面"
|
||||
echo -e " 选择 AI 模型 → 填写 API Key → 开始用"
|
||||
echo ""
|
||||
read -p " 按回车关闭..."
|
||||
300
portable/Linux-Menu.sh
Executable file
300
portable/Linux-Menu.sh
Executable file
@@ -0,0 +1,300 @@
|
||||
#!/bin/bash
|
||||
# U-Claw Menu - Portable AI Agent
|
||||
# Linux version
|
||||
|
||||
UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
APP_DIR="$UCLAW_DIR/app"
|
||||
CORE_DIR="$APP_DIR/core"
|
||||
DATA_DIR="$UCLAW_DIR/data"
|
||||
STATE_DIR="$DATA_DIR/.openclaw"
|
||||
CONFIG_PATH="$STATE_DIR/openclaw.json"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
WHITE='\033[1;37m'
|
||||
NC='\033[0m'
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
|
||||
# Node.js
|
||||
ARCH=$(uname -m)
|
||||
if [ "$ARCH" = "x86_64" ]; then
|
||||
NODE_DIR="$APP_DIR/runtime/node-linux-x64"
|
||||
elif [ "$ARCH" = "aarch64" ]; then
|
||||
NODE_DIR="$APP_DIR/runtime/node-linux-arm64"
|
||||
else
|
||||
echo -e "${RED}Unsupported architecture: $ARCH${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NODE_BIN="$NODE_DIR/bin/node"
|
||||
NPM_BIN="$NODE_DIR/bin/npm"
|
||||
export PATH="$NODE_DIR/bin:$PATH"
|
||||
export OPENCLAW_HOME="$DATA_DIR"
|
||||
export OPENCLAW_STATE_DIR="$STATE_DIR"
|
||||
export OPENCLAW_CONFIG_PATH="$CONFIG_PATH"
|
||||
|
||||
mkdir -p "$STATE_DIR" "$DATA_DIR/memory" "$DATA_DIR/backups" "$DATA_DIR/logs"
|
||||
|
||||
# Load maintenance functions
|
||||
source "$UCLAW_DIR/lib/maintain.sh"
|
||||
|
||||
# Run openclaw command
|
||||
OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs"
|
||||
|
||||
run_oc() {
|
||||
cd "$CORE_DIR"
|
||||
"$NODE_BIN" "$OPENCLAW_MJS" "$@"
|
||||
}
|
||||
|
||||
# Show menu
|
||||
show_menu() {
|
||||
clear
|
||||
local NODE_VER=$("$NODE_BIN" --version 2>/dev/null || echo "N/A")
|
||||
local CFG_STATUS="${RED}未配置${NC}"
|
||||
[ -f "$CONFIG_PATH" ] && CFG_STATUS="${GREEN}已配置${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}╔══════════════════════════════════════╗"
|
||||
echo -e " ║ U-Claw 虾盘 v1.1 ║"
|
||||
echo -e " ║ Portable AI Agent (Linux) ║"
|
||||
echo -e " ╚══════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e " Node: ${GREEN}${NODE_VER}${NC} 配置: ${CFG_STATUS}"
|
||||
echo ""
|
||||
echo -e " ${WHITE}${BOLD}── 配置 ──────────────────────────────${NC}"
|
||||
echo -e " ${GREEN}[1]${NC} 配置向导(选模型、填 API Key)"
|
||||
echo -e " ${GREEN}[2]${NC} 打开网页控制台"
|
||||
echo ""
|
||||
echo -e " ${WHITE}${BOLD}── 聊天平台 ──────────────────────────${NC}"
|
||||
echo -e " ${GREEN}[3]${NC} 接入 QQ 机器人(推荐,1分钟搞定)"
|
||||
echo -e " ${GREEN}[4]${NC} 接入其他平台(飞书/Telegram/微信)"
|
||||
echo ""
|
||||
echo -e " ${WHITE}${BOLD}── 维护 ──────────────────────────────${NC}"
|
||||
echo -e " ${GREEN}[5]${NC} 诊断修复"
|
||||
echo -e " ${GREEN}[6]${NC} 备份配置"
|
||||
echo -e " ${GREEN}[7]${NC} 恢复备份"
|
||||
echo -e " ${GREEN}[8]${NC} 系统信息"
|
||||
echo ""
|
||||
echo -e " ${WHITE}${BOLD}── 高级维护 ──────────────────────────${NC}"
|
||||
echo -e " ${GREEN}[9]${NC} 杀死残留进程"
|
||||
echo -e " ${GREEN}[10]${NC} 查看日志"
|
||||
echo -e " ${GREEN}[11]${NC} 恢复出厂设置"
|
||||
echo -e " ${GREEN}[12]${NC} 卸载"
|
||||
echo -e " ${GREEN}[13]${NC} 检查更新"
|
||||
echo -e " ${GREEN}[14]${NC} 清理空间"
|
||||
echo -e " ${GREEN}[15]${NC} 插件管理"
|
||||
echo ""
|
||||
echo -e " ${DIM}[0] 退出${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# [1] Config wizard
|
||||
do_config() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 配置向导 ━━━${NC}"
|
||||
echo ""
|
||||
echo -e " ${WHITE}国产模型选择提示:${NC}"
|
||||
echo ""
|
||||
echo -e " DeepSeek → 选 Custom Provider"
|
||||
echo -e " URL: https://api.deepseek.com/v1"
|
||||
echo -e " 模型: deepseek-chat"
|
||||
echo -e " Kimi → 选 Moonshot AI"
|
||||
echo -e " 通义千问 → 选 Qwen"
|
||||
echo -e " 豆包 → 选 Volcano Engine"
|
||||
echo ""
|
||||
read -p " 按回车启动配置向导..."
|
||||
run_oc onboard
|
||||
}
|
||||
|
||||
# [2] Web dashboard
|
||||
do_dashboard() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}启动网页控制台...${NC}"
|
||||
echo ""
|
||||
cd "$CORE_DIR"
|
||||
|
||||
# Find free port
|
||||
local PORT=18789
|
||||
while ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; do
|
||||
PORT=$((PORT + 1))
|
||||
if [ $PORT -gt 18799 ]; then
|
||||
echo -e " ${RED}端口 18789-18799 全被占用${NC}"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
local TOKEN=$(python3 -c "import json,os; p='$CONFIG_PATH'; d=json.load(open(p)) if os.path.exists(p) else {}; print(d.get('gateway',{}).get('auth',{}).get('token','uclaw'))" 2>/dev/null || echo "uclaw")
|
||||
|
||||
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT &
|
||||
local PID=$!
|
||||
|
||||
for i in $(seq 1 30); do
|
||||
sleep 0.5
|
||||
if curl --noproxy '*' -s -o /dev/null "http://127.0.0.1:$PORT/" 2>/dev/null; then
|
||||
local URL="http://127.0.0.1:$PORT/#token=$TOKEN"
|
||||
echo -e " ${GREEN}控制台: $URL${NC}"
|
||||
xdg-open "$URL" 2>/dev/null || echo -e " ${YELLOW}请在浏览器打开: $URL${NC}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo " 关闭此窗口会停止服务"
|
||||
wait $PID
|
||||
}
|
||||
|
||||
# [3] QQ Bot (pre-installed)
|
||||
do_qq() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 接入 QQ 机器人 ━━━${NC}"
|
||||
echo ""
|
||||
echo -e " ${GREEN}QQ 插件已预装!只需输入 AppID 和 AppSecret。${NC}"
|
||||
echo ""
|
||||
echo " 获取方式: 访问 q.qq.com → 创建机器人"
|
||||
echo ""
|
||||
read -p " AppID: " QQ_ID
|
||||
read -p " AppSecret: " QQ_SECRET
|
||||
echo ""
|
||||
|
||||
if [ -z "$QQ_ID" ] || [ -z "$QQ_SECRET" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
run_oc channels add --channel qqbot --token "${QQ_ID}:${QQ_SECRET}" 2>&1 || true
|
||||
echo ""
|
||||
read -p " 你的 QQ 号(设白名单,留空跳过): " QQ_ALLOW
|
||||
if [ -n "$QQ_ALLOW" ]; then
|
||||
run_oc config set channels.qqbot.allowFrom "\"${QQ_ALLOW}\"" 2>&1 || true
|
||||
echo -e " ${GREEN}白名单已设置${NC}"
|
||||
fi
|
||||
echo ""
|
||||
echo -e " ${GREEN}QQ 机器人配置完成!重启网关后生效。${NC}"
|
||||
}
|
||||
|
||||
# [4] Other platforms
|
||||
do_platforms() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 其他聊天平台 ━━━${NC}"
|
||||
echo ""
|
||||
echo -e " ${GREEN}[a]${NC} 飞书 Feishu — 企业首选"
|
||||
echo -e " ${GREEN}[b]${NC} Telegram — 海外推荐"
|
||||
echo -e " ${GREEN}[c]${NC} 微信(社区插件) — iPad协议"
|
||||
echo -e " ${GREEN}[d]${NC} Discord"
|
||||
echo ""
|
||||
read -p " 选择 (a-d): " -n 1 CH
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
case $CH in
|
||||
a) echo " 飞书: 访问 open.feishu.cn/app 创建应用" ;;
|
||||
b) echo " Telegram: 找 @BotFather 创建机器人" ;;
|
||||
c)
|
||||
echo -e " ${YELLOW}安装微信插件...${NC}"
|
||||
run_oc plugins install @icesword760/openclaw-wechat 2>&1 || true
|
||||
;;
|
||||
d) echo " Discord: 访问 discord.com/developers/applications" ;;
|
||||
*) echo " 无效选择" ;;
|
||||
esac
|
||||
echo ""
|
||||
echo " 配置完成后运行配置向导 [1] 绑定平台"
|
||||
}
|
||||
|
||||
# [5] Doctor
|
||||
do_doctor() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}━━━ 诊断修复 ━━━${NC}"
|
||||
echo ""
|
||||
run_oc doctor --repair 2>&1 || echo -e " ${YELLOW}诊断命令执行失败${NC}"
|
||||
}
|
||||
|
||||
# [6] Backup
|
||||
do_backup() {
|
||||
echo ""
|
||||
local TS=$(date +%Y%m%d_%H%M%S)
|
||||
local BK="$DATA_DIR/backups/backup_$TS"
|
||||
mkdir -p "$BK"
|
||||
|
||||
[ -f "$CONFIG_PATH" ] && cp "$CONFIG_PATH" "$BK/" && echo -e " ${GREEN} + openclaw.json${NC}"
|
||||
[ -d "$DATA_DIR/memory" ] && cp -R "$DATA_DIR/memory" "$BK/" 2>/dev/null && echo -e " ${GREEN} + memory/${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e " ${GREEN}备份完成: $BK${NC}"
|
||||
echo " 大小: $(du -sh "$BK" | cut -f1)"
|
||||
}
|
||||
|
||||
# [7] Restore
|
||||
do_restore() {
|
||||
echo ""
|
||||
local BK_DIR="$DATA_DIR/backups"
|
||||
if [ ! -d "$BK_DIR" ] || [ -z "$(ls -A "$BK_DIR" 2>/dev/null)" ]; then
|
||||
echo -e " ${YELLOW}没有备份${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo " 可用备份:"
|
||||
local i=1
|
||||
for b in "$BK_DIR"/*/; do
|
||||
echo -e " ${GREEN}[$i]${NC} $(basename "$b") ($(du -sh "$b" | cut -f1))"
|
||||
i=$((i+1))
|
||||
done
|
||||
echo ""
|
||||
read -p " 选择编号: " NUM
|
||||
|
||||
local j=1
|
||||
for b in "$BK_DIR"/*/; do
|
||||
if [ "$j" = "$NUM" ]; then
|
||||
[ -f "$b/openclaw.json" ] && cp "$b/openclaw.json" "$CONFIG_PATH" && echo -e " ${GREEN} + 配置已恢复${NC}"
|
||||
[ -d "$b/memory" ] && cp -R "$b/memory" "$DATA_DIR/" && echo -e " ${GREEN} + 记忆已恢复${NC}"
|
||||
echo -e " ${GREEN}恢复完成${NC}"
|
||||
return
|
||||
fi
|
||||
j=$((j+1))
|
||||
done
|
||||
echo -e " ${RED}无效选择${NC}"
|
||||
}
|
||||
|
||||
# [8] System info
|
||||
do_sysinfo() {
|
||||
echo ""
|
||||
echo " 系统: $(uname -s) $(uname -r)"
|
||||
echo " 发行版: $(cat /etc/os-release 2>/dev/null | grep ^PRETTY_NAME | cut -d= -f2 | tr -d '"' || echo 'Unknown')"
|
||||
echo " CPU: $(uname -m) $(lscpu 2>/dev/null | grep 'Model name' | sed 's/.*:\s*//' || echo '')"
|
||||
echo " 内存: $(free -h 2>/dev/null | awk '/^Mem:/{print $2}' || echo 'N/A')"
|
||||
echo " Node: $("$NODE_BIN" --version 2>/dev/null)"
|
||||
echo " 路径: $UCLAW_DIR"
|
||||
echo " 大小: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)"
|
||||
echo " 磁盘: $(df -h "$UCLAW_DIR" | tail -1 | awk '{print $4 " 可用"}')"
|
||||
}
|
||||
|
||||
# Main loop
|
||||
while true; do
|
||||
show_menu
|
||||
read -p " 请选择 [0-15]: " CHOICE
|
||||
echo ""
|
||||
|
||||
case $CHOICE in
|
||||
1) do_config ;;
|
||||
2) do_dashboard ;;
|
||||
3) do_qq ;;
|
||||
4) do_platforms ;;
|
||||
5) do_doctor ;;
|
||||
6) do_backup ;;
|
||||
7) do_restore ;;
|
||||
8) do_sysinfo ;;
|
||||
9) do_kill_gateway ;;
|
||||
10) do_logs ;;
|
||||
11) do_factory_reset ;;
|
||||
12) do_uninstall ;;
|
||||
13) do_update ;;
|
||||
14) do_cleanup ;;
|
||||
15) do_plugins ;;
|
||||
0) echo -e " ${CYAN}再见!${NC}"; exit 0 ;;
|
||||
*) echo -e " ${RED}无效选择${NC}" ;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
read -p " 按回车返回..."
|
||||
done
|
||||
185
portable/Linux-Start.sh
Executable file
185
portable/Linux-Start.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# U-Claw - Portable AI Agent
|
||||
# Linux version - run: bash Linux-Start.sh
|
||||
# ============================================================
|
||||
|
||||
UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
APP_DIR="$UCLAW_DIR/app"
|
||||
CORE_DIR="$APP_DIR/core"
|
||||
DATA_DIR="$UCLAW_DIR/data"
|
||||
SYSTEM_DIR="$UCLAW_DIR/system"
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
CYAN='\033[0;36m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
clear
|
||||
echo ""
|
||||
echo -e "${CYAN}"
|
||||
echo " ╔══════════════════════════════════════╗"
|
||||
echo " ║ 🦞 U-Claw v1.1 ║"
|
||||
echo " ║ Portable AI Agent (Linux) ║"
|
||||
echo " ╚══════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
|
||||
# ---- 1. Detect CPU & set runtime ----
|
||||
ARCH=$(uname -m)
|
||||
if [ "$ARCH" = "x86_64" ]; then
|
||||
NODE_DIR="$APP_DIR/runtime/node-linux-x64"
|
||||
echo -e " ${GREEN}Linux x86_64${NC}"
|
||||
elif [ "$ARCH" = "aarch64" ]; then
|
||||
NODE_DIR="$APP_DIR/runtime/node-linux-arm64"
|
||||
echo -e " ${GREEN}Linux ARM64${NC}"
|
||||
else
|
||||
echo -e " ${RED}Unsupported architecture: $ARCH${NC}"
|
||||
echo -e " ${RED}Only x86_64 and arm64 are supported.${NC}"
|
||||
echo ""
|
||||
read -p " Press Enter to exit..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NODE_BIN="$NODE_DIR/bin/node"
|
||||
export PATH="$NODE_DIR/bin:$PATH"
|
||||
|
||||
# ---- 2. Check runtime ----
|
||||
if [ ! -f "$NODE_BIN" ]; then
|
||||
echo -e " ${RED}Error: Node.js runtime not found${NC}"
|
||||
echo " Expected: $NODE_BIN"
|
||||
echo " Please run setup.sh first or ensure app/runtime/ is complete"
|
||||
read -p " Press Enter to exit..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NODE_VER=$("$NODE_BIN" --version)
|
||||
echo -e " Node.js: ${GREEN}${NODE_VER}${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- 3. Check & init data ----
|
||||
mkdir -p "$DATA_DIR/memory" "$DATA_DIR/backups" "$DATA_DIR/logs"
|
||||
|
||||
if [ ! -f "$DATA_DIR/config.json" ] && [ ! -f "$DATA_DIR/.openclaw/openclaw.json" ]; then
|
||||
echo -e " ${YELLOW}First run - creating default config...${NC}"
|
||||
mkdir -p "$DATA_DIR/.openclaw"
|
||||
cat > "$DATA_DIR/.openclaw/openclaw.json" << 'CFGEOF'
|
||||
{
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"auth": { "token": "uclaw" }
|
||||
}
|
||||
}
|
||||
CFGEOF
|
||||
echo -e " ${GREEN}Config created${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ---- 4. Set environment (portable mode) ----
|
||||
STATE_DIR="$DATA_DIR/.openclaw"
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
# Sync config to where OpenClaw expects it
|
||||
if [ -f "$DATA_DIR/config.json" ] && [ ! -f "$STATE_DIR/openclaw.json" ]; then
|
||||
cp "$DATA_DIR/config.json" "$STATE_DIR/openclaw.json"
|
||||
fi
|
||||
|
||||
export OPENCLAW_HOME="$DATA_DIR"
|
||||
export OPENCLAW_STATE_DIR="$STATE_DIR"
|
||||
export OPENCLAW_CONFIG_PATH="$STATE_DIR/openclaw.json"
|
||||
|
||||
# ---- 5. Run migration if exists ----
|
||||
if [ -f "$SYSTEM_DIR/migrate.js" ]; then
|
||||
"$NODE_BIN" "$SYSTEM_DIR/migrate.js" "$DATA_DIR" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ---- 6. Check dependencies ----
|
||||
if [ ! -d "$CORE_DIR/node_modules" ]; then
|
||||
echo -e " ${YELLOW}First run - installing dependencies...${NC}"
|
||||
echo " (Using China mirror)"
|
||||
cd "$CORE_DIR"
|
||||
"$NODE_BIN" "$NODE_DIR/bin/npm" install --registry=https://registry.npmmirror.com 2>&1
|
||||
echo -e " ${GREEN}Dependencies installed${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ---- 7. Find available port ----
|
||||
PORT=18789
|
||||
while ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; do
|
||||
echo -e " ${YELLOW}Port $PORT in use, trying next...${NC}"
|
||||
PORT=$((PORT + 1))
|
||||
if [ $PORT -gt 18799 ]; then
|
||||
echo -e " ${RED}No available port (18789-18799)${NC}"
|
||||
read -p " Press Enter to exit..."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Update config with correct port if changed
|
||||
if [ $PORT -ne 18789 ]; then
|
||||
"$NODE_BIN" -e "
|
||||
const fs = require('fs');
|
||||
const p = '$DATA_DIR/config.json';
|
||||
if (fs.existsSync(p)) {
|
||||
const c = JSON.parse(fs.readFileSync(p, 'utf8'));
|
||||
c.gateway = c.gateway || {};
|
||||
c.gateway.port = $PORT;
|
||||
fs.writeFileSync(p, JSON.stringify(c, null, 2));
|
||||
}
|
||||
" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ---- 8. Start gateway ----
|
||||
echo -e " ${CYAN}Starting OpenClaw on port $PORT...${NC}"
|
||||
echo " Do NOT close this window."
|
||||
echo ""
|
||||
|
||||
cd "$CORE_DIR"
|
||||
|
||||
TOKEN=$(python3 -c "import json,os; p='$STATE_DIR/openclaw.json' if os.path.exists('$STATE_DIR/openclaw.json') else '$DATA_DIR/config.json'; d=json.load(open(p)); print(d.get('gateway',{}).get('auth',{}).get('token','uclaw'))" 2>/dev/null || echo "uclaw")
|
||||
|
||||
OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs"
|
||||
GW_LOG="$DATA_DIR/logs/gateway.log"
|
||||
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT 2>&1 | tee -a "$GW_LOG" &
|
||||
GW_PID=$!
|
||||
|
||||
# ---- 9. Wait & open browser ----
|
||||
for i in $(seq 1 30); do
|
||||
sleep 0.5
|
||||
if curl -s -o /dev/null -w '' "http://127.0.0.1:$PORT/" 2>/dev/null; then
|
||||
DASHBOARD_URL="http://127.0.0.1:$PORT/#token=${TOKEN}"
|
||||
CONFIG_PAGE="$UCLAW_DIR/Config.html?port=$PORT"
|
||||
echo ""
|
||||
echo -e " ${GREEN}✅ Started successfully!${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if model is configured
|
||||
HAS_MODEL=$(python3 -c "
|
||||
import json,os
|
||||
for p in ['$STATE_DIR/openclaw.json','$DATA_DIR/config.json']:
|
||||
if os.path.exists(p):
|
||||
d=json.load(open(p))
|
||||
if d.get('agent',{}).get('model'):
|
||||
print('yes'); break
|
||||
" 2>/dev/null)
|
||||
|
||||
if [ "$HAS_MODEL" = "yes" ]; then
|
||||
echo -e " ${CYAN}Dashboard: ${DASHBOARD_URL}${NC}"
|
||||
echo ""
|
||||
xdg-open "$DASHBOARD_URL" 2>/dev/null || echo -e " ${YELLOW}Please open in browser: ${DASHBOARD_URL}${NC}"
|
||||
else
|
||||
echo -e " ${YELLOW}首次使用,打开配置页面...${NC}"
|
||||
echo -e " ${CYAN}配置页面: Config.html${NC}"
|
||||
echo -e " ${CYAN}控制台: ${DASHBOARD_URL}${NC}"
|
||||
echo ""
|
||||
xdg-open "$CONFIG_PAGE" 2>/dev/null || echo -e " ${YELLOW}Please open in browser: ${CONFIG_PAGE}${NC}"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
wait $GW_PID
|
||||
|
||||
echo ""
|
||||
echo -e " ${YELLOW}OpenClaw stopped.${NC}"
|
||||
read -p " Press Enter to close..."
|
||||
@@ -27,7 +27,10 @@ export OPENCLAW_HOME="$DATA_DIR"
|
||||
export OPENCLAW_STATE_DIR="$STATE_DIR"
|
||||
export OPENCLAW_CONFIG_PATH="$CONFIG_PATH"
|
||||
|
||||
mkdir -p "$STATE_DIR" "$DATA_DIR/memory" "$DATA_DIR/backups"
|
||||
mkdir -p "$STATE_DIR" "$DATA_DIR/memory" "$DATA_DIR/backups" "$DATA_DIR/logs"
|
||||
|
||||
# Load maintenance functions
|
||||
source "$UCLAW_DIR/lib/maintain.sh"
|
||||
|
||||
# Remove macOS quarantine
|
||||
if xattr -l "$NODE_BIN" 2>/dev/null | grep -q "com.apple.quarantine"; then
|
||||
@@ -71,6 +74,15 @@ show_menu() {
|
||||
echo -e " ${GREEN}[7]${NC} 恢复备份"
|
||||
echo -e " ${GREEN}[8]${NC} 系统信息"
|
||||
echo ""
|
||||
echo -e " ${WHITE}${BOLD}── 高级维护 ──────────────────────────${NC}"
|
||||
echo -e " ${GREEN}[9]${NC} 杀死残留进程"
|
||||
echo -e " ${GREEN}[10]${NC} 查看日志"
|
||||
echo -e " ${GREEN}[11]${NC} 恢复出厂设置"
|
||||
echo -e " ${GREEN}[12]${NC} 卸载"
|
||||
echo -e " ${GREEN}[13]${NC} 检查更新"
|
||||
echo -e " ${GREEN}[14]${NC} 清理空间"
|
||||
echo -e " ${GREEN}[15]${NC} 插件管理"
|
||||
echo ""
|
||||
echo -e " ${DIM}[0] 退出${NC}"
|
||||
echo ""
|
||||
}
|
||||
@@ -255,7 +267,7 @@ do_sysinfo() {
|
||||
# Main loop
|
||||
while true; do
|
||||
show_menu
|
||||
read -p " 请选择 [0-8]: " CHOICE
|
||||
read -p " 请选择 [0-15]: " CHOICE
|
||||
echo ""
|
||||
|
||||
case $CHOICE in
|
||||
@@ -267,6 +279,13 @@ while true; do
|
||||
6) do_backup ;;
|
||||
7) do_restore ;;
|
||||
8) do_sysinfo ;;
|
||||
9) do_kill_gateway ;;
|
||||
10) do_logs ;;
|
||||
11) do_factory_reset ;;
|
||||
12) do_uninstall ;;
|
||||
13) do_update ;;
|
||||
14) do_cleanup ;;
|
||||
15) do_plugins ;;
|
||||
0) echo -e " ${CYAN}再见!${NC}"; exit 0 ;;
|
||||
*) echo -e " ${RED}无效选择${NC}" ;;
|
||||
esac
|
||||
|
||||
@@ -142,7 +142,8 @@ cd "$CORE_DIR"
|
||||
TOKEN=$(python3 -c "import json,os; p='$STATE_DIR/openclaw.json' if os.path.exists('$STATE_DIR/openclaw.json') else '$DATA_DIR/config.json'; d=json.load(open(p)); print(d.get('gateway',{}).get('auth',{}).get('token','uclaw'))" 2>/dev/null || echo "uclaw")
|
||||
|
||||
OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs"
|
||||
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT &
|
||||
GW_LOG="$DATA_DIR/logs/gateway.log"
|
||||
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT 2>&1 | tee -a "$GW_LOG" &
|
||||
GW_PID=$!
|
||||
|
||||
# ---- 10. Wait & open browser ----
|
||||
|
||||
@@ -19,6 +19,7 @@ set "OPENCLAW_MJS=%CORE_DIR%\node_modules\openclaw\openclaw.mjs"
|
||||
if not exist "%STATE_DIR%" mkdir "%STATE_DIR%"
|
||||
if not exist "%DATA_DIR%\memory" mkdir "%DATA_DIR%\memory"
|
||||
if not exist "%DATA_DIR%\backups" mkdir "%DATA_DIR%\backups"
|
||||
if not exist "%DATA_DIR%\logs" mkdir "%DATA_DIR%\logs"
|
||||
|
||||
:menu
|
||||
cls
|
||||
@@ -50,9 +51,18 @@ echo [6] Backup config
|
||||
echo [7] Restore backup
|
||||
echo [8] System info
|
||||
echo.
|
||||
echo -- Advanced --
|
||||
echo [9] Kill residual processes
|
||||
echo [10] View logs
|
||||
echo [11] Factory reset
|
||||
echo [12] Uninstall
|
||||
echo [13] Check for updates
|
||||
echo [14] Disk cleanup
|
||||
echo [15] Plugin management
|
||||
echo.
|
||||
echo [0] Exit
|
||||
echo.
|
||||
set /p choice=" Choose [0-8]: "
|
||||
set /p choice=" Choose [0-15]: "
|
||||
|
||||
if "%choice%"=="1" goto :onboard
|
||||
if "%choice%"=="2" goto :dashboard
|
||||
@@ -62,6 +72,13 @@ if "%choice%"=="5" goto :doctor
|
||||
if "%choice%"=="6" goto :backup
|
||||
if "%choice%"=="7" goto :restore
|
||||
if "%choice%"=="8" goto :sysinfo
|
||||
if "%choice%"=="9" goto :killproc
|
||||
if "%choice%"=="10" goto :viewlogs
|
||||
if "%choice%"=="11" goto :factoryreset
|
||||
if "%choice%"=="12" goto :uninstall
|
||||
if "%choice%"=="13" goto :checkupdate
|
||||
if "%choice%"=="14" goto :diskcleanup
|
||||
if "%choice%"=="15" goto :plugins
|
||||
if "%choice%"=="0" exit /b 0
|
||||
echo Invalid choice
|
||||
pause
|
||||
@@ -179,4 +196,172 @@ echo OS: Windows
|
||||
echo Path: %UCLAW_DIR%
|
||||
echo Data: %DATA_DIR%
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:killproc
|
||||
echo.
|
||||
echo === Kill Residual Processes ===
|
||||
echo.
|
||||
echo Checking ports 18789-18799...
|
||||
set FOUND=0
|
||||
for /l %%p in (18789,1,18799) do (
|
||||
netstat -ano | findstr ":%%p " | findstr "LISTENING" >nul 2>&1
|
||||
if not errorlevel 1 (
|
||||
echo Port %%p: process found
|
||||
set FOUND=1
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":%%p " ^| findstr "LISTENING"') do (
|
||||
echo Killing PID %%a...
|
||||
taskkill /PID %%a /F >nul 2>&1
|
||||
)
|
||||
)
|
||||
)
|
||||
if "%FOUND%"=="0" echo No residual processes found.
|
||||
if "%FOUND%"=="1" echo Processes killed.
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:viewlogs
|
||||
echo.
|
||||
echo === View Logs ===
|
||||
echo.
|
||||
set "LOG_FILE=%DATA_DIR%\logs\gateway.log"
|
||||
if not exist "%LOG_FILE%" (
|
||||
echo No log file found. Start the gateway first.
|
||||
pause
|
||||
goto :menu
|
||||
)
|
||||
echo [a] View last 50 lines
|
||||
echo [b] Open log file
|
||||
echo.
|
||||
set /p logchoice=" Choose (a-b): "
|
||||
if "%logchoice%"=="a" (
|
||||
echo.
|
||||
powershell -command "Get-Content '%LOG_FILE%' -Tail 50"
|
||||
)
|
||||
if "%logchoice%"=="b" (
|
||||
start notepad "%LOG_FILE%"
|
||||
)
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:factoryreset
|
||||
echo.
|
||||
echo === Factory Reset ===
|
||||
echo.
|
||||
echo WARNING: This will delete all config and memory data!
|
||||
echo.
|
||||
echo Type RESET to confirm:
|
||||
set /p resetconfirm=" > "
|
||||
if not "%resetconfirm%"=="RESET" (
|
||||
echo Cancelled.
|
||||
pause
|
||||
goto :menu
|
||||
)
|
||||
echo.
|
||||
echo [1/4] Backing up...
|
||||
set "TS=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%"
|
||||
set "TS=%TS: =0%"
|
||||
set "BK=%DATA_DIR%\backups\pre-reset_%TS%"
|
||||
mkdir "%BK%" 2>nul
|
||||
if exist "%STATE_DIR%\openclaw.json" copy "%STATE_DIR%\openclaw.json" "%BK%\" >nul 2>nul
|
||||
if exist "%DATA_DIR%\memory" xcopy /s /q "%DATA_DIR%\memory" "%BK%\memory\" >nul 2>nul
|
||||
echo Backup saved: %BK%
|
||||
echo [2/4] Deleting config...
|
||||
del "%STATE_DIR%\openclaw.json" 2>nul
|
||||
del "%DATA_DIR%\config.json" 2>nul
|
||||
echo [3/4] Clearing memory...
|
||||
rmdir /s /q "%DATA_DIR%\memory" 2>nul
|
||||
mkdir "%DATA_DIR%\memory" 2>nul
|
||||
echo [4/4] Restoring default config...
|
||||
if exist "%UCLAW_DIR%default-config.json" (
|
||||
copy "%UCLAW_DIR%default-config.json" "%STATE_DIR%\openclaw.json" >nul
|
||||
) else (
|
||||
echo {"gateway":{"mode":"local","auth":{"token":"uclaw"}}} > "%STATE_DIR%\openclaw.json"
|
||||
)
|
||||
echo.
|
||||
echo Factory reset complete! Run Setup wizard [1] to reconfigure.
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:uninstall
|
||||
echo.
|
||||
echo === Uninstall U-Claw ===
|
||||
echo.
|
||||
if exist "%USERPROFILE%\.uclaw" (
|
||||
echo Found installed data: %USERPROFILE%\.uclaw
|
||||
echo Type UNINSTALL to delete:
|
||||
set /p unconfirm=" > "
|
||||
if "%unconfirm%"=="UNINSTALL" (
|
||||
rmdir /s /q "%USERPROFILE%\.uclaw" 2>nul
|
||||
echo Uninstalled!
|
||||
) else (
|
||||
echo Cancelled.
|
||||
)
|
||||
) else (
|
||||
echo Portable version - just delete this folder to uninstall.
|
||||
echo Path: %UCLAW_DIR%
|
||||
echo.
|
||||
echo For Electron desktop app:
|
||||
echo Open Settings - Apps - find U-Claw - Uninstall
|
||||
)
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:checkupdate
|
||||
echo.
|
||||
echo === Check for Updates ===
|
||||
echo.
|
||||
if not exist "%CORE_DIR%\node_modules\openclaw\package.json" (
|
||||
echo OpenClaw not installed.
|
||||
pause
|
||||
goto :menu
|
||||
)
|
||||
echo Checking latest version...
|
||||
for /f "tokens=*" %%v in ('"%NODE_BIN%" -e "console.log(require('%CORE_DIR:\=/%/node_modules/openclaw/package.json').version)"') do set CUR_VER=%%v
|
||||
echo Current: %CUR_VER%
|
||||
echo.
|
||||
echo To update, run in the core directory:
|
||||
echo npm install openclaw@latest --registry=https://registry.npmmirror.com
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:diskcleanup
|
||||
echo.
|
||||
echo === Disk Cleanup ===
|
||||
echo.
|
||||
echo Checking sizes...
|
||||
for /f "tokens=*" %%s in ('powershell -command "(Get-ChildItem '%UCLAW_DIR%' -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum / 1MB" 2^>nul') do echo Total: %%s MB
|
||||
echo.
|
||||
echo To clean up manually:
|
||||
echo - Delete old backups in %DATA_DIR%\backups\
|
||||
echo - Delete logs in %DATA_DIR%\logs\
|
||||
pause
|
||||
goto :menu
|
||||
|
||||
:plugins
|
||||
echo.
|
||||
echo === Plugin Management ===
|
||||
echo.
|
||||
echo [a] List installed plugins
|
||||
echo [b] Install a plugin
|
||||
echo [c] Remove a plugin
|
||||
echo.
|
||||
set /p plgchoice=" Choose (a-c): "
|
||||
cd /d "%CORE_DIR%"
|
||||
if "%plgchoice%"=="a" "%NODE_BIN%" "%OPENCLAW_MJS%" plugins list
|
||||
if "%plgchoice%"=="b" (
|
||||
echo.
|
||||
echo Common plugins:
|
||||
echo @icesword760/openclaw-wechat
|
||||
echo.
|
||||
set /p plgname=" Plugin name: "
|
||||
if not "%plgname%"=="" "%NODE_BIN%" "%OPENCLAW_MJS%" plugins install "%plgname%"
|
||||
)
|
||||
if "%plgchoice%"=="c" (
|
||||
"%NODE_BIN%" "%OPENCLAW_MJS%" plugins list
|
||||
echo.
|
||||
set /p plgname=" Plugin to remove: "
|
||||
if not "%plgname%"=="" "%NODE_BIN%" "%OPENCLAW_MJS%" plugins remove "%plgname%"
|
||||
)
|
||||
pause
|
||||
goto :menu
|
||||
@@ -104,8 +104,25 @@ echo DO NOT close this window while using U-Claw!
|
||||
echo.
|
||||
|
||||
cd /d "%CORE_DIR%"
|
||||
|
||||
REM Check if model is configured - open Config.html for first time, dashboard for returning users
|
||||
set "HAS_MODEL=no"
|
||||
if exist "%DATA_DIR%\config.json" (
|
||||
findstr /c:"agent" "%DATA_DIR%\config.json" >nul 2>&1 && set "HAS_MODEL=yes"
|
||||
)
|
||||
|
||||
if "%HAS_MODEL%"=="yes" (
|
||||
echo Opening dashboard...
|
||||
start "" http://127.0.0.1:%PORT%/#token=uclaw
|
||||
) else (
|
||||
echo First time - opening Config page...
|
||||
start "" "%UCLAW_DIR%Config.html?port=%PORT%"
|
||||
)
|
||||
|
||||
if not exist "%DATA_DIR%\logs" mkdir "%DATA_DIR%\logs"
|
||||
set "OPENCLAW_MJS=%CORE_DIR%\node_modules\openclaw\openclaw.mjs"
|
||||
"%NODE_BIN%" "%OPENCLAW_MJS%" gateway run --allow-unconfigured --force --port %PORT%
|
||||
echo Log: %DATA_DIR%\logs\gateway.log
|
||||
"%NODE_BIN%" "%OPENCLAW_MJS%" gateway run --allow-unconfigured --force --port %PORT% 2>&1 | powershell -command "& { $input | Tee-Object -Append -FilePath '%DATA_DIR%\logs\gateway.log' }"
|
||||
|
||||
echo.
|
||||
echo OpenClaw stopped.
|
||||
|
||||
473
portable/lib/maintain.sh
Normal file
473
portable/lib/maintain.sh
Normal file
@@ -0,0 +1,473 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# U-Claw Maintenance Functions (shared by Mac & Linux menus)
|
||||
# Requires caller to set: $UCLAW_DIR, $DATA_DIR, $STATE_DIR,
|
||||
# $CONFIG_PATH, $NODE_BIN, $NPM_BIN, $CORE_DIR,
|
||||
# color vars ($RED $GREEN $YELLOW $CYAN $WHITE $NC $BOLD $DIM),
|
||||
# and run_oc() function.
|
||||
# ============================================================
|
||||
|
||||
LOG_DIR="$DATA_DIR/logs"
|
||||
BACKUP_DIR="$DATA_DIR/backups"
|
||||
DEFAULT_CONFIG="$UCLAW_DIR/default-config.json"
|
||||
|
||||
# Detect install mode: installed (~/.uclaw), usb (/Volumes or /media), portable (other)
|
||||
detect_install_mode() {
|
||||
if echo "$UCLAW_DIR" | grep -q "/.uclaw"; then
|
||||
echo "installed"
|
||||
elif echo "$UCLAW_DIR" | grep -qE "/Volumes/|/media/|/mnt/"; then
|
||||
echo "usb"
|
||||
else
|
||||
echo "portable"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── [9] Kill residual gateway processes ──────────────────────
|
||||
|
||||
do_kill_gateway() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 杀死残留进程 ━━━${NC}"
|
||||
echo ""
|
||||
|
||||
local FOUND=0
|
||||
|
||||
# Method 1: Check ports 18789-18799
|
||||
for PORT in $(seq 18789 18799); do
|
||||
local PIDS=""
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
PIDS=$(lsof -ti :$PORT 2>/dev/null)
|
||||
elif command -v ss >/dev/null 2>&1; then
|
||||
PIDS=$(ss -tlnp 2>/dev/null | grep ":$PORT " | sed -n 's/.*pid=\([0-9]*\).*/\1/p')
|
||||
fi
|
||||
if [ -n "$PIDS" ]; then
|
||||
for PID in $PIDS; do
|
||||
local CMD=$(ps -p "$PID" -o comm= 2>/dev/null || echo "unknown")
|
||||
echo -e " ${YELLOW}端口 $PORT: PID $PID ($CMD)${NC}"
|
||||
FOUND=1
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# Method 2: Check for openclaw.mjs processes
|
||||
local OC_PIDS=$(pgrep -f "openclaw.mjs gateway" 2>/dev/null)
|
||||
if [ -n "$OC_PIDS" ]; then
|
||||
for PID in $OC_PIDS; do
|
||||
echo -e " ${YELLOW}OpenClaw 网关进程: PID $PID${NC}"
|
||||
FOUND=1
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$FOUND" = "0" ]; then
|
||||
echo -e " ${GREEN}没有发现残留进程${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -p " 确认杀死以上进程? (y/N): " CONFIRM
|
||||
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Kill port processes
|
||||
for PORT in $(seq 18789 18799); do
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
lsof -ti :$PORT 2>/dev/null | xargs kill 2>/dev/null
|
||||
elif command -v ss >/dev/null 2>&1; then
|
||||
ss -tlnp 2>/dev/null | grep ":$PORT " | sed -n 's/.*pid=\([0-9]*\).*/\1/p' | xargs kill 2>/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
# Kill openclaw.mjs processes
|
||||
pgrep -f "openclaw.mjs gateway" 2>/dev/null | xargs kill 2>/dev/null
|
||||
|
||||
sleep 1
|
||||
echo -e " ${GREEN}进程已清理${NC}"
|
||||
}
|
||||
|
||||
# ── [10] View/export/clean logs ──────────────────────────────
|
||||
|
||||
do_logs() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 日志管理 ━━━${NC}"
|
||||
echo ""
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
local LOG_FILE="$LOG_DIR/gateway.log"
|
||||
|
||||
echo -e " ${GREEN}[a]${NC} 查看最近日志(最后 50 行)"
|
||||
echo -e " ${GREEN}[b]${NC} 导出日志到桌面"
|
||||
echo -e " ${GREEN}[c]${NC} 清理 7 天前的旧日志"
|
||||
echo ""
|
||||
read -p " 选择 (a-c): " -n 1 LOG_CHOICE
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
case $LOG_CHOICE in
|
||||
a)
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
echo -e " ${DIM}── $LOG_FILE ──${NC}"
|
||||
echo ""
|
||||
tail -50 "$LOG_FILE"
|
||||
else
|
||||
echo -e " ${YELLOW}日志文件不存在: $LOG_FILE${NC}"
|
||||
echo " 启动网关后会自动生成日志。"
|
||||
fi
|
||||
;;
|
||||
b)
|
||||
if [ ! -f "$LOG_FILE" ]; then
|
||||
echo -e " ${YELLOW}没有日志可导出${NC}"
|
||||
return
|
||||
fi
|
||||
local TS=$(date +%Y%m%d_%H%M%S)
|
||||
local EXPORT_DIR="$HOME/Desktop"
|
||||
[ ! -d "$EXPORT_DIR" ] && EXPORT_DIR="$HOME"
|
||||
local EXPORT_FILE="$EXPORT_DIR/uclaw-logs-$TS.txt"
|
||||
cp "$LOG_FILE" "$EXPORT_FILE"
|
||||
echo -e " ${GREEN}日志已导出: $EXPORT_FILE${NC}"
|
||||
echo " 大小: $(du -sh "$EXPORT_FILE" | cut -f1)"
|
||||
;;
|
||||
c)
|
||||
local COUNT=$(find "$LOG_DIR" -name "*.log" -mtime +7 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [ "$COUNT" = "0" ]; then
|
||||
echo -e " ${GREEN}没有需要清理的旧日志${NC}"
|
||||
return
|
||||
fi
|
||||
echo -e " 找到 ${YELLOW}$COUNT${NC} 个超过 7 天的日志文件"
|
||||
read -p " 确认清理? (y/N): " CONFIRM
|
||||
if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then
|
||||
find "$LOG_DIR" -name "*.log" -mtime +7 -delete 2>/dev/null
|
||||
echo -e " ${GREEN}旧日志已清理${NC}"
|
||||
else
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e " ${RED}无效选择${NC}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── [11] Factory reset ───────────────────────────────────────
|
||||
|
||||
do_factory_reset() {
|
||||
echo ""
|
||||
echo -e " ${RED}${BOLD}━━━ 恢复出厂设置 ━━━${NC}"
|
||||
echo ""
|
||||
echo -e " ${RED}警告: 此操作将删除所有配置和记忆数据!${NC}"
|
||||
echo ""
|
||||
echo " 将执行以下操作:"
|
||||
echo " 1. 自动备份当前配置和记忆"
|
||||
echo " 2. 删除配置文件 (openclaw.json)"
|
||||
echo " 3. 删除记忆数据 (memory/)"
|
||||
echo " 4. 恢复默认配置"
|
||||
echo ""
|
||||
echo -e " ${YELLOW}请输入 RESET 确认(区分大小写):${NC}"
|
||||
read -p " > " CONFIRM
|
||||
|
||||
if [ "$CONFIRM" != "RESET" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Step 1: Auto backup
|
||||
echo ""
|
||||
echo -e " ${CYAN}[1/4] 自动备份...${NC}"
|
||||
local TS=$(date +%Y%m%d_%H%M%S)
|
||||
local BK="$BACKUP_DIR/pre-reset_$TS"
|
||||
mkdir -p "$BK"
|
||||
[ -f "$CONFIG_PATH" ] && cp "$CONFIG_PATH" "$BK/" 2>/dev/null
|
||||
[ -d "$DATA_DIR/memory" ] && cp -R "$DATA_DIR/memory" "$BK/" 2>/dev/null
|
||||
echo -e " ${GREEN}备份已保存: $BK${NC}"
|
||||
|
||||
# Step 2: Delete config
|
||||
echo -e " ${CYAN}[2/4] 删除配置...${NC}"
|
||||
rm -f "$CONFIG_PATH" 2>/dev/null
|
||||
rm -f "$DATA_DIR/config.json" 2>/dev/null
|
||||
|
||||
# Step 3: Delete memory
|
||||
echo -e " ${CYAN}[3/4] 清理记忆数据...${NC}"
|
||||
rm -rf "$DATA_DIR/memory" 2>/dev/null
|
||||
mkdir -p "$DATA_DIR/memory"
|
||||
|
||||
# Step 4: Restore default config
|
||||
echo -e " ${CYAN}[4/4] 恢复默认配置...${NC}"
|
||||
mkdir -p "$STATE_DIR"
|
||||
if [ -f "$DEFAULT_CONFIG" ]; then
|
||||
cp "$DEFAULT_CONFIG" "$CONFIG_PATH"
|
||||
else
|
||||
cat > "$CONFIG_PATH" << 'CFGEOF'
|
||||
{
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"auth": { "token": "uclaw" }
|
||||
}
|
||||
}
|
||||
CFGEOF
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e " ${GREEN}出厂设置已恢复!${NC}"
|
||||
echo -e " 备份位置: $BK"
|
||||
echo -e " 请重新运行配置向导 [1] 设置模型。"
|
||||
}
|
||||
|
||||
# ── [12] Uninstall ───────────────────────────────────────────
|
||||
|
||||
do_uninstall() {
|
||||
echo ""
|
||||
echo -e " ${RED}${BOLD}━━━ 卸载 U-Claw ━━━${NC}"
|
||||
echo ""
|
||||
|
||||
local MODE=$(detect_install_mode)
|
||||
|
||||
case $MODE in
|
||||
installed)
|
||||
echo " 检测到: 已安装版本 (~/.uclaw/)"
|
||||
echo ""
|
||||
echo " 将删除以下目录:"
|
||||
echo -e " ${YELLOW}$HOME/.uclaw/${NC}"
|
||||
if [ -d "$HOME/.uclaw" ]; then
|
||||
echo " 大小: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)"
|
||||
fi
|
||||
echo ""
|
||||
echo -e " ${RED}请输入 UNINSTALL 确认:${NC}"
|
||||
read -p " > " CONFIRM
|
||||
if [ "$CONFIRM" != "UNINSTALL" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
rm -rf "$HOME/.uclaw"
|
||||
echo -e " ${GREEN}卸载完成!${NC}"
|
||||
;;
|
||||
usb)
|
||||
echo " 检测到: U 盘模式"
|
||||
echo ""
|
||||
echo " 便携版不需要卸载 —— 只需:"
|
||||
echo " 1. 关闭所有 U-Claw 窗口"
|
||||
echo " 2. 安全弹出 U 盘"
|
||||
echo " 3. 如需清理电脑上的数据,删除 ~/.uclaw/ (如果存在)"
|
||||
echo ""
|
||||
if [ -d "$HOME/.uclaw" ]; then
|
||||
echo -e " ${YELLOW}发现本机数据: ~/.uclaw/${NC}"
|
||||
echo " 大小: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)"
|
||||
read -p " 是否删除本机数据? (y/N): " DEL
|
||||
if [ "$DEL" = "y" ] || [ "$DEL" = "Y" ]; then
|
||||
rm -rf "$HOME/.uclaw"
|
||||
echo -e " ${GREEN}本机数据已清理${NC}"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
portable)
|
||||
echo " 检测到: 便携版本"
|
||||
echo ""
|
||||
echo " 便携版不需要卸载 —— 直接删除文件夹即可:"
|
||||
echo -e " ${YELLOW}$UCLAW_DIR${NC}"
|
||||
echo ""
|
||||
if [ -d "$HOME/.uclaw" ]; then
|
||||
echo -e " ${YELLOW}发现本机数据: ~/.uclaw/${NC}"
|
||||
echo " 大小: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)"
|
||||
read -p " 是否删除本机数据? (y/N): " DEL
|
||||
if [ "$DEL" = "y" ] || [ "$DEL" = "Y" ]; then
|
||||
rm -rf "$HOME/.uclaw"
|
||||
echo -e " ${GREEN}本机数据已清理${NC}"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
echo " Electron 桌面版卸载:"
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
echo " macOS: 将 U-Claw.app 从「应用程序」拖到废纸篓"
|
||||
else
|
||||
echo " Linux: sudo apt remove u-claw 或 rm ~/.local/share/applications/u-claw.desktop"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── [13] Check for updates (P1) ─────────────────────────────
|
||||
|
||||
do_update() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 检查更新 ━━━${NC}"
|
||||
echo ""
|
||||
|
||||
if [ ! -f "$NODE_BIN" ]; then
|
||||
echo -e " ${RED}Node.js 未找到,无法检查更新${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e " ${DIM}正在查询最新版本...${NC}"
|
||||
|
||||
# Get current version
|
||||
local CUR_VER=""
|
||||
if [ -f "$CORE_DIR/node_modules/openclaw/package.json" ]; then
|
||||
CUR_VER=$("$NODE_BIN" -e "console.log(require('$CORE_DIR/node_modules/openclaw/package.json').version)" 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -z "$CUR_VER" ]; then
|
||||
echo -e " ${RED}无法读取当前版本(OpenClaw 可能未安装)${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get latest version from npmmirror
|
||||
local LATEST_VER=$(curl -s --connect-timeout 10 "https://registry.npmmirror.com/openclaw/latest" 2>/dev/null | "$NODE_BIN" -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).version)}catch(e){console.log('error')}})" 2>/dev/null)
|
||||
|
||||
if [ -z "$LATEST_VER" ] || [ "$LATEST_VER" = "error" ]; then
|
||||
echo -e " ${YELLOW}无法获取最新版本(网络问题?)${NC}"
|
||||
echo " 当前版本: $CUR_VER"
|
||||
return
|
||||
fi
|
||||
|
||||
echo " 当前版本: $CUR_VER"
|
||||
echo " 最新版本: $LATEST_VER"
|
||||
echo ""
|
||||
|
||||
if [ "$CUR_VER" = "$LATEST_VER" ]; then
|
||||
echo -e " ${GREEN}已是最新版本!${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e " ${YELLOW}有新版本可用!${NC}"
|
||||
read -p " 是否立即升级? (y/N): " DO_UPDATE
|
||||
if [ "$DO_UPDATE" != "y" ] && [ "$DO_UPDATE" != "Y" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e " ${CYAN}正在升级...${NC}"
|
||||
cd "$CORE_DIR"
|
||||
"$NPM_BIN" install openclaw@latest --registry=https://registry.npmmirror.com 2>&1
|
||||
local NEW_VER=$("$NODE_BIN" -e "console.log(require('./node_modules/openclaw/package.json').version)" 2>/dev/null)
|
||||
echo ""
|
||||
echo -e " ${GREEN}升级完成!${NC} $CUR_VER → $NEW_VER"
|
||||
}
|
||||
|
||||
# ── [14] Disk cleanup (P1) ───────────────────────────────────
|
||||
|
||||
do_cleanup() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 清理空间 ━━━${NC}"
|
||||
echo ""
|
||||
|
||||
# Show directory sizes
|
||||
echo -e " ${WHITE}目录占用:${NC}"
|
||||
[ -d "$CORE_DIR/node_modules" ] && echo " node_modules: $(du -sh "$CORE_DIR/node_modules" 2>/dev/null | cut -f1)"
|
||||
[ -d "$DATA_DIR/memory" ] && echo " memory: $(du -sh "$DATA_DIR/memory" 2>/dev/null | cut -f1)"
|
||||
[ -d "$BACKUP_DIR" ] && echo " backups: $(du -sh "$BACKUP_DIR" 2>/dev/null | cut -f1)"
|
||||
[ -d "$LOG_DIR" ] && echo " logs: $(du -sh "$LOG_DIR" 2>/dev/null | cut -f1)"
|
||||
echo " 总计: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)"
|
||||
echo ""
|
||||
|
||||
local CLEANED=0
|
||||
|
||||
# Clean old backups (keep latest 3)
|
||||
if [ -d "$BACKUP_DIR" ]; then
|
||||
local BK_COUNT=$(ls -d "$BACKUP_DIR"/*/ 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [ "$BK_COUNT" -gt 3 ]; then
|
||||
local OLD_COUNT=$((BK_COUNT - 3))
|
||||
echo -e " ${YELLOW}发现 $BK_COUNT 个备份,保留最新 3 个,删除 $OLD_COUNT 个旧备份${NC}"
|
||||
read -p " 确认? (y/N): " DEL_BK
|
||||
if [ "$DEL_BK" = "y" ] || [ "$DEL_BK" = "Y" ]; then
|
||||
ls -dt "$BACKUP_DIR"/*/ 2>/dev/null | tail -n "$OLD_COUNT" | while read -r DIR; do
|
||||
rm -rf "$DIR"
|
||||
done
|
||||
echo -e " ${GREEN}旧备份已清理${NC}"
|
||||
CLEANED=1
|
||||
fi
|
||||
else
|
||||
echo " 备份: ${BK_COUNT} 个(无需清理)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean old logs (>7 days)
|
||||
if [ -d "$LOG_DIR" ]; then
|
||||
local OLD_LOGS=$(find "$LOG_DIR" -name "*.log" -mtime +7 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [ "$OLD_LOGS" -gt 0 ]; then
|
||||
echo -e " ${YELLOW}发现 $OLD_LOGS 个超过 7 天的日志${NC}"
|
||||
read -p " 确认清理? (y/N): " DEL_LOG
|
||||
if [ "$DEL_LOG" = "y" ] || [ "$DEL_LOG" = "Y" ]; then
|
||||
find "$LOG_DIR" -name "*.log" -mtime +7 -delete 2>/dev/null
|
||||
echo -e " ${GREEN}旧日志已清理${NC}"
|
||||
CLEANED=1
|
||||
fi
|
||||
else
|
||||
echo " 日志: 无需清理"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean npm cache
|
||||
echo ""
|
||||
read -p " 是否清理 npm 缓存? (y/N): " DEL_CACHE
|
||||
if [ "$DEL_CACHE" = "y" ] || [ "$DEL_CACHE" = "Y" ]; then
|
||||
"$NPM_BIN" cache clean --force 2>/dev/null
|
||||
echo -e " ${GREEN}npm 缓存已清理${NC}"
|
||||
CLEANED=1
|
||||
fi
|
||||
|
||||
if [ "$CLEANED" = "0" ]; then
|
||||
echo ""
|
||||
echo -e " ${GREEN}没有需要清理的内容${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo " 清理后总计: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── [15] Plugin management (P1) ─────────────────────────────
|
||||
|
||||
do_plugins() {
|
||||
echo ""
|
||||
echo -e " ${CYAN}${BOLD}━━━ 插件管理 ━━━${NC}"
|
||||
echo ""
|
||||
echo -e " ${GREEN}[a]${NC} 列出已安装插件"
|
||||
echo -e " ${GREEN}[b]${NC} 安装插件"
|
||||
echo -e " ${GREEN}[c]${NC} 卸载插件"
|
||||
echo ""
|
||||
read -p " 选择 (a-c): " -n 1 PLG_CHOICE
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
case $PLG_CHOICE in
|
||||
a)
|
||||
echo -e " ${WHITE}已安装插件:${NC}"
|
||||
echo ""
|
||||
run_oc plugins list 2>&1 || echo -e " ${YELLOW}无法获取插件列表${NC}"
|
||||
;;
|
||||
b)
|
||||
echo " 常用插件:"
|
||||
echo " @icesword760/openclaw-wechat — 微信"
|
||||
echo " @nicepkg/openclaw-plugin-qq — QQ(社区版)"
|
||||
echo ""
|
||||
read -p " 输入插件名称(留空取消): " PLG_NAME
|
||||
if [ -z "$PLG_NAME" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
echo ""
|
||||
echo -e " ${CYAN}正在安装 $PLG_NAME ...${NC}"
|
||||
run_oc plugins install "$PLG_NAME" 2>&1
|
||||
echo ""
|
||||
echo -e " ${GREEN}安装完成${NC}"
|
||||
;;
|
||||
c)
|
||||
echo -e " ${WHITE}已安装插件:${NC}"
|
||||
echo ""
|
||||
run_oc plugins list 2>&1 || true
|
||||
echo ""
|
||||
read -p " 输入要卸载的插件名称(留空取消): " PLG_NAME
|
||||
if [ -z "$PLG_NAME" ]; then
|
||||
echo -e " ${YELLOW}已取消${NC}"
|
||||
return
|
||||
fi
|
||||
echo ""
|
||||
echo -e " ${CYAN}正在卸载 $PLG_NAME ...${NC}"
|
||||
run_oc plugins remove "$PLG_NAME" 2>&1
|
||||
echo ""
|
||||
echo -e " ${GREEN}卸载完成${NC}"
|
||||
;;
|
||||
*)
|
||||
echo -e " ${RED}无效选择${NC}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
220
portable/setup-linux-usb.sh
Executable file
220
portable/setup-linux-usb.sh
Executable file
@@ -0,0 +1,220 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# U-Claw - Linux 启动盘 OpenClaw 安装脚本
|
||||
# 在 Linux Mint 启动盘环境中运行此脚本安装 OpenClaw
|
||||
#
|
||||
# 使用方法:
|
||||
# 1. 用 Rufus 制作 Linux Mint 启动盘(开启 Persistent Storage)
|
||||
# 2. 从 USB 启动进入 Linux Mint
|
||||
# 3. 连接网络
|
||||
# 4. 打开终端,运行: bash setup-linux-usb.sh
|
||||
# ============================================================
|
||||
|
||||
set -e
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
CYAN='\033[0;36m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
BOLD='\033[1m'
|
||||
|
||||
NODE_VER="v22.14.0"
|
||||
MIRROR="https://registry.npmmirror.com"
|
||||
NODE_MIRROR="https://npmmirror.com/mirrors/node"
|
||||
|
||||
INSTALL_DIR="$HOME/U-Claw"
|
||||
|
||||
clear
|
||||
echo ""
|
||||
echo -e "${CYAN}${BOLD}"
|
||||
echo " ╔══════════════════════════════════════╗"
|
||||
echo " ║ U-Claw Linux 启动盘安装 ║"
|
||||
echo " ║ 在 Live Linux 环境中安装 OpenClaw ║"
|
||||
echo " ╚══════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- Check network ----
|
||||
echo -e " ${BOLD}[0/4] 检查网络连接...${NC}"
|
||||
if ! ping -c 1 -W 3 npmmirror.com >/dev/null 2>&1; then
|
||||
echo -e " ${RED}无法连接到网络!${NC}"
|
||||
echo -e " ${YELLOW}请先连接 WiFi 或插入网线,然后重新运行此脚本。${NC}"
|
||||
echo ""
|
||||
read -p " 按回车退出..."
|
||||
exit 1
|
||||
fi
|
||||
echo -e " ${GREEN}网络正常 ✓${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- Check CPU ----
|
||||
ARCH=$(uname -m)
|
||||
if [ "$ARCH" = "x86_64" ]; then
|
||||
NODE_PLATFORM="linux-x64"
|
||||
NODE_DIR_NAME="node-linux-x64"
|
||||
echo -e " ${GREEN}架构: x86_64 ✓${NC}"
|
||||
elif [ "$ARCH" = "aarch64" ]; then
|
||||
NODE_PLATFORM="linux-arm64"
|
||||
NODE_DIR_NAME="node-linux-arm64"
|
||||
echo -e " ${GREEN}架构: ARM64 ✓${NC}"
|
||||
else
|
||||
echo -e " ${RED}不支持的架构: $ARCH${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ---- Step 1: Install Node.js ----
|
||||
echo -e " ${BOLD}[1/4] 安装 Node.js $NODE_VER...${NC}"
|
||||
|
||||
NODE_INSTALL_DIR="$INSTALL_DIR/runtime/$NODE_DIR_NAME"
|
||||
|
||||
if [ -f "$NODE_INSTALL_DIR/bin/node" ]; then
|
||||
echo -e " ${GREEN}Node.js 已存在,跳过${NC}"
|
||||
else
|
||||
TARBALL="node-${NODE_VER}-${NODE_PLATFORM}.tar.gz"
|
||||
URL="${NODE_MIRROR}/${NODE_VER}/${TARBALL}"
|
||||
|
||||
echo -e " ${CYAN}下载: $URL${NC}"
|
||||
mkdir -p "$NODE_INSTALL_DIR"
|
||||
curl -# -L "$URL" -o "/tmp/$TARBALL"
|
||||
tar -xzf "/tmp/$TARBALL" -C "$NODE_INSTALL_DIR" --strip-components=1
|
||||
rm -f "/tmp/$TARBALL"
|
||||
chmod +x "$NODE_INSTALL_DIR/bin/node"
|
||||
echo -e " ${GREEN}Node.js 安装完成 ✓${NC}"
|
||||
fi
|
||||
|
||||
NODE_BIN="$NODE_INSTALL_DIR/bin/node"
|
||||
NPM_BIN="$NODE_INSTALL_DIR/bin/npm"
|
||||
export PATH="$NODE_INSTALL_DIR/bin:$PATH"
|
||||
|
||||
echo -e " 版本: $("$NODE_BIN" --version)"
|
||||
echo ""
|
||||
|
||||
# ---- Step 2: Install OpenClaw ----
|
||||
echo -e " ${BOLD}[2/4] 安装 OpenClaw...${NC}"
|
||||
|
||||
CORE_DIR="$INSTALL_DIR/core"
|
||||
mkdir -p "$CORE_DIR"
|
||||
|
||||
cat > "$CORE_DIR/package.json" << 'PKGEOF'
|
||||
{
|
||||
"name": "u-claw-core",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"openclaw": "latest"
|
||||
}
|
||||
}
|
||||
PKGEOF
|
||||
|
||||
cd "$CORE_DIR"
|
||||
echo -e " ${CYAN}从国内镜像下载 OpenClaw...${NC}"
|
||||
"$NODE_BIN" "$NPM_BIN" install --registry="$MIRROR" 2>&1 | tail -5
|
||||
echo -e " ${CYAN}安装 QQ 插件...${NC}"
|
||||
"$NODE_BIN" "$NPM_BIN" install @sliverp/qqbot@latest --registry="$MIRROR" 2>&1 | tail -2
|
||||
echo -e " ${GREEN}OpenClaw 安装完成 ✓${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- Step 3: Create config & launch script ----
|
||||
echo -e " ${BOLD}[3/4] 创建配置和启动脚本...${NC}"
|
||||
|
||||
# Default config
|
||||
mkdir -p "$INSTALL_DIR/data/.openclaw"
|
||||
mkdir -p "$INSTALL_DIR/data/memory"
|
||||
mkdir -p "$INSTALL_DIR/data/backups"
|
||||
|
||||
CONFIG_PATH="$INSTALL_DIR/data/.openclaw/openclaw.json"
|
||||
if [ ! -f "$CONFIG_PATH" ]; then
|
||||
cat > "$CONFIG_PATH" << 'CFGEOF'
|
||||
{
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"auth": { "token": "uclaw" }
|
||||
}
|
||||
}
|
||||
CFGEOF
|
||||
fi
|
||||
|
||||
# Launch script
|
||||
cat > "$INSTALL_DIR/start.sh" << STARTEOF
|
||||
#!/bin/bash
|
||||
DIR="$INSTALL_DIR"
|
||||
NODE_BIN="$NODE_BIN"
|
||||
CORE_DIR="\$DIR/core"
|
||||
OPENCLAW_MJS="\$CORE_DIR/node_modules/openclaw/openclaw.mjs"
|
||||
|
||||
export OPENCLAW_HOME="\$DIR/data"
|
||||
export OPENCLAW_STATE_DIR="\$DIR/data/.openclaw"
|
||||
export OPENCLAW_CONFIG_PATH="\$DIR/data/.openclaw/openclaw.json"
|
||||
|
||||
PORT=18789
|
||||
while ss -tlnp 2>/dev/null | grep -q ":\$PORT " || netstat -tlnp 2>/dev/null | grep -q ":\$PORT "; do
|
||||
PORT=\$((PORT + 1))
|
||||
[ \$PORT -gt 18799 ] && echo "No available port" && exit 1
|
||||
done
|
||||
|
||||
echo "Starting OpenClaw on port \$PORT..."
|
||||
cd "\$CORE_DIR"
|
||||
"\$NODE_BIN" "\$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port \$PORT &
|
||||
PID=\$!
|
||||
|
||||
for i in \$(seq 1 30); do
|
||||
sleep 0.5
|
||||
if curl -s -o /dev/null "http://127.0.0.1:\$PORT/" 2>/dev/null; then
|
||||
xdg-open "http://127.0.0.1:\$PORT/#token=uclaw" 2>/dev/null || echo "Open: http://127.0.0.1:\$PORT/#token=uclaw"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
wait \$PID
|
||||
STARTEOF
|
||||
chmod +x "$INSTALL_DIR/start.sh"
|
||||
|
||||
echo -e " ${GREEN}启动脚本已创建 ✓${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- Step 4: Create desktop shortcut ----
|
||||
echo -e " ${BOLD}[4/4] 创建桌面快捷方式...${NC}"
|
||||
|
||||
DESKTOP_FILE="$HOME/Desktop/U-Claw.desktop"
|
||||
cat > "$DESKTOP_FILE" << DESKEOF
|
||||
[Desktop Entry]
|
||||
Name=U-Claw AI 助手
|
||||
Comment=Portable AI Agent powered by OpenClaw
|
||||
Exec=bash $INSTALL_DIR/start.sh
|
||||
Terminal=true
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
DESKEOF
|
||||
chmod +x "$DESKTOP_FILE"
|
||||
|
||||
# Also add to applications menu
|
||||
mkdir -p "$HOME/.local/share/applications"
|
||||
cp "$DESKTOP_FILE" "$HOME/.local/share/applications/u-claw.desktop"
|
||||
|
||||
echo -e " ${GREEN}桌面快捷方式已创建 ✓${NC}"
|
||||
echo ""
|
||||
|
||||
# ---- Summary ----
|
||||
INSTALL_SIZE=$(du -sh "$INSTALL_DIR" | cut -f1)
|
||||
|
||||
echo -e " ${GREEN}${BOLD}╔══════════════════════════════════════╗"
|
||||
echo -e " ║ ✅ 安装成功! ║"
|
||||
echo -e " ╚══════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e " ${BOLD}安装位置:${NC} $INSTALL_DIR"
|
||||
echo -e " ${BOLD}大小:${NC} $INSTALL_SIZE"
|
||||
echo ""
|
||||
echo -e " ${BOLD}启动方式:${NC}"
|
||||
echo -e " 双击桌面的 ${CYAN}U-Claw AI 助手${NC} 图标"
|
||||
echo -e " 或终端运行: ${CYAN}bash ~/U-Claw/start.sh${NC}"
|
||||
echo ""
|
||||
echo -e " ${BOLD}首次使用:${NC}"
|
||||
echo -e " 启动后浏览器自动打开 → 选择 AI 模型 → 填写 API Key"
|
||||
echo ""
|
||||
echo -e " ${YELLOW}${BOLD}⚠️ 持久化提醒:${NC}"
|
||||
echo -e " ${YELLOW}如果你用 Rufus 制作启动盘时开启了 Persistent Storage,${NC}"
|
||||
echo -e " ${YELLOW}上述安装和配置在重启后仍然保留。${NC}"
|
||||
echo -e " ${YELLOW}如果没有开启持久化,重启后需要重新运行此脚本。${NC}"
|
||||
echo ""
|
||||
read -p " 按回车关闭..."
|
||||
Reference in New Issue
Block a user