merge: resolve conflict in Windows-Start.bat, add Linux scripts and maintain lib

This commit is contained in:
dongsheng123132
2026-03-13 17:35:55 +08:00
parent c0dbe3bc41
commit 7766d59e55
11 changed files with 1952 additions and 75 deletions

View File

@@ -89,5 +89,6 @@ Release artifacts go to GitHub Releases, not the repo.
- Mac Apple Silicon (ARM64): ✅ Working - Mac Apple Silicon (ARM64): ✅ Working
- Windows x64: 🚧 In development - Windows x64: 🚧 In development
- Linux x86_64: ✅ Working (scripts + live USB mode)
- Linux ARM64: ✅ Working (scripts)
- Mac Intel (x64): ❌ Not yet - Mac Intel (x64): ❌ Not yet
- Linux: ❌ Not yet

341
README.md
View File

@@ -1,65 +1,107 @@
# 🦞 U-Claw # 🦞 U-Claw
**AI 助手 U 盘 — 克隆、补依赖、拷到 U 盘、双击运行** > **制作「插上就能用」的 AI 助手 U 盘 — 教程与源代码**
> **Build a plug-and-play AI assistant USB drive — Tutorial & Source Code**
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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 ```bash
# 1. 克隆代码
git clone https://github.com/dongsheng123132/u-claw.git 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 ```bash
# Mac curl -O https://raw.githubusercontent.com/dongsheng123132/u-claw/main/portable/setup-linux-usb.sh
cp -R portable/ /Volumes/你的U盘/U-Claw/ bash setup-linux-usb.sh
# 或直接在 Finder 拖过去
``` ```
## U 盘上能做什么 详细图文教程见 [guide.html → Linux 启动盘模式](https://u-claw.org/guide.html)。
| 功能 | Mac | Windows | 说明 | ### U 盘功能一览
|------|-----|---------|------|
| **免安装运行** | `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 盘文件结构 | 功能 | 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 盘 U-Claw/ ← 整个拷到 U 盘
├── Mac-Start.command 双击 = Mac 免安装运行 ├── Mac-Start.command Mac 免安装运行
├── Mac-Menu.command 功能菜单8 项) ├── Mac-Menu.command Mac 功能菜单
├── Mac-Install.command 安装到 Mac ├── Mac-Install.command 安装到 Mac
├── Windows-Start.bat 双击 = Windows 免安装运行 ├── Windows-Start.bat Windows 免安装运行
├── Windows-Menu.bat 功能菜单 ├── Windows-Menu.bat Windows 功能菜单
├── Windows-Install.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 首次配置页面 ├── Config.html 首次配置页面
├── setup.sh 补齐依赖(开发者用) ├── setup.sh 补齐依赖(开发者用)
├── app/ ← 大依赖setup.sh 下载,不进 git ├── app/ ← 大依赖setup.sh 下载,不进 git
│ ├── core/ OpenClaw + QQ 插件 │ ├── core/ OpenClaw + QQ 插件
│ └── runtime/ │ └── runtime/
│ ├── node-mac-arm64/ Mac Apple Silicon │ ├── 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 └── data/ ← 用户数据(不进 git
├── .openclaw/ 配置文件 ├── .openclaw/ 配置文件
├── memory/ AI 记忆 ├── memory/ AI 记忆
└── backups/ 备份 └── backups/ 备份
``` ```
**代码库 = U 盘内容 - 大依赖。** `app/``data/``.gitignore` 里。 ### 桌面安装版Electron App
## 桌面安装版Electron App
除了 U 盘便携版,还有桌面 App 版本: 除了 U 盘便携版,还有桌面 App 版本:
@@ -71,9 +113,9 @@ npm run build:mac-arm64 # 打包 → release/*.dmg
npm run build:win # 打包 → release/*.exe npm run build:win # 打包 → release/*.exe
``` ```
## 支持的 AI 模型 ### 支持的 AI 模型
### 国产模型(无需翻墙) **国产模型(无需翻墙)**
| 模型 | 推荐场景 | | 模型 | 推荐场景 |
|------|----------| |------|----------|
@@ -84,11 +126,9 @@ npm run build:win # 打包 → release/*.exe
| MiniMax | 语音多模态 | | MiniMax | 语音多模态 |
| 豆包 Doubao | 火山引擎 | | 豆包 Doubao | 火山引擎 |
### 国际模型 **国际模型:** Claude · GPT · Gemini需翻墙或中转
Claude · GPT · Gemini需翻墙或中转 ### 支持的聊天平台
## 支持的聊天平台
| 平台 | 状态 | 说明 | | 平台 | 状态 | 说明 |
|------|------|------| |------|------|------|
@@ -99,7 +139,7 @@ Claude · GPT · Gemini需翻墙或中转
| Discord | ✅ 内置 | — | | Discord | ✅ 内置 | — |
| 微信 | ✅ 社区插件 | iPad 协议 | | 微信 | ✅ 社区插件 | iPad 协议 |
## 国内镜像 ### 国内镜像
所有脚本默认走国内镜像,无需翻墙: 所有脚本默认走国内镜像,无需翻墙:
@@ -109,60 +149,42 @@ Claude · GPT · Gemini需翻墙或中转
| Node.js | `npmmirror.com/mirrors/node` | | Node.js | `npmmirror.com/mirrors/node` |
| Electron | `npmmirror.com/mirrors/electron` | | Electron | `npmmirror.com/mirrors/electron` |
## 开发 & 测试 ### 开发 & 贡献
```bash ```bash
# 克隆
git clone https://github.com/dongsheng123132/u-claw.git git clone https://github.com/dongsheng123132/u-claw.git
# 补依赖
cd u-claw/portable && bash setup.sh cd u-claw/portable && bash setup.sh
bash Mac-Start.command # Mac 测试
# 测试启动 bash Linux-Start.sh # Linux 测试
bash Mac-Start.command # Mac
# 或 Windows-Start.bat # Windows
# 测试没问题 → 拷到 U 盘
# 有问题 → 修代码 → 重新测试
``` ```
### 提交代码 **平台支持:**
```bash | 平台 | 状态 |
git checkout -b feat/your-feature |------|------|
git add -A | Mac Apple Silicon (M1-M4) | ✅ |
git commit -m "feat: your change" | Linux x86_64 | ✅ |
git push -u origin feat/your-feature | Linux ARM64 | ✅ |
``` | Windows x64 | 🚧 开发中 |
| Mac Intel | ❌ 暂不支持 |
## 待开发 / 欢迎贡献 欢迎 PR特别需要Windows 脚本完善、新平台支持、教程翻译。
- [ ] Windows 便携版完善测试 ### FAQ
- [ ] Mac Intel 支持
- [ ] Linux 支持AppImage
- [ ] 桌面版自动更新
- [ ] SkillHub 技能市场功能完善
- [ ] 多语言支持English UI
## FAQ
**Q: 需要翻墙吗?** **Q: 需要翻墙吗?**
安装不需要。运行需要联网调 API国产模型无需翻墙 不需要。安装和运行全程使用国内镜像,国产模型 API 直连
**Q: U 盘需要多大?** **Q: U 盘需要多大?**
建议 4GB 以上(完整约 2.3GB)。 便携版 4GB+(完整约 2.3GB)。Linux 启动盘 64GB+ USB 3.0。
**Q: 能分发吗?** **Q: 能分发吗?**
MIT 协议,随便复制。 MIT 协议,随便复制分发
**Q: Mac 提示"未验证的开发者"** **Q: Mac 提示"未验证的开发者"**
右键脚本 → 打开。 右键脚本 → 打开。
## License ### 联系
[MIT](LICENSE)
## 联系
- 微信: hecare888 - 微信: hecare888
- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) - 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)** **Made with 🦞 by [dongsheng](https://github.com/dongsheng123132)**

273
portable/Linux-Install.sh Executable file
View 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
View 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
View 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..."

View File

@@ -27,7 +27,10 @@ export OPENCLAW_HOME="$DATA_DIR"
export OPENCLAW_STATE_DIR="$STATE_DIR" export OPENCLAW_STATE_DIR="$STATE_DIR"
export OPENCLAW_CONFIG_PATH="$CONFIG_PATH" 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 # Remove macOS quarantine
if xattr -l "$NODE_BIN" 2>/dev/null | grep -q "com.apple.quarantine"; then 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}[7]${NC} 恢复备份"
echo -e " ${GREEN}[8]${NC} 系统信息" echo -e " ${GREEN}[8]${NC} 系统信息"
echo "" 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 -e " ${DIM}[0] 退出${NC}"
echo "" echo ""
} }
@@ -255,7 +267,7 @@ do_sysinfo() {
# Main loop # Main loop
while true; do while true; do
show_menu show_menu
read -p " 请选择 [0-8]: " CHOICE read -p " 请选择 [0-15]: " CHOICE
echo "" echo ""
case $CHOICE in case $CHOICE in
@@ -267,6 +279,13 @@ while true; do
6) do_backup ;; 6) do_backup ;;
7) do_restore ;; 7) do_restore ;;
8) do_sysinfo ;; 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 ;; 0) echo -e " ${CYAN}再见!${NC}"; exit 0 ;;
*) echo -e " ${RED}无效选择${NC}" ;; *) echo -e " ${RED}无效选择${NC}" ;;
esac esac

View File

@@ -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") 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" 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=$! GW_PID=$!
# ---- 10. Wait & open browser ---- # ---- 10. Wait & open browser ----

View File

@@ -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 "%STATE_DIR%" mkdir "%STATE_DIR%"
if not exist "%DATA_DIR%\memory" mkdir "%DATA_DIR%\memory" 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%\backups" mkdir "%DATA_DIR%\backups"
if not exist "%DATA_DIR%\logs" mkdir "%DATA_DIR%\logs"
:menu :menu
cls cls
@@ -50,9 +51,18 @@ echo [6] Backup config
echo [7] Restore backup echo [7] Restore backup
echo [8] System info echo [8] System info
echo. 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 [0] Exit
echo. echo.
set /p choice=" Choose [0-8]: " set /p choice=" Choose [0-15]: "
if "%choice%"=="1" goto :onboard if "%choice%"=="1" goto :onboard
if "%choice%"=="2" goto :dashboard if "%choice%"=="2" goto :dashboard
@@ -62,6 +72,13 @@ if "%choice%"=="5" goto :doctor
if "%choice%"=="6" goto :backup if "%choice%"=="6" goto :backup
if "%choice%"=="7" goto :restore if "%choice%"=="7" goto :restore
if "%choice%"=="8" goto :sysinfo 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 if "%choice%"=="0" exit /b 0
echo Invalid choice echo Invalid choice
pause pause
@@ -179,4 +196,172 @@ echo OS: Windows
echo Path: %UCLAW_DIR% echo Path: %UCLAW_DIR%
echo Data: %DATA_DIR% echo Data: %DATA_DIR%
pause 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 goto :menu

View File

@@ -104,8 +104,25 @@ echo DO NOT close this window while using U-Claw!
echo. echo.
cd /d "%CORE_DIR%" 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" 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.
echo OpenClaw stopped. echo OpenClaw stopped.

473
portable/lib/maintain.sh Normal file
View 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
View 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 " 按回车关闭..."