Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
126eea5e5c | ||
|
|
433eb2de51 | ||
|
|
41ae7bb9c7 |
67
.github/workflows/release-beta-on-push.yml
vendored
67
.github/workflows/release-beta-on-push.yml
vendored
@ -266,9 +266,65 @@ jobs:
|
|||||||
path: zeroclaw-${{ matrix.target }}.${{ matrix.ext }}
|
path: zeroclaw-${{ matrix.target }}.${{ matrix.ext }}
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
build-desktop:
|
||||||
|
name: Build Desktop App (macOS Universal)
|
||||||
|
needs: [version]
|
||||||
|
if: needs.version.outputs.skip != 'true'
|
||||||
|
runs-on: macos-14
|
||||||
|
timeout-minutes: 40
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
|
|
||||||
|
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
|
||||||
|
with:
|
||||||
|
toolchain: 1.92.0
|
||||||
|
targets: aarch64-apple-darwin,x86_64-apple-darwin
|
||||||
|
|
||||||
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
|
||||||
|
with:
|
||||||
|
prefix-key: macos-tauri
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
|
||||||
|
- name: Install Tauri CLI
|
||||||
|
run: cargo install tauri-cli --locked
|
||||||
|
|
||||||
|
- name: Sync Tauri version with Cargo.toml
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
VERSION=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
|
||||||
|
cd apps/tauri
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
jq --arg v "$VERSION" '.version = $v' tauri.conf.json > tmp.json && mv tmp.json tauri.conf.json
|
||||||
|
else
|
||||||
|
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" tauri.conf.json
|
||||||
|
fi
|
||||||
|
echo "Tauri version set to: $VERSION"
|
||||||
|
|
||||||
|
- name: Build Tauri app (universal binary)
|
||||||
|
working-directory: apps/tauri
|
||||||
|
run: cargo tauri build --target universal-apple-darwin
|
||||||
|
|
||||||
|
- name: Prepare desktop release assets
|
||||||
|
run: |
|
||||||
|
mkdir -p desktop-assets
|
||||||
|
find target -name '*.dmg' -exec cp {} desktop-assets/ZeroClaw.dmg \; 2>/dev/null || true
|
||||||
|
find target -name '*.app.tar.gz' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz \; 2>/dev/null || true
|
||||||
|
find target -name '*.app.tar.gz.sig' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz.sig \; 2>/dev/null || true
|
||||||
|
echo "--- Desktop assets ---"
|
||||||
|
ls -lh desktop-assets/
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
|
with:
|
||||||
|
name: desktop-macos
|
||||||
|
path: desktop-assets/*
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
name: Publish Beta Release
|
name: Publish Beta Release
|
||||||
needs: [version, release-notes, build]
|
needs: [version, release-notes, build, build-desktop]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
@ -278,16 +334,21 @@ jobs:
|
|||||||
pattern: zeroclaw-*
|
pattern: zeroclaw-*
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||||
|
with:
|
||||||
|
name: desktop-macos
|
||||||
|
path: artifacts/desktop-macos
|
||||||
|
|
||||||
- name: Generate checksums
|
- name: Generate checksums
|
||||||
run: |
|
run: |
|
||||||
cd artifacts
|
cd artifacts
|
||||||
find . -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
|
find . -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
|
||||||
cat SHA256SUMS
|
cat SHA256SUMS
|
||||||
|
|
||||||
- name: Collect release assets
|
- name: Collect release assets
|
||||||
run: |
|
run: |
|
||||||
mkdir -p release-assets
|
mkdir -p release-assets
|
||||||
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
|
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
|
||||||
cp install.sh release-assets/
|
cp install.sh release-assets/
|
||||||
echo "--- Assets ---"
|
echo "--- Assets ---"
|
||||||
ls -lh release-assets/
|
ls -lh release-assets/
|
||||||
|
|||||||
66
.github/workflows/release-stable-manual.yml
vendored
66
.github/workflows/release-stable-manual.yml
vendored
@ -273,9 +273,64 @@ jobs:
|
|||||||
path: zeroclaw-${{ matrix.target }}.${{ matrix.ext }}
|
path: zeroclaw-${{ matrix.target }}.${{ matrix.ext }}
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|
||||||
|
build-desktop:
|
||||||
|
name: Build Desktop App (macOS Universal)
|
||||||
|
needs: [validate]
|
||||||
|
runs-on: macos-14
|
||||||
|
timeout-minutes: 40
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
|
|
||||||
|
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
|
||||||
|
with:
|
||||||
|
toolchain: 1.92.0
|
||||||
|
targets: aarch64-apple-darwin,x86_64-apple-darwin
|
||||||
|
|
||||||
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
|
||||||
|
with:
|
||||||
|
prefix-key: macos-tauri
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
|
||||||
|
- name: Install Tauri CLI
|
||||||
|
run: cargo install tauri-cli --locked
|
||||||
|
|
||||||
|
- name: Sync Tauri version with Cargo.toml
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
VERSION=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
|
||||||
|
cd apps/tauri
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
jq --arg v "$VERSION" '.version = $v' tauri.conf.json > tmp.json && mv tmp.json tauri.conf.json
|
||||||
|
else
|
||||||
|
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" tauri.conf.json
|
||||||
|
fi
|
||||||
|
echo "Tauri version set to: $VERSION"
|
||||||
|
|
||||||
|
- name: Build Tauri app (universal binary)
|
||||||
|
working-directory: apps/tauri
|
||||||
|
run: cargo tauri build --target universal-apple-darwin
|
||||||
|
|
||||||
|
- name: Prepare desktop release assets
|
||||||
|
run: |
|
||||||
|
mkdir -p desktop-assets
|
||||||
|
find target -name '*.dmg' -exec cp {} desktop-assets/ZeroClaw.dmg \; 2>/dev/null || true
|
||||||
|
find target -name '*.app.tar.gz' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz \; 2>/dev/null || true
|
||||||
|
find target -name '*.app.tar.gz.sig' -exec cp {} desktop-assets/ZeroClaw-macos.app.tar.gz.sig \; 2>/dev/null || true
|
||||||
|
echo "--- Desktop assets ---"
|
||||||
|
ls -lh desktop-assets/
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
|
with:
|
||||||
|
name: desktop-macos
|
||||||
|
path: desktop-assets/*
|
||||||
|
retention-days: 14
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
name: Publish Stable Release
|
name: Publish Stable Release
|
||||||
needs: [validate, release-notes, build]
|
needs: [validate, release-notes, build, build-desktop]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
@ -285,16 +340,21 @@ jobs:
|
|||||||
pattern: zeroclaw-*
|
pattern: zeroclaw-*
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||||
|
with:
|
||||||
|
name: desktop-macos
|
||||||
|
path: artifacts/desktop-macos
|
||||||
|
|
||||||
- name: Generate checksums
|
- name: Generate checksums
|
||||||
run: |
|
run: |
|
||||||
cd artifacts
|
cd artifacts
|
||||||
find . -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
|
find . -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
|
||||||
cat SHA256SUMS
|
cat SHA256SUMS
|
||||||
|
|
||||||
- name: Collect release assets
|
- name: Collect release assets
|
||||||
run: |
|
run: |
|
||||||
mkdir -p release-assets
|
mkdir -p release-assets
|
||||||
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
|
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.dmg' -o -name 'SHA256SUMS' \) -exec cp {} release-assets/ \;
|
||||||
cp install.sh release-assets/
|
cp install.sh release-assets/
|
||||||
echo "--- Assets ---"
|
echo "--- Assets ---"
|
||||||
ls -lh release-assets/
|
ls -lh release-assets/
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -12364,7 +12364,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroclawlabs"
|
name = "zeroclawlabs"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aardvark-sys",
|
"aardvark-sys",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ resolver = "2"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "zeroclawlabs"
|
name = "zeroclawlabs"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["theonlyhennygod"]
|
authors = ["theonlyhennygod"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/config.schema.json",
|
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/config.schema.json",
|
||||||
"productName": "ZeroClaw",
|
"productName": "ZeroClaw",
|
||||||
"version": "0.6.0",
|
"version": "0.6.1",
|
||||||
"identifier": "ai.zeroclawlabs.desktop",
|
"identifier": "ai.zeroclawlabs.desktop",
|
||||||
"build": {
|
"build": {
|
||||||
"devUrl": "http://127.0.0.1:42617/_app/",
|
"devUrl": "http://127.0.0.1:42617/_app/",
|
||||||
|
|||||||
163
install.sh
163
install.sh
@ -230,6 +230,49 @@ detect_release_target() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_device_class() {
|
||||||
|
# Containers are never desktops
|
||||||
|
if _is_container_runtime; then
|
||||||
|
echo "container"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Termux / Android
|
||||||
|
if [[ -n "${TERMUX_VERSION:-}" || -d "/data/data/com.termux" ]]; then
|
||||||
|
echo "mobile"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local os arch
|
||||||
|
os="$(uname -s)"
|
||||||
|
arch="$(uname -m)"
|
||||||
|
|
||||||
|
case "$os" in
|
||||||
|
Darwin)
|
||||||
|
# macOS is always a desktop
|
||||||
|
echo "desktop"
|
||||||
|
;;
|
||||||
|
Linux)
|
||||||
|
# Raspberry Pi / ARM SBCs — treat as embedded (typically headless)
|
||||||
|
case "$arch" in
|
||||||
|
armv6l|armv7l)
|
||||||
|
echo "embedded"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
# Check for a display server (X11 or Wayland)
|
||||||
|
if [[ -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" || -n "${XDG_SESSION_TYPE:-}" ]]; then
|
||||||
|
echo "desktop"
|
||||||
|
else
|
||||||
|
echo "server"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "server"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
should_attempt_prebuilt_for_resources() {
|
should_attempt_prebuilt_for_resources() {
|
||||||
local workspace="${1:-.}"
|
local workspace="${1:-.}"
|
||||||
local min_ram_mb min_disk_mb total_ram_mb free_disk_mb low_resource
|
local min_ram_mb min_disk_mb total_ram_mb free_disk_mb low_resource
|
||||||
@ -1155,6 +1198,9 @@ while [[ $# -gt 0 ]]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
OS_NAME="$(uname -s)"
|
OS_NAME="$(uname -s)"
|
||||||
|
DEVICE_CLASS="$(detect_device_class)"
|
||||||
|
step_dot "Device: $OS_NAME/$(uname -m) ($DEVICE_CLASS)"
|
||||||
|
|
||||||
if [[ "$GUIDED_MODE" == "auto" ]]; then
|
if [[ "$GUIDED_MODE" == "auto" ]]; then
|
||||||
if [[ "$OS_NAME" == "Linux" && "$ORIGINAL_ARG_COUNT" -eq 0 && -t 0 && -t 1 ]]; then
|
if [[ "$OS_NAME" == "Linux" && "$ORIGINAL_ARG_COUNT" -eq 0 && -t 0 && -t 1 ]]; then
|
||||||
GUIDED_MODE="on"
|
GUIDED_MODE="on"
|
||||||
@ -1479,63 +1525,64 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Build desktop app (macOS only) ---
|
# --- Companion desktop app (device-class-aware) ---
|
||||||
if [[ "$SKIP_BUILD" == false && "$OS_NAME" == "Darwin" && -d "$WORK_DIR/apps/tauri" ]]; then
|
# The desktop app is a pre-built download from the website, not built from source.
|
||||||
echo
|
# This keeps the one-liner install fast and the CLI binary small.
|
||||||
echo -e "${BOLD}Desktop app preflight${RESET}"
|
DESKTOP_DOWNLOAD_URL="https://www.zeroclawlabs.ai/download"
|
||||||
|
DESKTOP_APP_DETECTED=false
|
||||||
|
|
||||||
_desktop_ok=true
|
if [[ "$DEVICE_CLASS" == "desktop" ]]; then
|
||||||
|
# Check if the companion app is already installed
|
||||||
# Check Rust toolchain
|
case "$OS_NAME" in
|
||||||
if have_cmd cargo && have_cmd rustc; then
|
Darwin)
|
||||||
step_ok "Rust $(rustc --version | awk '{print $2}') found"
|
if [[ -d "/Applications/ZeroClaw.app" ]] || [[ -d "$HOME/Applications/ZeroClaw.app" ]]; then
|
||||||
else
|
DESKTOP_APP_DETECTED=true
|
||||||
step_fail "Rust toolchain not found — required for desktop app"
|
step_ok "Companion app found (ZeroClaw.app)"
|
||||||
_desktop_ok=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check Xcode CLT (needed for linking native frameworks)
|
|
||||||
if xcode-select -p >/dev/null 2>&1; then
|
|
||||||
step_ok "Xcode Command Line Tools installed"
|
|
||||||
else
|
|
||||||
step_fail "Xcode Command Line Tools not found — run: xcode-select --install"
|
|
||||||
_desktop_ok=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check that the Tauri CLI is available (cargo-tauri or tauri-cli)
|
|
||||||
if have_cmd cargo-tauri; then
|
|
||||||
step_ok "cargo-tauri $(cargo tauri --version 2>/dev/null | awk '{print $NF}') found"
|
|
||||||
else
|
|
||||||
step_dot "cargo-tauri not found — installing"
|
|
||||||
if cargo install tauri-cli --locked 2>/dev/null; then
|
|
||||||
step_ok "cargo-tauri installed"
|
|
||||||
else
|
|
||||||
warn "Failed to install cargo-tauri — desktop app build may fail"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check node/npm (needed for web frontend that Tauri embeds)
|
|
||||||
if have_cmd node && have_cmd npm; then
|
|
||||||
step_ok "Node.js $(node --version) found"
|
|
||||||
else
|
|
||||||
warn "node/npm not found — desktop app needs the web dashboard built first"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$_desktop_ok" == true ]]; then
|
|
||||||
step_dot "Building desktop app (zeroclaw-desktop)"
|
|
||||||
if cargo build -p zeroclaw-desktop --release --locked 2>/dev/null; then
|
|
||||||
step_ok "Desktop app built"
|
|
||||||
# Copy binary to cargo bin for easy access
|
|
||||||
if [[ -x "$WORK_DIR/target/release/zeroclaw-desktop" ]]; then
|
|
||||||
cp -f "$WORK_DIR/target/release/zeroclaw-desktop" "$HOME/.cargo/bin/zeroclaw-desktop" 2>/dev/null && \
|
|
||||||
step_ok "zeroclaw-desktop installed to ~/.cargo/bin" || true
|
|
||||||
fi
|
fi
|
||||||
else
|
;;
|
||||||
warn "Desktop app build failed — you can build later with: cargo build -p zeroclaw-desktop --release"
|
Linux)
|
||||||
fi
|
if have_cmd zeroclaw-desktop; then
|
||||||
else
|
DESKTOP_APP_DETECTED=true
|
||||||
warn "Skipping desktop app build — fix missing dependencies above and re-run"
|
step_ok "Companion app found (zeroclaw-desktop)"
|
||||||
|
elif [[ -x "$HOME/.local/bin/zeroclaw-desktop" ]]; then
|
||||||
|
DESKTOP_APP_DETECTED=true
|
||||||
|
step_ok "Companion app found (~/.local/bin/zeroclaw-desktop)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$DESKTOP_APP_DETECTED" == false ]]; then
|
||||||
|
echo
|
||||||
|
echo -e "${BOLD}Companion App${RESET}"
|
||||||
|
echo -e " Menu bar access to your ZeroClaw agent."
|
||||||
|
echo -e " Works alongside the CLI — connects to the same gateway."
|
||||||
|
echo
|
||||||
|
case "$OS_NAME" in
|
||||||
|
Darwin)
|
||||||
|
echo -e " ${BOLD}Download for macOS:${RESET} ${BLUE}${DESKTOP_DOWNLOAD_URL}${RESET}"
|
||||||
|
;;
|
||||||
|
Linux)
|
||||||
|
echo -e " ${BOLD}Download for Linux:${RESET} ${BLUE}${DESKTOP_DOWNLOAD_URL}${RESET}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo -e " ${DIM}Or run: zeroclaw desktop --install${RESET}"
|
||||||
fi
|
fi
|
||||||
|
elif [[ "$DEVICE_CLASS" != "desktop" ]]; then
|
||||||
|
# Non-desktop device — explain why companion app is not offered
|
||||||
|
case "$DEVICE_CLASS" in
|
||||||
|
mobile)
|
||||||
|
step_dot "Mobile device — use the web dashboard at http://127.0.0.1:42617"
|
||||||
|
;;
|
||||||
|
embedded)
|
||||||
|
step_dot "Embedded device ($(uname -m)) — use the web dashboard"
|
||||||
|
;;
|
||||||
|
container)
|
||||||
|
step_dot "Container runtime — use the web dashboard"
|
||||||
|
;;
|
||||||
|
server)
|
||||||
|
step_dot "Headless server — use the web dashboard"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ZEROCLAW_BIN=""
|
ZEROCLAW_BIN=""
|
||||||
@ -1704,8 +1751,12 @@ echo -e "${BOLD}Next steps:${RESET}"
|
|||||||
echo -e " ${DIM}zeroclaw status${RESET}"
|
echo -e " ${DIM}zeroclaw status${RESET}"
|
||||||
echo -e " ${DIM}zeroclaw agent -m \"Hello, ZeroClaw!\"${RESET}"
|
echo -e " ${DIM}zeroclaw agent -m \"Hello, ZeroClaw!\"${RESET}"
|
||||||
echo -e " ${DIM}zeroclaw gateway${RESET}"
|
echo -e " ${DIM}zeroclaw gateway${RESET}"
|
||||||
if [[ "$OS_NAME" == "Darwin" ]] && have_cmd zeroclaw-desktop; then
|
if [[ "$DEVICE_CLASS" == "desktop" ]]; then
|
||||||
echo -e " ${DIM}zeroclaw-desktop${RESET} ${DIM}# Launch the menu bar app${RESET}"
|
if [[ "$DESKTOP_APP_DETECTED" == true ]]; then
|
||||||
|
echo -e " ${DIM}zeroclaw desktop${RESET} ${DIM}# Launch the menu bar app${RESET}"
|
||||||
|
else
|
||||||
|
echo -e " ${DIM}zeroclaw desktop --install${RESET} ${DIM}# Download the companion app${RESET}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
echo
|
echo
|
||||||
echo -e "${BOLD}Docs:${RESET} ${BLUE}https://www.zeroclawlabs.ai/docs${RESET}"
|
echo -e "${BOLD}Docs:${RESET} ${BLUE}https://www.zeroclawlabs.ai/docs${RESET}"
|
||||||
|
|||||||
135
src/main.rs
135
src/main.rs
@ -535,6 +535,25 @@ Examples:
|
|||||||
shell: CompletionShell,
|
shell: CompletionShell,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Launch or install the companion desktop app
|
||||||
|
#[command(long_about = "\
|
||||||
|
Launch the ZeroClaw companion desktop app.
|
||||||
|
|
||||||
|
The companion app is a lightweight menu bar / system tray application \
|
||||||
|
that connects to the same gateway as the CLI. It provides quick access \
|
||||||
|
to the dashboard, status monitoring, and device pairing.
|
||||||
|
|
||||||
|
Use --install to download the pre-built companion app for your platform.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
zeroclaw desktop # launch the companion app
|
||||||
|
zeroclaw desktop --install # download and install it")]
|
||||||
|
Desktop {
|
||||||
|
/// Download and install the companion app
|
||||||
|
#[arg(long)]
|
||||||
|
install: bool,
|
||||||
|
},
|
||||||
|
|
||||||
/// Manage WASM plugins
|
/// Manage WASM plugins
|
||||||
#[cfg(feature = "plugins-wasm")]
|
#[cfg(feature = "plugins-wasm")]
|
||||||
Plugin {
|
Plugin {
|
||||||
@ -1324,6 +1343,122 @@ async fn main() -> Result<()> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Commands::Desktop {
|
||||||
|
install: do_install,
|
||||||
|
} => {
|
||||||
|
let download_url = "https://www.zeroclawlabs.ai/download";
|
||||||
|
|
||||||
|
if do_install {
|
||||||
|
println!("Download the ZeroClaw companion app:");
|
||||||
|
println!();
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
println!(" macOS: {download_url}");
|
||||||
|
println!();
|
||||||
|
println!("Or install via Homebrew (coming soon):");
|
||||||
|
println!(" brew install --cask zeroclaw");
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
println!(" Linux: {download_url}");
|
||||||
|
println!();
|
||||||
|
println!(" Download the .deb or .AppImage for your architecture.");
|
||||||
|
}
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||||
|
{
|
||||||
|
println!(" {download_url}");
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
// On macOS, open the download page in the browser
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
let _ = std::process::Command::new("open").arg(download_url).spawn();
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
let _ = std::process::Command::new("xdg-open")
|
||||||
|
.arg(download_url)
|
||||||
|
.spawn();
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate the companion app
|
||||||
|
let desktop_bin = {
|
||||||
|
let mut found = None;
|
||||||
|
|
||||||
|
// 1. macOS: check /Applications/ZeroClaw.app
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
let app_paths = [
|
||||||
|
PathBuf::from("/Applications/ZeroClaw.app/Contents/MacOS/ZeroClaw"),
|
||||||
|
PathBuf::from(std::env::var("HOME").unwrap_or_default())
|
||||||
|
.join("Applications/ZeroClaw.app/Contents/MacOS/ZeroClaw"),
|
||||||
|
];
|
||||||
|
for app in &app_paths {
|
||||||
|
if app.is_file() {
|
||||||
|
found = Some(app.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Same directory as the current executable
|
||||||
|
if found.is_none() {
|
||||||
|
if let Ok(exe) = std::env::current_exe() {
|
||||||
|
let sibling = exe.with_file_name("zeroclaw-desktop");
|
||||||
|
if sibling.is_file() {
|
||||||
|
found = Some(sibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. ~/.cargo/bin/zeroclaw-desktop or ~/.local/bin/zeroclaw-desktop
|
||||||
|
if found.is_none() {
|
||||||
|
if let Some(home) = std::env::var_os("HOME") {
|
||||||
|
let home = PathBuf::from(home);
|
||||||
|
for dir in &[".cargo/bin", ".local/bin"] {
|
||||||
|
let candidate = home.join(dir).join("zeroclaw-desktop");
|
||||||
|
if candidate.is_file() {
|
||||||
|
found = Some(candidate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Fallback to PATH lookup
|
||||||
|
if found.is_none() {
|
||||||
|
if let Ok(path) = which::which("zeroclaw-desktop") {
|
||||||
|
found = Some(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found
|
||||||
|
};
|
||||||
|
|
||||||
|
match desktop_bin {
|
||||||
|
Some(bin) => {
|
||||||
|
println!("Launching ZeroClaw companion app...");
|
||||||
|
let _child = std::process::Command::new(&bin)
|
||||||
|
.spawn()
|
||||||
|
.with_context(|| format!("Failed to launch {}", bin.display()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("ZeroClaw companion app is not installed.");
|
||||||
|
println!();
|
||||||
|
println!(" Download it at: {download_url}");
|
||||||
|
println!(" Or run: zeroclaw desktop --install");
|
||||||
|
println!();
|
||||||
|
println!("The companion app is a lightweight menu bar app that");
|
||||||
|
println!("connects to the same gateway as the CLI.");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Commands::Update {
|
Commands::Update {
|
||||||
check,
|
check,
|
||||||
force: _force,
|
force: _force,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user