diff --git a/CLAUDE.md b/CLAUDE.md
index fbb4af1..f499c6b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -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
diff --git a/README.md b/README.md
index 91ebde0..33fc25d 100644
--- a/README.md
+++ b/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)
---
-## 使用方式
+
+
+## 中文
+
+### 这是什么
+
+这个仓库是一个**制作教程 + 全套源代码**,教你把 [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 协议,随便复制。
---
+
+
+## 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)**
diff --git a/portable/Linux-Install.sh b/portable/Linux-Install.sh
new file mode 100755
index 0000000..521b66b
--- /dev/null
+++ b/portable/Linux-Install.sh
@@ -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 " 按回车关闭..."
diff --git a/portable/Linux-Menu.sh b/portable/Linux-Menu.sh
new file mode 100755
index 0000000..63d24e8
--- /dev/null
+++ b/portable/Linux-Menu.sh
@@ -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
diff --git a/portable/Linux-Start.sh b/portable/Linux-Start.sh
new file mode 100755
index 0000000..c5175a1
--- /dev/null
+++ b/portable/Linux-Start.sh
@@ -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..."
diff --git a/portable/Mac-Menu.command b/portable/Mac-Menu.command
index 474c77a..00dc772 100755
--- a/portable/Mac-Menu.command
+++ b/portable/Mac-Menu.command
@@ -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
diff --git a/portable/Mac-Start.command b/portable/Mac-Start.command
index 67ae4d3..b96a1e9 100755
--- a/portable/Mac-Start.command
+++ b/portable/Mac-Start.command
@@ -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 ----
diff --git a/portable/Windows-Menu.bat b/portable/Windows-Menu.bat
index cc2bbcb..3989bc9 100644
--- a/portable/Windows-Menu.bat
+++ b/portable/Windows-Menu.bat
@@ -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
\ No newline at end of file
diff --git a/portable/Windows-Start.bat b/portable/Windows-Start.bat
index e1da2ca..08e6136 100644
--- a/portable/Windows-Start.bat
+++ b/portable/Windows-Start.bat
@@ -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.
diff --git a/portable/lib/maintain.sh b/portable/lib/maintain.sh
new file mode 100644
index 0000000..a39fd38
--- /dev/null
+++ b/portable/lib/maintain.sh
@@ -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
+}
diff --git a/portable/setup-linux-usb.sh b/portable/setup-linux-usb.sh
new file mode 100755
index 0000000..98c99d9
--- /dev/null
+++ b/portable/setup-linux-usb.sh
@@ -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 " 按回车关闭..."