diff --git a/docs/app/(home)/openclaw-os/page.tsx b/docs/app/(home)/openclaw-os/page.tsx index 9819b9e5e..a2b70f3a5 100644 --- a/docs/app/(home)/openclaw-os/page.tsx +++ b/docs/app/(home)/openclaw-os/page.tsx @@ -41,7 +41,8 @@ export default function OpenClawOSPage() { mobilePreviewImageWidth={804} mobilePreviewImageHeight={880} mobilePreviewImageCropTopPercent={20} - showGitHubBanner={false} + githubRepoUrl="https://github.com/thesysdev/openclaw-os" + githubButtonLabel="Star on GitHub" widePreview showTagline taglineCompact diff --git a/docs/app/(home)/sections/FeaturesSection/FeaturesSection.tsx b/docs/app/(home)/sections/FeaturesSection/FeaturesSection.tsx index 906bf1d30..a5f39d8c4 100644 --- a/docs/app/(home)/sections/FeaturesSection/FeaturesSection.tsx +++ b/docs/app/(home)/sections/FeaturesSection/FeaturesSection.tsx @@ -1,12 +1,13 @@ "use client"; import { - Browsers, - Eye, - MagicWand, - PushPin, - SlidersHorizontal, - SquaresFour, + BellIcon, + BrowserIcon, + EyeIcon, + MagicWandIcon, + PushPinIcon, + SlidersHorizontalIcon, + SquaresFourIcon, } from "@phosphor-icons/react"; import svgPaths from "@/imports/svg-urruvoh2be"; import { PillLink } from "../../components/Button/Button"; @@ -80,32 +81,37 @@ export const OPENCLAW_FEATURES: FeatureListItem[] = [ { title: "Generative UI", description: "Build apps, dashboards, and artifacts on demand", - icon: , + icon: , }, { title: "Persistent apps", description: "Apps stay in place and refresh with live data automatically", - icon: , + icon: , }, { title: "Structured workspace", description: "Agents, sessions, artifacts, and apps in one organized space", - icon: , + icon: , }, { title: "Full visibility", description: "Inspect tool calls, context, and agent actions in real time", - icon: , + icon: , }, { title: "Direct control", description: "Permissions, schedules, and execution from one interface", - icon: , + icon: , + }, + { + title: "Live notifications", + description: "Cron jobs notifications", + icon: , }, { title: "Elegant interface", description: "Built for clarity with responsive layouts and themes", - icon: , + icon: , }, ]; diff --git a/docs/app/(home)/sections/HeroSection/HeroSection.tsx b/docs/app/(home)/sections/HeroSection/HeroSection.tsx index 7bfd87232..2c0cc26a9 100644 --- a/docs/app/(home)/sections/HeroSection/HeroSection.tsx +++ b/docs/app/(home)/sections/HeroSection/HeroSection.tsx @@ -116,6 +116,30 @@ function MobilePlaygroundButton({ className = "" }: { className?: string }) { ); } +function DesktopGithubButton({ + href, + label = "Star on GitHub", + className = "", +}: { + href: string; + label?: string; + className?: string; +}) { + return ( + } + > + + {label} + + ); +} + function AnnouncementBanner({ className = "" }: { className?: string }) { return ( <> @@ -150,10 +174,18 @@ function AnnouncementBanner({ className = "" }: { className?: string }) { ); } -function GitHubBanner({ className = "" }: { className?: string }) { +function GitHubBanner({ + href = "https://github.com/thesysdev/openui", + label = "Star us on Github", + className = "", +}: { + href?: string; + label?: string; + className?: string; +}) { return ( @@ -180,6 +212,8 @@ function DesktopHero({ compact, showBanner, showPlaygroundButton, + githubRepoUrl, + githubButtonLabel, }: { title: ReactNode; subtitle: ReactNode; @@ -187,7 +221,13 @@ function DesktopHero({ compact: boolean; showBanner: boolean; showPlaygroundButton: boolean; + githubRepoUrl?: string; + githubButtonLabel?: string; }) { + // The shadow-room class compensates for the absent secondary CTA — only + // applied when both the playground button AND the GitHub button are off. + const hasSecondaryCta = showPlaygroundButton || !!githubRepoUrl; + return (
@@ -203,11 +243,14 @@ function DesktopHero({
{showPlaygroundButton && } + {githubRepoUrl && ( + + )}
@@ -227,6 +270,7 @@ function MobileHero({ showBanner, showPlaygroundButton, showGitHubBanner, + githubRepoUrl, mobileImageOverride, mobileImageAlt, mobileImageWidth, @@ -241,6 +285,7 @@ function MobileHero({ showBanner: boolean; showPlaygroundButton: boolean; showGitHubBanner: boolean; + githubRepoUrl?: string; mobileImageOverride?: string; mobileImageAlt?: string; mobileImageWidth?: number; @@ -282,7 +327,9 @@ function MobileHero({
{showPlaygroundButton && } - {showGitHubBanner && } + {showGitHubBanner && ( + + )}
{/* Mobile hero image */} @@ -391,6 +438,8 @@ export function HeroSection({ tagline, taglineCompact = false, showGitHubBanner = true, + githubRepoUrl, + githubButtonLabel, mobilePreviewImage, mobilePreviewImageAlt, mobilePreviewImageWidth, @@ -412,6 +461,12 @@ export function HeroSection({ tagline?: ReactNode; taglineCompact?: boolean; showGitHubBanner?: boolean; + /** When set, adds a desktop GitHub PillLink CTA pointing here AND uses + * this URL for the mobile GitHub banner (instead of the default openui + * repo). Useful for sub-product pages like /openclaw-os. */ + githubRepoUrl?: string; + /** Optional override for the desktop GitHub button label (default: "Star on GitHub"). */ + githubButtonLabel?: string; mobilePreviewImage?: string; mobilePreviewImageAlt?: string; mobilePreviewImageWidth?: number; @@ -429,6 +484,8 @@ export function HeroSection({ compact={compact} showBanner={showBanner} showPlaygroundButton={showPlaygroundButton} + githubRepoUrl={githubRepoUrl} + githubButtonLabel={githubButtonLabel} /> &1 | Out-Null + if ($LASTEXITCODE -eq 0) { + # The openclaw CLI emits plugin-registration logs to stdout when loading a + # plugin to discover its commands; grep just the URL line. + $output = (& openclaw os url 2>$null | Out-String) + if ($output) { + $match = [regex]::Match($output, 'https?://[^\s]+') + if ($match.Success) { $url = $match.Value } + } + } + + if (-not $url) { + Write-Warn2 '`openclaw os url` not available — older plugin or missing token.' + Write-Log "Open http://127.0.0.1:18789/plugins/$PluginPathSlug and paste the token from $OpenclawConfig." + return + } + + Write-Host "" + Write-Host " Dashboard URL: " -NoNewline + Write-Host $url -ForegroundColor Cyan + Write-Host "" + + try { + Set-Clipboard -Value $url -ErrorAction Stop + Write-Log 'Copied to clipboard.' + } catch { + # Set-Clipboard missing on PS 5.0; ignore — URL was printed above. + } + + try { + Start-Process $url -ErrorAction Stop + Write-Ok 'Opened in your browser. Keep that tab to use OpenClaw OS.' + } catch { + Write-Log 'Open the URL above to use OpenClaw OS.' + } +} + function Do-Install { Banner Check-Prereqs @@ -245,8 +290,7 @@ function Do-Install { Verify Write-Host "" Write-Host "✓ OpenClaw OS installed." -ForegroundColor Cyan - Write-Host " Open the Claw UI from your OpenClaw client to start generating apps." -ForegroundColor DarkGray - Write-Host "" + Print-DashboardUrl } function Do-Uninstall { diff --git a/docs/public/openclaw-os/install.sh b/docs/public/openclaw-os/install.sh index 151dfccea..da10d45c6 100755 --- a/docs/public/openclaw-os/install.sh +++ b/docs/public/openclaw-os/install.sh @@ -13,6 +13,7 @@ REPO="thesysdev/openclaw-os" SRC_DIR="$HOME/.openclaw/openui/openclaw-os" PLUGIN_DIR="$SRC_DIR/packages/claw-plugin" PLUGIN_ID="openclaw-os-plugin" +PLUGIN_PATH_SLUG="openclawos" OPENCLAW_CONFIG="$HOME/.openclaw/openclaw.json" BOLD='\033[1m' @@ -34,7 +35,7 @@ require_cmd() { } banner() { - printf "\n${BOLD}${ACCENT}OpenClaw OS${NC} ${INFO}— Generative UI for OpenClaw${NC}\n\n" + printf "\n${BOLD}${ACCENT}OpenClaw OS${NC} ${INFO}— The default workspace for OpenClaw${NC}\n\n" } check_prereqs() { @@ -170,6 +171,53 @@ verify() { fi } +print_dashboard_url() { + step "Opening OpenClaw OS" + + # The plugin (via `api.registerCli`) constructs the auth-bearing URL from the + # gateway-validated config — survives `--dev`/`--profile`, no JSON parsing. + # Clipboard + browser open stay in shell so the plugin doesn't need + # `child_process` (would trip openclaw's install security scan). + local url="" + if openclaw os --help >/dev/null 2>&1; then + # The openclaw CLI emits plugin-registration logs to stdout when loading a + # plugin to discover its commands. The action runs *after* registration, so + # the URL is the last http-shaped line. `tail -n1` is more robust than + # `head -1` against future log lines that happen to contain URLs. + url="$(openclaw os url 2>/dev/null | grep -Eo 'https?://[^[:space:]]+' | tail -n1 || true)" + fi + + if [[ -z "$url" ]]; then + warn "\`openclaw os url\` not available — older plugin or missing token." + log "Open http://127.0.0.1:18789/plugins/$PLUGIN_PATH_SLUG and paste the token from $OPENCLAW_CONFIG." + return + fi + + printf "\n ${BOLD}Dashboard URL:${NC} %s\n\n" "$url" + + case "$(uname -s)" in + Darwin) + command -v pbcopy >/dev/null 2>&1 && printf '%s' "$url" | pbcopy 2>/dev/null && log "Copied to clipboard." + open "$url" >/dev/null 2>&1 && ok "Opened in your browser. Keep that tab to use OpenClaw OS." \ + || log "Open the URL above to use OpenClaw OS." + ;; + Linux) + if command -v wl-copy >/dev/null 2>&1; then printf '%s' "$url" | wl-copy 2>/dev/null && log "Copied to clipboard." + elif command -v xclip >/dev/null 2>&1; then printf '%s' "$url" | xclip -selection clipboard 2>/dev/null && log "Copied to clipboard." + fi + if command -v xdg-open >/dev/null 2>&1; then + xdg-open "$url" >/dev/null 2>&1 && ok "Opened in your browser. Keep that tab to use OpenClaw OS." \ + || log "Open the URL above to use OpenClaw OS." + else + log "Open the URL above to use OpenClaw OS." + fi + ;; + *) + log "Open the URL above to use OpenClaw OS." + ;; + esac +} + uninstall_plugin() { step "Disabling $PLUGIN_ID" if openclaw plugins disable "$PLUGIN_ID" 2>&1; then @@ -179,7 +227,8 @@ uninstall_plugin() { fi step "Uninstalling $PLUGIN_ID" - if openclaw plugins uninstall "$PLUGIN_ID" 2>&1; then + # --force skips the interactive y/N prompt (no TTY in `curl | bash`). + if openclaw plugins uninstall "$PLUGIN_ID" --force 2>&1; then ok "Plugin uninstalled" else warn "Could not uninstall plugin (may not be registered). Continuing." @@ -217,7 +266,7 @@ do_install() { verify printf "\n${SUCCESS}${BOLD}✓ OpenClaw OS installed.${NC}\n" - printf "${INFO} Open the Claw UI from your OpenClaw client to start generating apps.${NC}\n\n" + print_dashboard_url } do_uninstall() {