Add crabwalk CLI (#30)

* feat: add crabwalk CLI

- bin/crabwalk: shell wrapper with start/stop/status/update commands
- daemon mode with --daemon flag
- auto-detect gateway token from ~/.clawdbot/clawdbot.json
- show network IPs on startup for remote access
- update skill.md and README with CLI usage

* auto-add ~/.local/bin to PATH during install

* support zsh PATH config
This commit is contained in:
Luciano Castillo
2026-02-01 15:24:33 -05:00
committed by GitHub
parent efb1790964
commit 27d0afd736
5 changed files with 351 additions and 46 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
- name: Create build artifact
run: |
tar -czvf crabwalk-${{ github.ref_name }}.tar.gz .output
tar -czvf crabwalk-${{ github.ref_name }}.tar.gz .output bin package.json
- name: Upload build to release
uses: softprops/action-gh-release@v1
+21
View File
@@ -26,6 +26,27 @@ Paste this link to your OpenClaw agent and ask it to install/update Crabwalk:
https://raw.githubusercontent.com/luccast/crabwalk/master/public/skill.md
```
### CLI Install
```bash
VERSION=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
mkdir -p ~/.crabwalk ~/.local/bin
curl -sL "https://github.com/luccast/crabwalk/releases/download/${VERSION}/crabwalk-${VERSION}.tar.gz" | tar -xz -C ~/.crabwalk
cp ~/.crabwalk/bin/crabwalk ~/.local/bin/
chmod +x ~/.local/bin/crabwalk
```
Then run:
```bash
crabwalk # Start on 0.0.0.0:3000
crabwalk start --daemon # Run in background
crabwalk start -p 8080 # Custom port
crabwalk stop # Stop daemon
crabwalk status # Check if running
crabwalk update # Update to latest
```
### Docker (recommended)
```bash
Executable
+277
View File
@@ -0,0 +1,277 @@
#!/usr/bin/env bash
# 🦀 Crabwalk CLI
set -e
CRABWALK_HOME="${CRABWALK_HOME:-$HOME/.crabwalk}"
PID_FILE="$CRABWALK_HOME/crabwalk.pid"
LOG_FILE="$CRABWALK_HOME/crabwalk.log"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Get version from package.json
get_version() {
cat "$CRABWALK_HOME/package.json" 2>/dev/null | grep '"version"' | cut -d'"' -f4
}
# Auto-detect token from OpenClaw config
auto_token() {
if [ -f "$HOME/.clawdbot/clawdbot.json" ]; then
python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.clawdbot/clawdbot.json')))['gateway']['auth']['token'])" 2>/dev/null || true
fi
}
# Get network IPs
get_network_ips() {
if command -v hostname &>/dev/null; then
hostname -I 2>/dev/null | tr ' ' '\n' | grep -v '^$' || true
elif command -v ip &>/dev/null; then
ip -4 addr show 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' || true
fi
}
# Check if running
is_running() {
if [ -f "$PID_FILE" ]; then
local pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
echo "$pid"
return 0
fi
fi
return 1
}
# Show startup banner
show_banner() {
local port="${1:-3000}"
local host="${2:-0.0.0.0}"
local version=$(get_version)
echo ""
echo -e "🦀 ${GREEN}Crabwalk${NC} v${version}"
echo ""
if [ "$host" = "0.0.0.0" ]; then
echo -e " ➜ Local: ${CYAN}http://localhost:${port}/monitor${NC}"
for ip in $(get_network_ips); do
echo -e " ➜ Network: ${CYAN}http://${ip}:${port}/monitor${NC}"
done
else
echo -e " ➜ Server: ${CYAN}http://${host}:${port}/monitor${NC}"
fi
echo ""
}
# Show help
show_help() {
local version=$(get_version)
echo "🦀 Crabwalk v${version:-unknown}"
echo ""
echo "Usage: crabwalk <command> [options]"
echo ""
echo "Commands:"
echo " start Start server (default)"
echo " stop Stop running server"
echo " status Check if server is running"
echo " update Update to latest version"
echo " help Show this help"
echo ""
echo "Options:"
echo " -p, --port <port> Server port (default: 3000)"
echo " -H, --host <host> Bind address (default: 0.0.0.0)"
echo " -g, --gateway <url> Gateway WebSocket URL"
echo " -t, --token <token> Gateway auth token"
echo " -d, --daemon Run in background"
echo " -v, --version Show version"
echo " -h, --help Show help"
echo ""
echo "Examples:"
echo " crabwalk # Start on 0.0.0.0:3000"
echo " crabwalk start --daemon # Run in background"
echo " crabwalk start -p 8080 # Custom port"
echo " crabwalk stop # Stop daemon"
echo " crabwalk status # Check status"
echo " crabwalk update # Update to latest"
}
# Start command
cmd_start() {
local port="${PORT:-3000}"
local host="${HOST:-0.0.0.0}"
local daemon=false
local token="${CLAWDBOT_API_TOKEN}"
local gateway="${CLAWDBOT_URL}"
# Parse args
while [[ $# -gt 0 ]]; do
case $1 in
-p|--port) port="$2"; shift 2 ;;
-H|--host) host="$2"; shift 2 ;;
-t|--token) token="$2"; shift 2 ;;
-g|--gateway) gateway="$2"; shift 2 ;;
-d|--daemon) daemon=true; shift ;;
*) shift ;;
esac
done
# Auto-detect token if not provided
if [ -z "$token" ]; then
token=$(auto_token)
fi
# Check if already running
if pid=$(is_running); then
echo -e "🦀 Crabwalk is already running (PID $pid)"
echo -e " Use ${YELLOW}crabwalk stop${NC} first"
exit 1
fi
# Check if crabwalk is installed
if [ ! -f "$CRABWALK_HOME/.output/server/index.mjs" ]; then
echo -e "${RED}Error:${NC} Crabwalk not found at $CRABWALK_HOME"
echo "Install with: https://raw.githubusercontent.com/luccast/crabwalk/master/public/skill.md"
exit 1
fi
# Build env vars
export PORT="$port"
export HOST="$host"
[ -n "$token" ] && export CLAWDBOT_API_TOKEN="$token"
[ -n "$gateway" ] && export CLAWDBOT_URL="$gateway"
if [ "$daemon" = true ]; then
# Run in background
nohup node "$CRABWALK_HOME/.output/server/index.mjs" > "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
sleep 1
if is_running >/dev/null; then
show_banner "$port" "$host"
echo -e "🦀 Running in background (PID $(cat $PID_FILE))"
echo -e " Logs: ${CYAN}$LOG_FILE${NC}"
else
echo -e "${RED}Error:${NC} Failed to start. Check $LOG_FILE"
exit 1
fi
else
# Run in foreground
show_banner "$port" "$host"
echo -e "Press ${YELLOW}Ctrl+C${NC} to stop"
echo ""
exec node "$CRABWALK_HOME/.output/server/index.mjs"
fi
}
# Stop command
cmd_stop() {
if pid=$(is_running); then
kill "$pid" 2>/dev/null
rm -f "$PID_FILE"
echo "🦀 Crabwalk stopped"
else
echo "🦀 Crabwalk is not running"
fi
}
# Status command
cmd_status() {
local port="${PORT:-3000}"
if pid=$(is_running); then
echo -e "🦀 Crabwalk is ${GREEN}running${NC} (PID $pid)"
echo -e " http://localhost:${port}/monitor"
else
echo -e "🦀 Crabwalk is ${RED}stopped${NC}"
fi
}
# Update command
cmd_update() {
local installed=$(get_version)
local latest=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4 | tr -d 'v')
if [ -z "$installed" ]; then
echo "🦀 Crabwalk not installed"
exit 1
fi
if [ -z "$latest" ]; then
echo -e "${RED}Error:${NC} Could not fetch latest version"
exit 1
fi
if [ "$installed" = "$latest" ]; then
echo "🦀 Already on latest: $installed"
exit 0
fi
echo "🦀 Update available: $installed -> $latest"
echo " https://github.com/luccast/crabwalk/releases/tag/v${latest}"
echo ""
read -p "Update now? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Stop if running
if is_running >/dev/null; then
echo "🦀 Stopping server..."
cmd_stop
fi
echo "🦀 Downloading v${latest}..."
local version="v${latest}"
rm -rf "$CRABWALK_HOME/.output"
curl -sL "https://github.com/luccast/crabwalk/releases/download/${version}/crabwalk-${version}.tar.gz" | tar -xz -C "$CRABWALK_HOME"
# Update CLI if needed
if [ -f "$CRABWALK_HOME/bin/crabwalk" ]; then
cp "$CRABWALK_HOME/bin/crabwalk" ~/.local/bin/crabwalk 2>/dev/null || true
fi
echo "🦀 Updated to v${latest}"
else
echo "🦀 Update cancelled"
fi
}
# Main
main() {
local cmd="${1:-start}"
shift 2>/dev/null || true
# Handle flags before command
case $cmd in
-v|--version)
echo "🦀 Crabwalk v$(get_version)"
exit 0
;;
-h|--help|help)
show_help
exit 0
;;
start)
cmd_start "$@"
;;
stop)
cmd_stop
;;
status)
cmd_status
;;
update)
cmd_update
;;
*)
# Assume it's an option for start
cmd_start "$cmd" "$@"
;;
esac
}
main "$@"
+2 -1
View File
@@ -11,6 +11,7 @@
"install": {
"method": "tarball",
"location": "~/.crabwalk",
"start_command": "node ~/.crabwalk/.output/server/index.mjs"
"cli": "~/.local/bin/crabwalk",
"start_command": "crabwalk"
}
}
+50 -44
View File
@@ -11,74 +11,77 @@ metadata: {"emoji":"🦀","category":"monitoring"}
Real-time companion monitor for OpenClaw agents. Visualize agent sessions, tool calls, and activity in a reactive graph UI.
## Quick Install
## Install
```bash
# Get latest version
# Download latest release
VERSION=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
# Download and extract
mkdir -p ~/.crabwalk
curl -sL "https://github.com/luccast/crabwalk/releases/download/${VERSION}/crabwalk-${VERSION}.tar.gz" | tar -xz -C ~/.crabwalk
# Start server (runs on port 3000)
node ~/.crabwalk/.output/server/index.mjs
# Install CLI
mkdir -p ~/.local/bin
cp ~/.crabwalk/bin/crabwalk ~/.local/bin/crabwalk
chmod +x ~/.local/bin/crabwalk
# Add to PATH if needed
if ! echo $PATH | grep -q "$HOME/.local/bin"; then
[ -f ~/.bashrc ] && echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
[ -f ~/.zshrc ] && echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
export PATH="$HOME/.local/bin:$PATH"
fi
```
## One-Liner Install
```bash
VERSION=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4) && mkdir -p ~/.crabwalk && curl -sL "https://github.com/luccast/crabwalk/releases/download/${VERSION}/crabwalk-${VERSION}.tar.gz" | tar -xz -C ~/.crabwalk && echo "Crabwalk ${VERSION} installed to ~/.crabwalk"
VERSION=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4) && mkdir -p ~/.crabwalk ~/.local/bin && curl -sL "https://github.com/luccast/crabwalk/releases/download/${VERSION}/crabwalk-${VERSION}.tar.gz" | tar -xz -C ~/.crabwalk && cp ~/.crabwalk/bin/crabwalk ~/.local/bin/ && chmod +x ~/.local/bin/crabwalk && (echo $PATH | grep -q "$HOME/.local/bin" || ([ -f ~/.bashrc ] && echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc; [ -f ~/.zshrc ] && echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc; export PATH="$HOME/.local/bin:$PATH")) && echo "🦀 Crabwalk ${VERSION} installed"
```
## Running
## CLI Usage
```bash
# Default (port 3000)
node ~/.crabwalk/.output/server/index.mjs
# Custom port
PORT=8080 node ~/.crabwalk/.output/server/index.mjs
# With gateway auth token
CLAWDBOT_API_TOKEN=your_token node ~/.crabwalk/.output/server/index.mjs
crabwalk # Start server (0.0.0.0:3000)
crabwalk start --daemon # Run in background
crabwalk start -p 8080 # Custom port
crabwalk stop # Stop background server
crabwalk status # Check if running
crabwalk update # Update to latest version
crabwalk --help # Show all options
```
Open http://localhost:3000 in browser.
## CLI Options
## Configuration
| Env Var | Description | Default |
|---------|-------------|---------|
| `PORT` | Server port | `3000` |
| `CLAWDBOT_API_TOKEN` | Gateway auth token | none |
```
Options:
-p, --port <port> Server port (default: 3000)
-H, --host <host> Bind address (default: 0.0.0.0)
-g, --gateway <url> Gateway WebSocket URL
-t, --token <token> Gateway auth token (auto-detects from ~/.clawdbot/clawdbot.json)
-d, --daemon Run in background
-v, --version Show version
-h, --help Show help
```
## Features
- `/monitor` — Real-time agent activity graph (ReactFlow)
- `/workspace` — File browser and markdown viewer
- Live WebSocket updates from clawdbot gateway
- Auto-detects gateway token from OpenClaw config
## Requirements
- Node.js 20+
- clawdbot gateway running on `ws://127.0.0.1:18789`
- OpenClaw gateway running on `ws://127.0.0.1:18789`
## Check for Updates
```bash
INSTALLED=$(cat ~/.crabwalk/package.json 2>/dev/null | grep '"version"' | cut -d'"' -f4)
LATEST=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4 | tr -d 'v')
if [ -z "$INSTALLED" ]; then
echo "Crabwalk not installed"
elif [ "$INSTALLED" != "$LATEST" ]; then
echo "Update available: $INSTALLED -> $LATEST"
else
echo "Already on latest: $INSTALLED"
fi
crabwalk update
```
This checks for updates and prompts before installing.
## Updating
**IMPORTANT: Always ask user permission before updating.**
@@ -86,24 +89,27 @@ fi
If update available, ask user:
> "Crabwalk update available (X.X.X -> Y.Y.Y). See release: https://github.com/luccast/crabwalk/releases/tag/vY.Y.Y — Update now?"
Only proceed if user confirms:
Only proceed if user confirms. Run:
```bash
crabwalk update
```
Or manually:
```bash
VERSION=$(curl -s https://api.github.com/repos/luccast/crabwalk/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
rm -rf ~/.crabwalk
mkdir -p ~/.crabwalk
rm -rf ~/.crabwalk/.output
curl -sL "https://github.com/luccast/crabwalk/releases/download/${VERSION}/crabwalk-${VERSION}.tar.gz" | tar -xz -C ~/.crabwalk
echo "Updated to ${VERSION}"
cp ~/.crabwalk/bin/crabwalk ~/.local/bin/crabwalk
echo "🦀 Updated to ${VERSION}"
```
## Verify Installation
```bash
# Check version
cat ~/.crabwalk/package.json | grep '"version"'
# Test server starts
timeout 5 node ~/.crabwalk/.output/server/index.mjs 2>&1 | head -5 || true
crabwalk --version
crabwalk status
```
---