@nicotinetool/o7-cli 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/bin/o7 +244 -0
- package/bin/o7-doctor +379 -0
- package/bin/o7-setup +143 -0
- package/bin/o7-setup.js +143 -0
- package/bin/o7.js +244 -0
- package/installer/com.unified-mc.plist.tmpl +35 -0
- package/installer/install.sh +297 -0
- package/installer/lib/antigravity-standalone.sh +301 -0
- package/installer/lib/antigravity.sh +140 -0
- package/installer/lib/auth.sh +286 -0
- package/installer/lib/checks.sh +177 -0
- package/installer/lib/ui.sh +120 -0
- package/installer/lib/validate.sh +87 -0
- package/installer/onboard.mjs +966 -0
- package/installer/templates/agents.md.tmpl +34 -0
- package/installer/templates/heartbeat.md.tmpl +63 -0
- package/installer/templates/openclaw.json.tmpl +116 -0
- package/installer/templates/soul.md.tmpl +45 -0
- package/installer/templates/user.md.tmpl +25 -0
- package/package.json +25 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# O7 OpenClaw Installer — UI Helpers
|
|
3
|
+
|
|
4
|
+
# Colors (degrade gracefully)
|
|
5
|
+
if [[ -t 1 ]] && tput colors &>/dev/null && [[ $(tput colors) -ge 8 ]]; then
|
|
6
|
+
RED='\033[0;31m'
|
|
7
|
+
GREEN='\033[0;32m'
|
|
8
|
+
YELLOW='\033[1;33m'
|
|
9
|
+
BLUE='\033[0;34m'
|
|
10
|
+
PURPLE='\033[0;35m'
|
|
11
|
+
CYAN='\033[0;36m'
|
|
12
|
+
WHITE='\033[1;37m'
|
|
13
|
+
DIM='\033[2m'
|
|
14
|
+
BOLD='\033[1m'
|
|
15
|
+
RESET='\033[0m'
|
|
16
|
+
else
|
|
17
|
+
RED='' GREEN='' YELLOW='' BLUE='' PURPLE='' CYAN='' WHITE='' DIM='' BOLD='' RESET=''
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Status indicators
|
|
21
|
+
ok() { echo -e "${GREEN}✅ $*${RESET}"; }
|
|
22
|
+
warn() { echo -e "${YELLOW}⚠️ $*${RESET}"; }
|
|
23
|
+
fail() { echo -e "${RED}❌ $*${RESET}"; }
|
|
24
|
+
info() { echo -e "${CYAN}ℹ️ $*${RESET}"; }
|
|
25
|
+
step() { echo -e "\n${BOLD}${PURPLE}▶ $*${RESET}"; }
|
|
26
|
+
detail(){ echo -e " ${DIM}$*${RESET}"; }
|
|
27
|
+
|
|
28
|
+
# Progress spinner
|
|
29
|
+
spin() {
|
|
30
|
+
local pid=$1 msg=$2
|
|
31
|
+
local chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
|
32
|
+
local i=0
|
|
33
|
+
while kill -0 "$pid" 2>/dev/null; do
|
|
34
|
+
printf "\r ${CYAN}%s${RESET} %s" "${chars:i%${#chars}:1}" "$msg"
|
|
35
|
+
i=$((i + 1))
|
|
36
|
+
sleep 0.1
|
|
37
|
+
done
|
|
38
|
+
printf "\r"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Ask yes/no (default yes)
|
|
42
|
+
confirm() {
|
|
43
|
+
local prompt="${1:-Continue?}"
|
|
44
|
+
echo -en "${BOLD}${prompt}${RESET} [Y/n] "
|
|
45
|
+
read -r answer
|
|
46
|
+
[[ -z "$answer" || "$answer" =~ ^[Yy] ]]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Ask for input
|
|
50
|
+
ask() {
|
|
51
|
+
local prompt="$1" var="$2" secret="${3:-false}"
|
|
52
|
+
echo -en "${BOLD}${prompt}${RESET} "
|
|
53
|
+
if [[ "$secret" == "true" ]]; then
|
|
54
|
+
read -rs "$var"
|
|
55
|
+
echo
|
|
56
|
+
else
|
|
57
|
+
read -r "$var"
|
|
58
|
+
fi
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Section banner
|
|
62
|
+
section() {
|
|
63
|
+
local num="$1" title="$2"
|
|
64
|
+
echo -e "\n${BOLD}${WHITE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
|
|
65
|
+
echo -e "${BOLD}${CYAN} Phase ${num}: ${title}${RESET}"
|
|
66
|
+
echo -e "${BOLD}${WHITE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Welcome banner
|
|
70
|
+
banner() {
|
|
71
|
+
echo -e "${BOLD}${CYAN}"
|
|
72
|
+
cat << 'BANNER'
|
|
73
|
+
|
|
74
|
+
___ ______ ___ ____ _
|
|
75
|
+
/ _ \|___ / / _ \ _ __ ___ _ __ / ___| | __ ___ __
|
|
76
|
+
| | | | / / | | | | '_ \ / _ \ '_ \ | | |/ _` \ \ /\ / /
|
|
77
|
+
| |_| | / / | |_| | |_) | __/ | | | |___| | (_| |\ V V /
|
|
78
|
+
\___/ /_/ \___/| .__/ \___|_| |_|\____|_|\__,_| \_/\_/
|
|
79
|
+
|_|
|
|
80
|
+
|
|
81
|
+
BANNER
|
|
82
|
+
echo -e "${RESET}"
|
|
83
|
+
echo -e "${DIM} One-click AI assistant setup for your Mac${RESET}"
|
|
84
|
+
echo -e "${DIM} Optimum7 — AI-Powered E-Commerce${RESET}"
|
|
85
|
+
echo
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Menu selector
|
|
89
|
+
menu() {
|
|
90
|
+
local prompt="$1"
|
|
91
|
+
shift
|
|
92
|
+
local options=("$@")
|
|
93
|
+
echo -e "${BOLD}${prompt}${RESET}"
|
|
94
|
+
for i in "${!options[@]}"; do
|
|
95
|
+
echo -e " ${CYAN}$((i + 1)))${RESET} ${options[$i]}"
|
|
96
|
+
done
|
|
97
|
+
local choice
|
|
98
|
+
while true; do
|
|
99
|
+
echo -en "${BOLD} Select [1-${#options[@]}]: ${RESET}"
|
|
100
|
+
read -r choice
|
|
101
|
+
if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#options[@]} )); then
|
|
102
|
+
echo "$((choice - 1))"
|
|
103
|
+
return
|
|
104
|
+
fi
|
|
105
|
+
echo -e "${RED} Invalid choice. Try again.${RESET}"
|
|
106
|
+
done
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# Summary table row
|
|
110
|
+
summary_row() {
|
|
111
|
+
local label="$1" status="$2"
|
|
112
|
+
printf " %-30s %s\n" "$label" "$status"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Installer log
|
|
116
|
+
INSTALL_LOG="${HOME}/.openclaw/install.log"
|
|
117
|
+
mkdir -p "$(dirname "$INSTALL_LOG")"
|
|
118
|
+
log() {
|
|
119
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$INSTALL_LOG"
|
|
120
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# O7 OpenClaw Installer — Provider Validation
|
|
3
|
+
|
|
4
|
+
# Test a model via openclaw agent --message (quick ping)
|
|
5
|
+
# Returns 0 on success, 1 on failure with diagnosis
|
|
6
|
+
validate_provider() {
|
|
7
|
+
local provider="$1" display_name="$2"
|
|
8
|
+
info "Testing ${display_name}..."
|
|
9
|
+
|
|
10
|
+
local output exit_code
|
|
11
|
+
output=$(timeout 30 openclaw agent --message "Reply with exactly: OK" --model "${provider}" --max-tokens 10 2>&1)
|
|
12
|
+
exit_code=$?
|
|
13
|
+
|
|
14
|
+
if (( exit_code == 0 )) && echo "$output" | grep -qi "ok"; then
|
|
15
|
+
ok "${display_name} is working"
|
|
16
|
+
log "VALIDATE OK: ${provider}"
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Diagnose the error
|
|
21
|
+
if echo "$output" | grep -qi "401\|unauthorized\|invalid.*key\|invalid.*token"; then
|
|
22
|
+
fail "${display_name}: Authentication failed (invalid or expired token)"
|
|
23
|
+
info "Your token/key seems wrong. Let's set it up again."
|
|
24
|
+
log "VALIDATE FAIL: ${provider} — 401 unauthorized"
|
|
25
|
+
return 1
|
|
26
|
+
elif echo "$output" | grep -qi "403\|forbidden\|access.*denied"; then
|
|
27
|
+
fail "${display_name}: Access denied (your account may not have access to this model)"
|
|
28
|
+
info "Check your subscription or plan at the provider's dashboard."
|
|
29
|
+
log "VALIDATE FAIL: ${provider} — 403 forbidden"
|
|
30
|
+
return 1
|
|
31
|
+
elif echo "$output" | grep -qi "429\|rate.*limit\|too.*many"; then
|
|
32
|
+
warn "${display_name}: Rate limited (but auth is working — you're good)"
|
|
33
|
+
log "VALIDATE WARN: ${provider} — 429 rate limited but auth OK"
|
|
34
|
+
return 0 # Rate limit = auth works
|
|
35
|
+
elif echo "$output" | grep -qi "timeout\|ETIMEDOUT\|ECONNREFUSED\|network"; then
|
|
36
|
+
fail "${display_name}: Network error (can't reach the API)"
|
|
37
|
+
info "Check your internet connection. If on VPN, try disconnecting."
|
|
38
|
+
log "VALIDATE FAIL: ${provider} — network error"
|
|
39
|
+
return 1
|
|
40
|
+
elif echo "$output" | grep -qi "not.*found\|no.*profile\|no.*auth"; then
|
|
41
|
+
fail "${display_name}: Not configured (no auth profile found)"
|
|
42
|
+
log "VALIDATE FAIL: ${provider} — no auth profile"
|
|
43
|
+
return 1
|
|
44
|
+
else
|
|
45
|
+
warn "${display_name}: Got a response but couldn't verify it's working correctly"
|
|
46
|
+
detail "Output: $(echo "$output" | head -3)"
|
|
47
|
+
log "VALIDATE UNCLEAR: ${provider} — $output"
|
|
48
|
+
return 0 # Assume OK if we got any response
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Validate with retry loop
|
|
53
|
+
validate_with_retry() {
|
|
54
|
+
local provider="$1" display_name="$2" setup_fn="$3"
|
|
55
|
+
local max_retries=3 attempt=1
|
|
56
|
+
|
|
57
|
+
while (( attempt <= max_retries )); do
|
|
58
|
+
if validate_provider "$provider" "$display_name"; then
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if (( attempt < max_retries )); then
|
|
63
|
+
echo
|
|
64
|
+
if confirm "Try setting up ${display_name} again? (attempt $((attempt+1))/${max_retries})"; then
|
|
65
|
+
$setup_fn
|
|
66
|
+
else
|
|
67
|
+
return 1
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
((attempt++))
|
|
71
|
+
done
|
|
72
|
+
|
|
73
|
+
fail "Could not validate ${display_name} after ${max_retries} attempts."
|
|
74
|
+
return 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Quick connectivity check
|
|
78
|
+
check_internet() {
|
|
79
|
+
if ! curl -s --max-time 5 https://api.anthropic.com >/dev/null 2>&1; then
|
|
80
|
+
if ! curl -s --max-time 5 https://www.google.com >/dev/null 2>&1; then
|
|
81
|
+
fail "No internet connection detected!"
|
|
82
|
+
info "Check your Wi-Fi or Ethernet connection and try again."
|
|
83
|
+
return 1
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
return 0
|
|
87
|
+
}
|