fix: chat scroll, add sidebar logo, WSL2 docs
- Fix chat panel not scrolling by adding overflow-hidden to ScrollArea - Add 36x36 app logo next to "ClawPal" title in sidebar - Add WSL2 SSH setup guide to README Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
95
README.md
95
README.md
@@ -1,42 +1,91 @@
|
|||||||
# ClawPal MVP (Tauri)
|
# ClawPal
|
||||||
|
|
||||||
ClawPal is a local helper for OpenClaw configuration:
|
A desktop companion app for [OpenClaw](https://github.com/openclaw/openclaw) — manage your AI agents, models, and configurations with a visual interface instead of editing JSON by hand.
|
||||||
- install scenarios via Recipes
|
|
||||||
- one-click rollback for every config change
|
|
||||||
- local doctor checks with basic auto-fixes
|
|
||||||
|
|
||||||
## Quick start
|
## Features
|
||||||
|
|
||||||
|
- **Recipes** — Browse and apply pre-built configuration templates with parameter forms, live diffs, and automatic rollback on failure
|
||||||
|
- **Agent Management** — Create, configure, and monitor your OpenClaw agents at a glance
|
||||||
|
- **Model Profiles** — Set up API keys, browse the model catalog, and switch the global default model in one click
|
||||||
|
- **Channel Bindings** — Connect Discord channels to agents with per-channel model overrides
|
||||||
|
- **Doctor** — Run diagnostics, auto-fix common issues, and clean up stale sessions
|
||||||
|
- **History & Rollback** — Every config change is snapshotted; roll back to any point in time
|
||||||
|
- **Remote Management** — Connect to remote OpenClaw instances over SSH and manage them the same way
|
||||||
|
- **Auto-Update** — ClawPal checks for new versions and updates itself in-app
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Download the latest release for your platform from [GitHub Releases](https://github.com/zhixianio/clawpal/releases):
|
||||||
|
|
||||||
|
| Platform | Format |
|
||||||
|
|----------|--------|
|
||||||
|
| macOS (Apple Silicon) | `.dmg` |
|
||||||
|
| macOS (Intel) | `.dmg` |
|
||||||
|
| Windows | `.exe` installer or portable |
|
||||||
|
| Linux | `.deb` / `.AppImage` |
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Prerequisites: [Node.js](https://nodejs.org/) 20+, [Rust](https://www.rust-lang.org/tools/install), and [Tauri CLI](https://v2.tauri.app/start/prerequisites/)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
npm install
|
||||||
npm run dev
|
npm run dev # Vite dev server + Tauri window
|
||||||
```
|
```
|
||||||
|
|
||||||
### Override folders outside `~/.openclaw`
|
### Build
|
||||||
|
|
||||||
You can place ClawPal-managed files outside `~/.openclaw` with env vars:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export CLAWPAL_OPENCLAW_DIR="$HOME/.openclaw" # OpenClaw 配置来源目录(默认)
|
|
||||||
export CLAWPAL_DATA_DIR="$HOME/.clawpal" # ClawPal 元数据目录(默认: $CLAWPAL_OPENCLAW_DIR/.clawpal)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
cd src-tauri && cargo build
|
cd src-tauri && cargo build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Release
|
### Release
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run release:dry-run
|
npm run release:dry-run # Preview version bump + tag
|
||||||
npm run release
|
npm run release # Tag and push (triggers CI)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Environment overrides
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export CLAWPAL_OPENCLAW_DIR="$HOME/.openclaw" # OpenClaw config directory (default)
|
||||||
|
export CLAWPAL_DATA_DIR="$HOME/.clawpal" # ClawPal metadata directory
|
||||||
|
```
|
||||||
|
|
||||||
|
## WSL2 (Windows Subsystem for Linux)
|
||||||
|
|
||||||
|
If you have OpenClaw installed inside WSL2, you can manage it from ClawPal using the built-in SSH Remote feature:
|
||||||
|
|
||||||
|
1. Enable SSH inside your WSL2 distro:
|
||||||
|
```bash
|
||||||
|
sudo apt install openssh-server
|
||||||
|
sudo systemctl enable ssh
|
||||||
|
sudo systemctl start ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. In ClawPal, add a new SSH host:
|
||||||
|
- **Host**: `localhost`
|
||||||
|
- **Port**: the SSH port (default `22`, or check with `ss -tlnp | grep ssh`)
|
||||||
|
- **User**: your WSL2 username
|
||||||
|
|
||||||
|
3. Connect — ClawPal will manage the WSL2 OpenClaw instance the same as any remote server.
|
||||||
|
|
||||||
|
## Tech stack
|
||||||
|
|
||||||
|
- **Frontend** — React, TypeScript, Tailwind CSS, Radix UI
|
||||||
|
- **Backend** — Rust, Tauri 2
|
||||||
|
- **Remote** — russh (SSH/SFTP)
|
||||||
|
|
||||||
## Project layout
|
## Project layout
|
||||||
|
|
||||||
- `src/` React + TypeScript UI
|
```
|
||||||
- `src-tauri/` Rust + Tauri host and command APIs
|
src/ React + TypeScript UI
|
||||||
- `docs/plans/` design and implementation plan
|
src-tauri/ Rust + Tauri backend
|
||||||
|
docs/plans/ Design and implementation plans
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Proprietary. All rights reserved.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Settings } from "./pages/Settings";
|
|||||||
import { Doctor } from "./pages/Doctor";
|
import { Doctor } from "./pages/Doctor";
|
||||||
import { Channels } from "./pages/Channels";
|
import { Channels } from "./pages/Channels";
|
||||||
import { Chat } from "./components/Chat";
|
import { Chat } from "./components/Chat";
|
||||||
|
import logoUrl from "./assets/logo.png";
|
||||||
import { DiffViewer } from "./components/DiffViewer";
|
import { DiffViewer } from "./components/DiffViewer";
|
||||||
import { InstanceTabBar } from "./components/InstanceTabBar";
|
import { InstanceTabBar } from "./components/InstanceTabBar";
|
||||||
import { InstanceContext } from "./lib/instance-context";
|
import { InstanceContext } from "./lib/instance-context";
|
||||||
@@ -218,7 +219,10 @@ export function App() {
|
|||||||
/>
|
/>
|
||||||
<div className="flex flex-1 overflow-hidden">
|
<div className="flex flex-1 overflow-hidden">
|
||||||
<aside className="w-[200px] min-w-[200px] bg-muted border-r border-border flex flex-col py-4">
|
<aside className="w-[200px] min-w-[200px] bg-muted border-r border-border flex flex-col py-4">
|
||||||
<h1 className="px-4 text-lg font-bold mb-4">ClawPal</h1>
|
<h1 className="px-4 text-lg font-bold mb-4 flex items-center gap-2">
|
||||||
|
<img src={logoUrl} alt="" className="w-9 h-9 rounded-lg" />
|
||||||
|
ClawPal
|
||||||
|
</h1>
|
||||||
<nav className="flex flex-col gap-1 px-2 flex-1">
|
<nav className="flex flex-col gap-1 px-2 flex-1">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -126,7 +126,7 @@ export function Chat() {
|
|||||||
New
|
New
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<ScrollArea className="flex-1 mb-2">
|
<ScrollArea className="flex-1 mb-2 overflow-hidden">
|
||||||
{messages.map((msg, i) => (
|
{messages.map((msg, i) => (
|
||||||
<div key={i} className={cn("mb-2", msg.role === "user" ? "text-right" : "text-left")}>
|
<div key={i} className={cn("mb-2", msg.role === "user" ? "text-right" : "text-left")}>
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
|
|||||||
Reference in New Issue
Block a user