openclacky 0.9.12 → 0.9.13
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/clacky/brand_config.rb +24 -5
- data/lib/clacky/cli.rb +20 -8
- data/lib/clacky/server/channel/adapters/feishu/ws_client.rb +43 -33
- data/lib/clacky/server/channel/adapters/wecom/ws_client.rb +41 -34
- data/lib/clacky/server/http_server.rb +74 -46
- data/lib/clacky/ui2/ui_controller.rb +3 -0
- data/lib/clacky/utils/parser_manager.rb +4 -1
- data/lib/clacky/version.rb +1 -1
- data/scripts/install.sh +493 -184
- data/scripts/install_simple.sh +582 -0
- metadata +36 -13
- data/scripts/install_original.sh +0 -891
data/scripts/install.sh
CHANGED
|
@@ -15,6 +15,7 @@ YELLOW='\033[1;33m'
|
|
|
15
15
|
BLUE='\033[0;34m'
|
|
16
16
|
NC='\033[0m' # No Color
|
|
17
17
|
|
|
18
|
+
# Print colored messages
|
|
18
19
|
print_info() {
|
|
19
20
|
echo -e "${BLUE}ℹ${NC} $1"
|
|
20
21
|
}
|
|
@@ -46,6 +47,7 @@ detect_os() {
|
|
|
46
47
|
esac
|
|
47
48
|
print_info "Detected OS: $OS"
|
|
48
49
|
|
|
50
|
+
# Detect Linux distribution
|
|
49
51
|
if [ "$OS" = "Linux" ]; then
|
|
50
52
|
if [ -f /etc/os-release ]; then
|
|
51
53
|
. /etc/os-release
|
|
@@ -62,7 +64,8 @@ command_exists() {
|
|
|
62
64
|
command -v "$1" >/dev/null 2>&1
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
# Detect current shell type
|
|
67
|
+
# Detect current shell type based on $SHELL environment variable
|
|
68
|
+
# Sets CURRENT_SHELL (e.g. "zsh", "bash", "fish") and SHELL_RC (rc file path)
|
|
66
69
|
detect_shell() {
|
|
67
70
|
local shell_name
|
|
68
71
|
shell_name=$(basename "$SHELL")
|
|
@@ -74,6 +77,7 @@ detect_shell() {
|
|
|
74
77
|
;;
|
|
75
78
|
bash)
|
|
76
79
|
CURRENT_SHELL="bash"
|
|
80
|
+
# macOS uses ~/.bash_profile; Linux uses ~/.bashrc
|
|
77
81
|
if [ "$OS" = "macOS" ]; then
|
|
78
82
|
SHELL_RC="$HOME/.bash_profile"
|
|
79
83
|
else
|
|
@@ -85,6 +89,7 @@ detect_shell() {
|
|
|
85
89
|
SHELL_RC="$HOME/.config/fish/config.fish"
|
|
86
90
|
;;
|
|
87
91
|
*)
|
|
92
|
+
# Fallback: treat as bash
|
|
88
93
|
CURRENT_SHELL="bash"
|
|
89
94
|
SHELL_RC="$HOME/.bashrc"
|
|
90
95
|
;;
|
|
@@ -93,27 +98,43 @@ detect_shell() {
|
|
|
93
98
|
print_info "Detected shell: $CURRENT_SHELL (rc file: $SHELL_RC)"
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
#
|
|
97
|
-
# Network region detection & mirror selection
|
|
98
|
-
# --------------------------------------------------------------------------
|
|
101
|
+
# Network-aware installer source selection
|
|
99
102
|
SLOW_THRESHOLD_MS=5000
|
|
100
|
-
NETWORK_REGION="global"
|
|
103
|
+
NETWORK_REGION="global" # "china" | "global" | "unknown"
|
|
101
104
|
USE_CN_MIRRORS=false
|
|
102
105
|
|
|
106
|
+
# --- Upstream (global) defaults ---
|
|
103
107
|
GITHUB_RAW_BASE_URL="https://raw.githubusercontent.com"
|
|
108
|
+
HOMEBREW_INSTALL_SCRIPT_URL="${GITHUB_RAW_BASE_URL}/Homebrew/install/HEAD/install.sh"
|
|
109
|
+
OPENCLACKY_INSTALL_SCRIPT_URL="${GITHUB_RAW_BASE_URL}/clacky-ai/openclacky/main/scripts/install.sh"
|
|
104
110
|
DEFAULT_RUBYGEMS_URL="https://rubygems.org"
|
|
111
|
+
DEFAULT_NPM_REGISTRY="https://registry.npmjs.org"
|
|
105
112
|
DEFAULT_MISE_INSTALL_URL="https://mise.run"
|
|
106
113
|
|
|
107
|
-
CN_CDN_BASE_URL="https://oss.1024code.com"
|
|
114
|
+
CN_CDN_BASE_URL="https://oss.1024code.com" # reverse proxy for raw.githubusercontent.com
|
|
115
|
+
|
|
116
|
+
# --- CN source URLs ---
|
|
117
|
+
CN_HOMEBREW_INSTALL_SCRIPT_URL="${CN_CDN_BASE_URL}/Homebrew/install/HEAD/install.sh"
|
|
108
118
|
CN_MISE_INSTALL_URL="${CN_CDN_BASE_URL}/mise.sh"
|
|
109
119
|
CN_RUBY_PRECOMPILED_URL="${CN_CDN_BASE_URL}/ruby/ruby-{version}.{platform}.tar.gz"
|
|
110
120
|
CN_RUBYGEMS_URL="https://mirrors.aliyun.com/rubygems/"
|
|
121
|
+
CN_NPM_REGISTRY="https://registry.npmmirror.com"
|
|
122
|
+
CN_NODE_MIRROR_URL="https://cdn.npmmirror.com/binaries/node/"
|
|
123
|
+
|
|
124
|
+
# --- Homebrew CN mirrors (Aliyun) ---
|
|
125
|
+
CN_HOMEBREW_BREW_GIT_REMOTE="https://mirrors.aliyun.com/homebrew/brew.git"
|
|
126
|
+
CN_HOMEBREW_CORE_GIT_REMOTE="https://mirrors.aliyun.com/homebrew/homebrew-core.git"
|
|
127
|
+
CN_HOMEBREW_BOTTLE_DOMAIN="https://mirrors.aliyun.com/homebrew/homebrew-bottles"
|
|
128
|
+
CN_HOMEBREW_API_DOMAIN="https://mirrors.aliyun.com/homebrew-bottles/api"
|
|
111
129
|
|
|
112
|
-
# Active values (overridden by detect_network_region)
|
|
130
|
+
# --- Active values (overridden by detect_network_region) ---
|
|
113
131
|
MISE_INSTALL_URL="$DEFAULT_MISE_INSTALL_URL"
|
|
114
132
|
RUBYGEMS_INSTALL_URL="$DEFAULT_RUBYGEMS_URL"
|
|
115
|
-
|
|
133
|
+
NPM_REGISTRY_URL="$DEFAULT_NPM_REGISTRY"
|
|
134
|
+
NODE_MIRROR_URL="" # empty = mise default (nodejs.org)
|
|
135
|
+
RUBY_VERSION_SPEC="ruby@3"
|
|
116
136
|
|
|
137
|
+
# Probe a single URL; echoes the round-trip time in milliseconds, or "timeout".
|
|
117
138
|
_probe_url() {
|
|
118
139
|
local url="$1"
|
|
119
140
|
local timeout_sec=5
|
|
@@ -134,16 +155,25 @@ _probe_url() {
|
|
|
134
155
|
fi
|
|
135
156
|
}
|
|
136
157
|
|
|
158
|
+
_is_timed_result() {
|
|
159
|
+
local result="$1"
|
|
160
|
+
|
|
161
|
+
[ -n "$result" ] && [ "$result" != "timeout" ] && [ "$result" -ge 0 ] 2>/dev/null
|
|
162
|
+
}
|
|
163
|
+
|
|
137
164
|
_is_slow_or_unreachable() {
|
|
138
165
|
local result="$1"
|
|
166
|
+
|
|
139
167
|
if [ "$result" = "timeout" ]; then
|
|
140
168
|
return 0
|
|
141
169
|
fi
|
|
170
|
+
|
|
142
171
|
[ "$result" -ge "$SLOW_THRESHOLD_MS" ] 2>/dev/null
|
|
143
172
|
}
|
|
144
173
|
|
|
145
174
|
_format_probe_time() {
|
|
146
175
|
local result="$1"
|
|
176
|
+
|
|
147
177
|
if [ "$result" = "timeout" ]; then
|
|
148
178
|
echo "timeout"
|
|
149
179
|
else
|
|
@@ -156,7 +186,7 @@ _print_probe_result() {
|
|
|
156
186
|
local result="$2"
|
|
157
187
|
|
|
158
188
|
if [ "$result" = "timeout" ]; then
|
|
159
|
-
print_warning "UNREACHABLE ${label}"
|
|
189
|
+
print_warning "UNREACHABLE (${result}) ${label}"
|
|
160
190
|
elif _is_slow_or_unreachable "$result"; then
|
|
161
191
|
print_warning "SLOW ($(_format_probe_time "$result")) ${label}"
|
|
162
192
|
else
|
|
@@ -164,17 +194,19 @@ _print_probe_result() {
|
|
|
164
194
|
fi
|
|
165
195
|
}
|
|
166
196
|
|
|
197
|
+
# Probe a URL up to MAX_RETRIES times; returns the first successful ms or "timeout".
|
|
167
198
|
_probe_url_with_retry() {
|
|
168
199
|
local url="$1"
|
|
169
200
|
local max_retries="${2:-2}"
|
|
170
|
-
local result
|
|
201
|
+
local attempt result
|
|
171
202
|
|
|
172
|
-
for
|
|
203
|
+
for attempt in $(seq 1 "$max_retries"); do
|
|
173
204
|
result=$(_probe_url "$url")
|
|
174
|
-
if ! _is_slow_or_unreachable "$result"; then
|
|
205
|
+
if [ "$result" != "timeout" ] && ! _is_slow_or_unreachable "$result"; then
|
|
175
206
|
echo "$result"
|
|
176
207
|
return 0
|
|
177
208
|
fi
|
|
209
|
+
# keep last result for reporting
|
|
178
210
|
done
|
|
179
211
|
echo "$result"
|
|
180
212
|
}
|
|
@@ -183,7 +215,13 @@ detect_network_region() {
|
|
|
183
215
|
print_step "Network pre-flight check..."
|
|
184
216
|
echo ""
|
|
185
217
|
|
|
186
|
-
|
|
218
|
+
# -----------------------------------------------------------------------
|
|
219
|
+
# Step 1: Region detection — google.com vs baidu.com
|
|
220
|
+
# google reachable → global
|
|
221
|
+
# google unreachable + baidu reachable → china
|
|
222
|
+
# both unreachable → unknown (best-effort, fall through)
|
|
223
|
+
# -----------------------------------------------------------------------
|
|
224
|
+
print_info "Step 1: Detecting network region..."
|
|
187
225
|
local google_result baidu_result
|
|
188
226
|
google_result=$(_probe_url "https://www.google.com")
|
|
189
227
|
baidu_result=$(_probe_url "https://www.baidu.com")
|
|
@@ -197,107 +235,271 @@ detect_network_region() {
|
|
|
197
235
|
|
|
198
236
|
if [ "$google_ok" = true ]; then
|
|
199
237
|
NETWORK_REGION="global"
|
|
200
|
-
print_success "Region: global"
|
|
238
|
+
print_success "Region: global (Google reachable)"
|
|
201
239
|
elif [ "$baidu_ok" = true ]; then
|
|
202
240
|
NETWORK_REGION="china"
|
|
203
|
-
print_success "Region: china"
|
|
241
|
+
print_success "Region: china (Baidu reachable, Google not)"
|
|
204
242
|
else
|
|
205
243
|
NETWORK_REGION="unknown"
|
|
206
|
-
print_warning "Region: unknown (both unreachable)"
|
|
244
|
+
print_warning "Region: unknown (both Google and Baidu unreachable)"
|
|
207
245
|
fi
|
|
208
246
|
echo ""
|
|
209
247
|
|
|
248
|
+
# -----------------------------------------------------------------------
|
|
249
|
+
# Step 2: Probe region-specific sources (retry 2× to avoid false alarms)
|
|
250
|
+
# -----------------------------------------------------------------------
|
|
251
|
+
print_info "Step 2: Probing installation sources (up to 2 retries each)..."
|
|
252
|
+
|
|
210
253
|
if [ "$NETWORK_REGION" = "china" ]; then
|
|
254
|
+
# CN sources: CDN (oss.1024code.com) + Aliyun + npmmirror
|
|
211
255
|
local cdn_result mirror_result
|
|
212
256
|
cdn_result=$(_probe_url_with_retry "$CN_MISE_INSTALL_URL")
|
|
213
257
|
mirror_result=$(_probe_url_with_retry "$CN_RUBYGEMS_URL")
|
|
214
258
|
|
|
215
|
-
_print_probe_result "
|
|
216
|
-
_print_probe_result "
|
|
259
|
+
_print_probe_result "Chinese CDN (mise/Ruby)" "$cdn_result"
|
|
260
|
+
_print_probe_result "CN mirror (gem/brew)" "$mirror_result"
|
|
217
261
|
|
|
218
262
|
local cdn_ok=false mirror_ok=false
|
|
219
263
|
! _is_slow_or_unreachable "$cdn_result" && cdn_ok=true
|
|
220
264
|
! _is_slow_or_unreachable "$mirror_result" && mirror_ok=true
|
|
221
265
|
|
|
266
|
+
# Step 3: warn on source failures, but do not abort
|
|
267
|
+
if [ "$cdn_ok" = false ]; then
|
|
268
|
+
print_warning "Chinese CDN is slow/unreachable. mise and Ruby precompiled binaries may fail."
|
|
269
|
+
fi
|
|
270
|
+
if [ "$mirror_ok" = false ]; then
|
|
271
|
+
print_warning "Aliyun mirror is slow/unreachable. gem/brew installs may be slow."
|
|
272
|
+
fi
|
|
273
|
+
if [ "$cdn_ok" = false ] && [ "$mirror_ok" = false ]; then
|
|
274
|
+
print_warning "All CN mirrors unreachable — falling back to global sources. Expect slow downloads."
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
# Step 4: apply CN sources
|
|
222
278
|
if [ "$cdn_ok" = true ] || [ "$mirror_ok" = true ]; then
|
|
223
279
|
USE_CN_MIRRORS=true
|
|
224
280
|
MISE_INSTALL_URL="$CN_MISE_INSTALL_URL"
|
|
225
281
|
RUBYGEMS_INSTALL_URL="$CN_RUBYGEMS_URL"
|
|
282
|
+
NPM_REGISTRY_URL="$CN_NPM_REGISTRY"
|
|
283
|
+
NODE_MIRROR_URL="$CN_NODE_MIRROR_URL"
|
|
226
284
|
RUBY_VERSION_SPEC="ruby@3.4.8"
|
|
227
|
-
print_info "CN mirrors applied
|
|
285
|
+
print_info "CN mirrors applied: CDN (mise/Ruby) + Aliyun (gem/brew) + npmmirror (npm/Node)"
|
|
228
286
|
else
|
|
229
|
-
|
|
287
|
+
USE_CN_MIRRORS=false
|
|
288
|
+
print_info "Falling back to global sources despite CN region detection."
|
|
230
289
|
fi
|
|
290
|
+
|
|
231
291
|
else
|
|
232
|
-
|
|
292
|
+
# Global sources: GitHub / RubyGems / npmjs / mise.run
|
|
293
|
+
local github_result rubygems_result npm_result mise_result
|
|
294
|
+
github_result=$(_probe_url_with_retry "$GITHUB_RAW_BASE_URL")
|
|
233
295
|
rubygems_result=$(_probe_url_with_retry "$DEFAULT_RUBYGEMS_URL")
|
|
296
|
+
npm_result=$(_probe_url_with_retry "$DEFAULT_NPM_REGISTRY")
|
|
234
297
|
mise_result=$(_probe_url_with_retry "$DEFAULT_MISE_INSTALL_URL")
|
|
235
298
|
|
|
236
|
-
_print_probe_result "
|
|
237
|
-
_print_probe_result "
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
299
|
+
_print_probe_result "GitHub raw" "$github_result"
|
|
300
|
+
_print_probe_result "RubyGems" "$rubygems_result"
|
|
301
|
+
_print_probe_result "npmjs.com" "$npm_result"
|
|
302
|
+
_print_probe_result "mise.run" "$mise_result"
|
|
303
|
+
|
|
304
|
+
# Step 3: warn on individual source failures
|
|
305
|
+
_is_slow_or_unreachable "$github_result" && print_warning "GitHub is slow/unreachable. Homebrew and install script updates may fail."
|
|
306
|
+
_is_slow_or_unreachable "$rubygems_result" && print_warning "RubyGems is slow/unreachable. gem install may fail."
|
|
307
|
+
_is_slow_or_unreachable "$npm_result" && print_warning "npmjs.com is slow/unreachable. npm install may fail."
|
|
308
|
+
_is_slow_or_unreachable "$mise_result" && print_warning "mise.run is slow/unreachable. mise installation may fail."
|
|
309
|
+
|
|
310
|
+
USE_CN_MIRRORS=false
|
|
311
|
+
MISE_INSTALL_URL="$DEFAULT_MISE_INSTALL_URL"
|
|
312
|
+
RUBYGEMS_INSTALL_URL="$DEFAULT_RUBYGEMS_URL"
|
|
313
|
+
NPM_REGISTRY_URL="$DEFAULT_NPM_REGISTRY"
|
|
314
|
+
NODE_MIRROR_URL=""
|
|
315
|
+
RUBY_VERSION_SPEC="ruby@3"
|
|
316
|
+
print_info "Using global upstream sources."
|
|
241
317
|
fi
|
|
242
318
|
|
|
243
319
|
echo ""
|
|
244
320
|
}
|
|
245
321
|
|
|
246
|
-
|
|
247
|
-
#
|
|
248
|
-
# --------------------------------------------------------------------------
|
|
322
|
+
|
|
323
|
+
# Compare version strings
|
|
249
324
|
version_ge() {
|
|
325
|
+
# Returns 0 (true) if $1 >= $2
|
|
250
326
|
printf '%s\n%s\n' "$2" "$1" | sort -V -C
|
|
251
327
|
}
|
|
252
328
|
|
|
253
|
-
#
|
|
254
|
-
# Ruby check (>= 2.6.0)
|
|
255
|
-
# --------------------------------------------------------------------------
|
|
329
|
+
# Check Ruby version
|
|
256
330
|
check_ruby() {
|
|
257
331
|
if command_exists ruby; then
|
|
258
332
|
RUBY_VERSION=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
|
|
259
|
-
print_info "Found Ruby $RUBY_VERSION"
|
|
333
|
+
print_info "Found Ruby version: $RUBY_VERSION"
|
|
260
334
|
|
|
261
|
-
if version_ge "$RUBY_VERSION" "
|
|
262
|
-
print_success "Ruby
|
|
335
|
+
if version_ge "$RUBY_VERSION" "3.1.0"; then
|
|
336
|
+
print_success "Ruby version is compatible (>= 3.1.0)"
|
|
263
337
|
return 0
|
|
264
338
|
else
|
|
265
|
-
print_warning "Ruby $RUBY_VERSION is too old (need >=
|
|
339
|
+
print_warning "Ruby version $RUBY_VERSION is too old (need >= 3.1.0)"
|
|
266
340
|
return 1
|
|
267
341
|
fi
|
|
268
342
|
else
|
|
269
|
-
print_warning "Ruby not
|
|
343
|
+
print_warning "Ruby is not installed"
|
|
270
344
|
return 1
|
|
271
345
|
fi
|
|
272
346
|
}
|
|
273
347
|
|
|
274
|
-
#
|
|
275
|
-
#
|
|
276
|
-
#
|
|
277
|
-
|
|
348
|
+
# Configure CN mirrors permanently in config files so all subsequent tool
|
|
349
|
+
# invocations (gem, npm, mise) automatically use the right source.
|
|
350
|
+
# Called once after detect_network_region, only when USE_CN_MIRRORS=true.
|
|
351
|
+
restore_mirrors() {
|
|
352
|
+
print_step "Restoring original mirror settings..."
|
|
353
|
+
|
|
354
|
+
# --- gem: restore ~/.gemrc ---
|
|
355
|
+
local gemrc="$HOME/.gemrc"
|
|
356
|
+
local gemrc_bak="$HOME/.gemrc_clackybak"
|
|
357
|
+
if [ -f "$gemrc_bak" ]; then
|
|
358
|
+
mv "$gemrc_bak" "$gemrc"
|
|
359
|
+
print_success "~/.gemrc restored from backup"
|
|
360
|
+
elif [ -f "$gemrc" ]; then
|
|
361
|
+
rm "$gemrc"
|
|
362
|
+
print_success "~/.gemrc removed (gem will use default rubygems.org)"
|
|
363
|
+
else
|
|
364
|
+
print_info "~/.gemrc — nothing to restore"
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
# --- npm: restore ~/.npmrc ---
|
|
368
|
+
local npmrc="$HOME/.npmrc"
|
|
369
|
+
local npmrc_bak="$HOME/.npmrc_clackybak"
|
|
370
|
+
if [ -f "$npmrc_bak" ]; then
|
|
371
|
+
mv "$npmrc_bak" "$npmrc"
|
|
372
|
+
print_success "~/.npmrc restored from backup"
|
|
373
|
+
elif [ -f "$npmrc" ]; then
|
|
374
|
+
rm "$npmrc"
|
|
375
|
+
print_success "~/.npmrc removed (npm will use default registry)"
|
|
376
|
+
else
|
|
377
|
+
print_info "~/.npmrc — nothing to restore"
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
# --- mise: unset node.mirror_url ---
|
|
381
|
+
local mise_bin=""
|
|
382
|
+
if command_exists mise; then
|
|
383
|
+
mise_bin="mise"
|
|
384
|
+
elif [ -x "$HOME/.local/bin/mise" ]; then
|
|
385
|
+
mise_bin="$HOME/.local/bin/mise"
|
|
386
|
+
fi
|
|
387
|
+
if [ -n "$mise_bin" ]; then
|
|
388
|
+
"$mise_bin" settings unset node.mirror_url 2>/dev/null && \
|
|
389
|
+
print_success "mise node.mirror_url unset"
|
|
390
|
+
else
|
|
391
|
+
print_info "mise not found — node.mirror_url skipped"
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
# --- Homebrew CN mirrors: remove from shell rc file ---
|
|
395
|
+
if [ -n "$SHELL_RC" ] && [ -f "$SHELL_RC" ] && grep -q "HOMEBREW_BOTTLE_DOMAIN" "$SHELL_RC" 2>/dev/null; then
|
|
396
|
+
# Remove the comment line and the three export lines added by the installer
|
|
397
|
+
sed -i.bak '/# Homebrew CN mirrors (added by openclacky installer)/d' "$SHELL_RC"
|
|
398
|
+
sed -i.bak '/HOMEBREW_BREW_GIT_REMOTE/d' "$SHELL_RC"
|
|
399
|
+
sed -i.bak '/HOMEBREW_CORE_GIT_REMOTE/d' "$SHELL_RC"
|
|
400
|
+
sed -i.bak '/HOMEBREW_BOTTLE_DOMAIN/d' "$SHELL_RC"
|
|
401
|
+
rm -f "${SHELL_RC}.bak"
|
|
402
|
+
unset HOMEBREW_BREW_GIT_REMOTE HOMEBREW_CORE_GIT_REMOTE HOMEBREW_BOTTLE_DOMAIN
|
|
403
|
+
print_success "Homebrew CN mirrors removed from $SHELL_RC"
|
|
404
|
+
else
|
|
405
|
+
print_info "Homebrew CN mirrors — nothing to restore"
|
|
406
|
+
fi
|
|
407
|
+
|
|
408
|
+
echo ""
|
|
409
|
+
print_success "Done. All mirror settings restored to original."
|
|
410
|
+
echo ""
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
configure_cn_mirrors() {
|
|
278
414
|
[ "$USE_CN_MIRRORS" = true ] || return 0
|
|
279
415
|
|
|
416
|
+
print_step "Configuring CN mirrors (permanent)..."
|
|
417
|
+
|
|
418
|
+
# --- gem: write ~/.gemrc ---
|
|
280
419
|
local gemrc="$HOME/.gemrc"
|
|
281
420
|
if [ -f "$gemrc" ] && grep -q "${CN_RUBYGEMS_URL}" "$gemrc" 2>/dev/null; then
|
|
282
|
-
|
|
421
|
+
# Already configured by us — leave it alone
|
|
422
|
+
print_success "gem source already set → ${CN_RUBYGEMS_URL} (~/.gemrc)"
|
|
283
423
|
else
|
|
284
|
-
|
|
424
|
+
# Existing file with different content — back it up then generate a clean one
|
|
425
|
+
if [ -f "$gemrc" ]; then
|
|
426
|
+
mv "$gemrc" "$HOME/.gemrc_clackybak"
|
|
427
|
+
print_info "Backed up existing ~/.gemrc → ~/.gemrc_clackybak"
|
|
428
|
+
fi
|
|
285
429
|
cat > "$gemrc" <<GEMRC
|
|
286
430
|
:sources:
|
|
287
431
|
- ${CN_RUBYGEMS_URL}
|
|
288
432
|
GEMRC
|
|
289
|
-
print_success "gem source → ${CN_RUBYGEMS_URL}"
|
|
433
|
+
print_success "gem source → ${CN_RUBYGEMS_URL} (~/.gemrc)"
|
|
434
|
+
fi
|
|
435
|
+
|
|
436
|
+
# --- npm: write ~/.npmrc ---
|
|
437
|
+
local npmrc="$HOME/.npmrc"
|
|
438
|
+
local npmrc_bak="$HOME/.npmrc_clackybak"
|
|
439
|
+
if [ -f "$npmrc" ] && grep -q "${NPM_REGISTRY_URL}" "$npmrc" 2>/dev/null; then
|
|
440
|
+
# Already configured by us — leave it alone
|
|
441
|
+
print_success "npm registry already set → ${NPM_REGISTRY_URL} (~/.npmrc)"
|
|
442
|
+
else
|
|
443
|
+
# Back up existing file (once), then write clean config
|
|
444
|
+
if [ -f "$npmrc" ] && [ ! -f "$npmrc_bak" ]; then
|
|
445
|
+
cp "$npmrc" "$npmrc_bak"
|
|
446
|
+
print_info "Backed up existing ~/.npmrc → ~/.npmrc_clackybak"
|
|
447
|
+
fi
|
|
448
|
+
if command_exists npm; then
|
|
449
|
+
npm config set registry "$NPM_REGISTRY_URL" 2>/dev/null && \
|
|
450
|
+
print_success "npm registry → ${NPM_REGISTRY_URL} (~/.npmrc)"
|
|
451
|
+
else
|
|
452
|
+
echo "registry=${NPM_REGISTRY_URL}" >> "$npmrc"
|
|
453
|
+
print_success "npm registry → ${NPM_REGISTRY_URL} (~/.npmrc, pre-set)"
|
|
454
|
+
fi
|
|
455
|
+
fi
|
|
456
|
+
|
|
457
|
+
# --- mise Node mirror ---
|
|
458
|
+
# Applied inside install_mise_runtime() after mise binary is available.
|
|
459
|
+
# NODE_MIRROR_URL is already set; nothing to do here.
|
|
460
|
+
|
|
461
|
+
echo ""
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
# Install via RubyGems
|
|
465
|
+
install_via_gem() {
|
|
466
|
+
print_step "Installing via RubyGems..."
|
|
467
|
+
|
|
468
|
+
if ! command_exists gem; then
|
|
469
|
+
print_error "RubyGems is not available"
|
|
470
|
+
return 1
|
|
471
|
+
fi
|
|
472
|
+
|
|
473
|
+
# Enforce Ruby >= 3.1.0 before attempting gem install
|
|
474
|
+
if ! command_exists ruby; then
|
|
475
|
+
print_error "Ruby is not available"
|
|
476
|
+
return 1
|
|
477
|
+
fi
|
|
478
|
+
RUBY_VERSION=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
|
|
479
|
+
if ! version_ge "$RUBY_VERSION" "3.1.0"; then
|
|
480
|
+
print_error "Ruby $RUBY_VERSION is too old (>= 3.1.0 required)"
|
|
481
|
+
return 1
|
|
482
|
+
fi
|
|
483
|
+
|
|
484
|
+
print_info "Installing ${DISPLAY_NAME}..."
|
|
485
|
+
gem install openclacky --no-document
|
|
486
|
+
|
|
487
|
+
if [ $? -eq 0 ]; then
|
|
488
|
+
print_success "${DISPLAY_NAME} installed successfully!"
|
|
489
|
+
install_chrome_devtools_mcp
|
|
490
|
+
return 0
|
|
491
|
+
else
|
|
492
|
+
print_error "Gem installation failed"
|
|
493
|
+
return 1
|
|
290
494
|
fi
|
|
291
495
|
}
|
|
292
496
|
|
|
293
|
-
#
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if ! command_exists mise && [ ! -x "$HOME/.local/bin/mise" ]; then
|
|
298
|
-
print_info "Installing mise..."
|
|
497
|
+
# Install mise for Ruby version management
|
|
498
|
+
install_mise_runtime() {
|
|
499
|
+
print_info "Installing mise..."
|
|
500
|
+
if ! command_exists mise; then
|
|
299
501
|
if curl -fsSL "$MISE_INSTALL_URL" | sh; then
|
|
300
|
-
# Add mise activation to shell rc
|
|
502
|
+
# Add mise activation to the current shell's rc file
|
|
301
503
|
local mise_init_line='eval "$(~/.local/bin/mise activate '"$CURRENT_SHELL"')"'
|
|
302
504
|
if [ -f "$SHELL_RC" ]; then
|
|
303
505
|
echo "$mise_init_line" >> "$SHELL_RC"
|
|
@@ -305,59 +507,116 @@ install_mise() {
|
|
|
305
507
|
echo "$mise_init_line" > "$SHELL_RC"
|
|
306
508
|
fi
|
|
307
509
|
print_info "Added mise activation to $SHELL_RC"
|
|
510
|
+
|
|
308
511
|
export PATH="$HOME/.local/bin:$PATH"
|
|
512
|
+
# Always activate using bash syntax here (this script runs under bash)
|
|
309
513
|
eval "$(~/.local/bin/mise activate bash)"
|
|
310
|
-
|
|
514
|
+
|
|
515
|
+
print_success "mise installed successfully"
|
|
311
516
|
else
|
|
312
517
|
print_error "Failed to install mise"
|
|
313
518
|
return 1
|
|
314
519
|
fi
|
|
315
520
|
else
|
|
316
|
-
export PATH="$HOME/.local/bin:$PATH"
|
|
317
|
-
eval "$(~/.local/bin/mise activate bash)" 2>/dev/null || true
|
|
318
521
|
print_success "mise already installed"
|
|
319
522
|
fi
|
|
523
|
+
|
|
524
|
+
# Apply CN Node mirror permanently — covers any future `mise install node` too.
|
|
525
|
+
if [ "$USE_CN_MIRRORS" = true ] && [ -n "$NODE_MIRROR_URL" ]; then
|
|
526
|
+
~/.local/bin/mise settings node.mirror_url="$NODE_MIRROR_URL" 2>/dev/null || true
|
|
527
|
+
print_info "mise Node mirror → ${NODE_MIRROR_URL}"
|
|
528
|
+
fi
|
|
320
529
|
}
|
|
321
530
|
|
|
322
|
-
# --------------------------------------------------------------------------
|
|
323
|
-
# Install Ruby via mise (precompiled when CN mirrors active)
|
|
324
|
-
# --------------------------------------------------------------------------
|
|
325
531
|
install_ruby_via_mise() {
|
|
326
|
-
|
|
532
|
+
if check_ruby; then
|
|
533
|
+
print_success "Ruby already installed and compatible — skipping Ruby installation"
|
|
534
|
+
return 0
|
|
535
|
+
fi
|
|
536
|
+
|
|
537
|
+
print_info "Installing Ruby 3 via mise..."
|
|
327
538
|
|
|
328
539
|
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
329
540
|
~/.local/bin/mise settings ruby.compile=false
|
|
330
541
|
~/.local/bin/mise settings ruby.precompiled_url="$CN_RUBY_PRECOMPILED_URL"
|
|
331
|
-
print_info "Using precompiled Ruby from CN CDN"
|
|
332
542
|
else
|
|
333
|
-
~/.local/bin/mise settings unset ruby.compile
|
|
543
|
+
~/.local/bin/mise settings unset ruby.compile >/dev/null 2>&1 || true
|
|
334
544
|
~/.local/bin/mise settings unset ruby.precompiled_url >/dev/null 2>&1 || true
|
|
335
545
|
fi
|
|
336
546
|
|
|
337
547
|
if ~/.local/bin/mise use -g "$RUBY_VERSION_SPEC"; then
|
|
338
548
|
eval "$(~/.local/bin/mise activate bash)"
|
|
339
|
-
print_success "Ruby installed
|
|
549
|
+
print_success "Ruby 3 installed successfully"
|
|
340
550
|
else
|
|
341
|
-
print_error "Failed to install Ruby
|
|
551
|
+
print_error "Failed to install Ruby 3"
|
|
342
552
|
return 1
|
|
343
553
|
fi
|
|
344
554
|
}
|
|
345
555
|
|
|
346
|
-
#
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
print_step "Checking Ruby..."
|
|
556
|
+
# Install dependencies and Ruby on macOS
|
|
557
|
+
install_macos_dependencies() {
|
|
558
|
+
print_step "Installing macOS dependencies and Ruby..."
|
|
559
|
+
echo ""
|
|
351
560
|
|
|
352
|
-
|
|
353
|
-
|
|
561
|
+
# Configure Homebrew CN mirrors before installing (CN mode only)
|
|
562
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
563
|
+
print_info "Configuring Homebrew CN mirrors..."
|
|
564
|
+
export HOMEBREW_INSTALL_FROM_API=1
|
|
565
|
+
export HOMEBREW_API_DOMAIN="$CN_HOMEBREW_API_DOMAIN"
|
|
566
|
+
export HOMEBREW_BREW_GIT_REMOTE="$CN_HOMEBREW_BREW_GIT_REMOTE"
|
|
567
|
+
export HOMEBREW_CORE_GIT_REMOTE="$CN_HOMEBREW_CORE_GIT_REMOTE"
|
|
568
|
+
export HOMEBREW_BOTTLE_DOMAIN="$CN_HOMEBREW_BOTTLE_DOMAIN"
|
|
569
|
+
|
|
570
|
+
# Persist to shell rc file
|
|
571
|
+
if ! grep -q "HOMEBREW_BOTTLE_DOMAIN" "$SHELL_RC" 2>/dev/null; then
|
|
572
|
+
{
|
|
573
|
+
echo ""
|
|
574
|
+
echo "# Homebrew CN mirrors (added by openclacky installer)"
|
|
575
|
+
echo "export HOMEBREW_INSTALL_FROM_API=1"
|
|
576
|
+
echo "export HOMEBREW_API_DOMAIN=\"${CN_HOMEBREW_API_DOMAIN}\""
|
|
577
|
+
echo "export HOMEBREW_BREW_GIT_REMOTE=\"${CN_HOMEBREW_BREW_GIT_REMOTE}\""
|
|
578
|
+
echo "export HOMEBREW_CORE_GIT_REMOTE=\"${CN_HOMEBREW_CORE_GIT_REMOTE}\""
|
|
579
|
+
echo "export HOMEBREW_BOTTLE_DOMAIN=\"${CN_HOMEBREW_BOTTLE_DOMAIN}\""
|
|
580
|
+
} >> "$SHELL_RC"
|
|
581
|
+
print_success "Homebrew CN mirrors written to $SHELL_RC"
|
|
582
|
+
else
|
|
583
|
+
print_success "Homebrew CN mirrors already configured in $SHELL_RC"
|
|
584
|
+
fi
|
|
354
585
|
fi
|
|
355
586
|
|
|
356
|
-
#
|
|
357
|
-
|
|
587
|
+
# Install Homebrew (it will automatically install Xcode Command Line Tools if needed)
|
|
588
|
+
print_info "Checking Homebrew installation..."
|
|
589
|
+
if ! command_exists brew; then
|
|
590
|
+
print_info "Installing Homebrew..."
|
|
591
|
+
local brew_install_url="$HOMEBREW_INSTALL_SCRIPT_URL"
|
|
592
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
593
|
+
brew_install_url="$CN_HOMEBREW_INSTALL_SCRIPT_URL"
|
|
594
|
+
fi
|
|
595
|
+
/bin/bash -c "$(curl -fsSL "$brew_install_url")"
|
|
596
|
+
|
|
597
|
+
# Add Homebrew to PATH
|
|
598
|
+
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> "$SHELL_RC"
|
|
599
|
+
export PATH="/opt/homebrew/bin:$PATH"
|
|
600
|
+
|
|
601
|
+
print_success "Homebrew installed successfully"
|
|
602
|
+
else
|
|
603
|
+
print_success "Homebrew already installed"
|
|
604
|
+
fi
|
|
605
|
+
|
|
606
|
+
# Install build dependencies
|
|
607
|
+
print_info "Installing build dependencies..."
|
|
608
|
+
if brew install openssl@3 libyaml gmp; then
|
|
609
|
+
print_success "Build dependencies installed"
|
|
610
|
+
else
|
|
611
|
+
print_error "Failed to install build dependencies"
|
|
612
|
+
return 1
|
|
613
|
+
fi
|
|
614
|
+
|
|
615
|
+
# Install mise for Ruby version management
|
|
616
|
+
# Detect current shell before configuring mise
|
|
358
617
|
detect_shell
|
|
359
618
|
|
|
360
|
-
if !
|
|
619
|
+
if ! install_mise_runtime; then
|
|
361
620
|
return 1
|
|
362
621
|
fi
|
|
363
622
|
|
|
@@ -365,7 +624,7 @@ ensure_ruby() {
|
|
|
365
624
|
return 1
|
|
366
625
|
fi
|
|
367
626
|
|
|
368
|
-
# Verify
|
|
627
|
+
# Verify Ruby installation
|
|
369
628
|
if check_ruby; then
|
|
370
629
|
return 0
|
|
371
630
|
else
|
|
@@ -374,91 +633,83 @@ ensure_ruby() {
|
|
|
374
633
|
fi
|
|
375
634
|
}
|
|
376
635
|
|
|
377
|
-
#
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if [ "$DISTRO" = "ubuntu" ] || [ "$DISTRO" = "debian" ]; then
|
|
382
|
-
print_step "Installing build dependencies..."
|
|
636
|
+
# Install dependencies and Ruby on Ubuntu/Debian
|
|
637
|
+
install_ubuntu_dependencies() {
|
|
638
|
+
print_step "Installing Ubuntu dependencies and Ruby..."
|
|
639
|
+
echo ""
|
|
383
640
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
deb ${mirror_base} ${codename} ${
|
|
391
|
-
deb ${mirror_base} ${codename}-updates ${
|
|
392
|
-
deb ${mirror_base} ${codename}-backports ${
|
|
393
|
-
deb ${mirror_base} ${codename}-security ${
|
|
641
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
642
|
+
print_info "Configuring apt mirror (Aliyun)..."
|
|
643
|
+
local codename="${VERSION_CODENAME:-jammy}"
|
|
644
|
+
local mirror_base="https://mirrors.aliyun.com/ubuntu/"
|
|
645
|
+
local common_components="main restricted universe multiverse"
|
|
646
|
+
sudo tee /etc/apt/sources.list > /dev/null <<EOF
|
|
647
|
+
deb ${mirror_base} ${codename} ${common_components}
|
|
648
|
+
deb ${mirror_base} ${codename}-updates ${common_components}
|
|
649
|
+
deb ${mirror_base} ${codename}-backports ${common_components}
|
|
650
|
+
deb ${mirror_base} ${codename}-security ${common_components}
|
|
394
651
|
EOF
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
sudo apt install -y build-essential libssl-dev libyaml-dev zlib1g-dev libgmp-dev git
|
|
399
|
-
print_success "Build dependencies installed"
|
|
652
|
+
print_success "Mirror configured"
|
|
653
|
+
else
|
|
654
|
+
print_info "Using default apt sources"
|
|
400
655
|
fi
|
|
401
|
-
}
|
|
402
656
|
|
|
403
|
-
#
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
# Gem dir is writable (e.g. mise-managed Ruby) — nothing to do
|
|
412
|
-
if [ -w "$gem_dir" ]; then
|
|
413
|
-
return 0
|
|
657
|
+
# Update package list
|
|
658
|
+
print_info "Updating package list..."
|
|
659
|
+
if sudo apt update; then
|
|
660
|
+
print_success "Package list updated"
|
|
661
|
+
else
|
|
662
|
+
print_error "Failed to update package list"
|
|
663
|
+
return 1
|
|
414
664
|
fi
|
|
415
665
|
|
|
416
|
-
#
|
|
417
|
-
|
|
418
|
-
|
|
666
|
+
# Install build dependencies
|
|
667
|
+
print_info "Installing build dependencies..."
|
|
668
|
+
if sudo apt install -y build-essential libssl-dev libyaml-dev zlib1g-dev libgmp-dev git; then
|
|
669
|
+
print_success "Build dependencies installed"
|
|
670
|
+
else
|
|
671
|
+
print_error "Failed to install build dependencies"
|
|
672
|
+
return 1
|
|
673
|
+
fi
|
|
419
674
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
export PATH="$HOME/.gem/ruby/${ruby_api}/bin:$PATH"
|
|
675
|
+
# Detect current shell before configuring mise
|
|
676
|
+
detect_shell
|
|
423
677
|
|
|
424
|
-
|
|
678
|
+
# In WSL, Windows paths (e.g. /mnt/c/Windows/system32) are appended to PATH.
|
|
679
|
+
# mise scans PATH directories for mise.toml and errors on untrusted files found there.
|
|
680
|
+
# Auto-trust the Windows system32 directory to suppress those errors.
|
|
681
|
+
export MISE_TRUSTED_CONFIG_PATHS="/mnt/c/Windows/system32"
|
|
425
682
|
|
|
426
|
-
#
|
|
427
|
-
if
|
|
428
|
-
|
|
429
|
-
echo ""
|
|
430
|
-
echo "# Ruby user gem dir (added by openclacky installer)"
|
|
431
|
-
echo "export GEM_HOME=\"\$HOME/.gem/ruby/${ruby_api}\""
|
|
432
|
-
echo "export GEM_PATH=\"\$HOME/.gem/ruby/${ruby_api}\""
|
|
433
|
-
echo "export PATH=\"\$HOME/.gem/ruby/${ruby_api}/bin:\$PATH\""
|
|
434
|
-
} >> "$SHELL_RC"
|
|
435
|
-
print_info "GEM_HOME written to $SHELL_RC"
|
|
683
|
+
# Install mise for Ruby version management
|
|
684
|
+
if ! install_mise_runtime; then
|
|
685
|
+
return 1
|
|
436
686
|
fi
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
# --------------------------------------------------------------------------
|
|
440
|
-
# gem install openclacky
|
|
441
|
-
# --------------------------------------------------------------------------
|
|
442
|
-
install_via_gem() {
|
|
443
|
-
print_step "Installing ${DISPLAY_NAME} via gem..."
|
|
444
|
-
|
|
445
|
-
configure_gem_source
|
|
446
|
-
setup_gem_home
|
|
447
687
|
|
|
448
|
-
|
|
688
|
+
if ! install_ruby_via_mise; then
|
|
689
|
+
return 1
|
|
690
|
+
fi
|
|
449
691
|
|
|
450
|
-
|
|
451
|
-
|
|
692
|
+
# Verify Ruby installation
|
|
693
|
+
if check_ruby; then
|
|
452
694
|
return 0
|
|
453
695
|
else
|
|
454
|
-
print_error "
|
|
696
|
+
print_error "Ruby installation verification failed"
|
|
455
697
|
return 1
|
|
456
698
|
fi
|
|
457
699
|
}
|
|
458
700
|
|
|
459
|
-
#
|
|
460
|
-
# Parse
|
|
461
|
-
#
|
|
701
|
+
# Suggest Ruby installation
|
|
702
|
+
# Parse command-line arguments.
|
|
703
|
+
#
|
|
704
|
+
# Supported flags:
|
|
705
|
+
# --brand-name=VALUE Human-readable brand name (e.g. "JohnAI")
|
|
706
|
+
# --command=VALUE CLI command to install as a wrapper (e.g. "johncli")
|
|
707
|
+
#
|
|
708
|
+
# Usage from install command:
|
|
709
|
+
# /bin/bash -c "$(curl -sSL .../install.sh)" -- --brand-name="JohnAI" --command="johncli"
|
|
710
|
+
#
|
|
711
|
+
# Note: bash -c passes positional args starting at $0, so real flags are in $@
|
|
712
|
+
# when invoked with the `--` separator; they land in $1..$N of the script.
|
|
462
713
|
parse_args() {
|
|
463
714
|
for arg in "$0" "$@"; do
|
|
464
715
|
case "$arg" in
|
|
@@ -468,14 +719,20 @@ parse_args() {
|
|
|
468
719
|
--command=*)
|
|
469
720
|
BRAND_COMMAND="${arg#--command=}"
|
|
470
721
|
;;
|
|
722
|
+
--restore-mirrors)
|
|
723
|
+
RESTORE_MIRRORS=true
|
|
724
|
+
;;
|
|
471
725
|
esac
|
|
472
726
|
done
|
|
727
|
+
# Global display name: brand name if provided, otherwise fall back to OpenClacky
|
|
473
728
|
DISPLAY_NAME="${BRAND_NAME:-OpenClacky}"
|
|
474
729
|
}
|
|
475
730
|
|
|
476
|
-
#
|
|
477
|
-
#
|
|
478
|
-
#
|
|
731
|
+
# Write brand configuration and install the wrapper command.
|
|
732
|
+
#
|
|
733
|
+
# Creates ~/.clacky/brand.yml with brand metadata and, if a custom command
|
|
734
|
+
# name was requested, installs a thin wrapper script at ~/.local/bin/<command>
|
|
735
|
+
# that simply delegates to openclacky.
|
|
479
736
|
setup_brand() {
|
|
480
737
|
[ -z "$BRAND_NAME" ] && return 0
|
|
481
738
|
|
|
@@ -485,60 +742,49 @@ setup_brand() {
|
|
|
485
742
|
|
|
486
743
|
print_step "Configuring brand: $BRAND_NAME"
|
|
487
744
|
|
|
745
|
+
# Write brand.yml — minimal entry; license_key is filled in later via
|
|
746
|
+
# the CLI or WebUI activation flow.
|
|
488
747
|
cat > "$brand_file" <<YAML
|
|
489
748
|
product_name: "${BRAND_NAME}"
|
|
490
749
|
package_name: "${BRAND_COMMAND}"
|
|
491
750
|
YAML
|
|
492
|
-
print_success "Brand config written to $brand_file"
|
|
493
751
|
|
|
752
|
+
print_success "Brand configuration written to $brand_file"
|
|
753
|
+
|
|
754
|
+
# Install wrapper command if a custom command name was provided.
|
|
494
755
|
if [ -n "$BRAND_COMMAND" ]; then
|
|
495
756
|
local bin_dir="$HOME/.local/bin"
|
|
496
757
|
mkdir -p "$bin_dir"
|
|
758
|
+
|
|
497
759
|
local wrapper="$bin_dir/$BRAND_COMMAND"
|
|
498
760
|
cat > "$wrapper" <<WRAPPER
|
|
499
761
|
#!/bin/sh
|
|
500
762
|
exec openclacky "\$@"
|
|
501
763
|
WRAPPER
|
|
502
764
|
chmod +x "$wrapper"
|
|
503
|
-
print_success "Wrapper installed: $wrapper"
|
|
765
|
+
print_success "Wrapper command installed: $wrapper"
|
|
504
766
|
|
|
767
|
+
# Remind user to add ~/.local/bin to PATH if needed.
|
|
505
768
|
case ":$PATH:" in
|
|
506
769
|
*":$bin_dir:"*) ;;
|
|
507
770
|
*)
|
|
508
|
-
print_warning "Add to your shell profile
|
|
771
|
+
print_warning "Add the following to your shell profile so '$BRAND_COMMAND' is available:"
|
|
772
|
+
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
|
509
773
|
;;
|
|
510
774
|
esac
|
|
511
775
|
fi
|
|
512
776
|
}
|
|
513
777
|
|
|
514
|
-
#
|
|
515
|
-
# Post-install info
|
|
516
|
-
# --------------------------------------------------------------------------
|
|
517
|
-
show_post_install_info() {
|
|
518
|
-
local cmd="${BRAND_COMMAND:-openclacky}"
|
|
519
|
-
|
|
520
|
-
echo ""
|
|
521
|
-
echo -e " ${GREEN}${DISPLAY_NAME} installed successfully!${NC}"
|
|
522
|
-
echo ""
|
|
523
|
-
echo " Reload your shell:"
|
|
524
|
-
echo ""
|
|
525
|
-
echo -e " ${YELLOW}source ${SHELL_RC}${NC}"
|
|
526
|
-
echo ""
|
|
527
|
-
echo -e " ${GREEN}Web UI${NC} (recommended):"
|
|
528
|
-
echo " $cmd server"
|
|
529
|
-
echo " Open http://localhost:7070"
|
|
530
|
-
echo ""
|
|
531
|
-
echo -e " ${GREEN}Terminal${NC}:"
|
|
532
|
-
echo " $cmd"
|
|
533
|
-
echo ""
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
# --------------------------------------------------------------------------
|
|
537
|
-
# Main
|
|
538
|
-
# --------------------------------------------------------------------------
|
|
778
|
+
# Main installation logic
|
|
539
779
|
main() {
|
|
540
780
|
parse_args "$@"
|
|
541
781
|
|
|
782
|
+
# --restore-mirrors: undo CN mirror config and exit
|
|
783
|
+
if [ "${RESTORE_MIRRORS:-false}" = true ]; then
|
|
784
|
+
restore_mirrors
|
|
785
|
+
exit 0
|
|
786
|
+
fi
|
|
787
|
+
|
|
542
788
|
echo ""
|
|
543
789
|
echo "${DISPLAY_NAME} Installation"
|
|
544
790
|
echo ""
|
|
@@ -546,29 +792,32 @@ main() {
|
|
|
546
792
|
detect_os
|
|
547
793
|
detect_shell
|
|
548
794
|
detect_network_region
|
|
795
|
+
configure_cn_mirrors
|
|
549
796
|
|
|
550
|
-
#
|
|
551
|
-
if [ "$OS" = "
|
|
797
|
+
# Install dependencies and Ruby (always run, handles already-installed gracefully)
|
|
798
|
+
if [ "$OS" = "macOS" ]; then
|
|
799
|
+
if ! install_macos_dependencies; then
|
|
800
|
+
print_error "Failed to install dependencies"
|
|
801
|
+
exit 1
|
|
802
|
+
fi
|
|
803
|
+
elif [ "$OS" = "Linux" ]; then
|
|
552
804
|
if [ "$DISTRO" = "ubuntu" ] || [ "$DISTRO" = "debian" ]; then
|
|
553
|
-
|
|
805
|
+
if ! install_ubuntu_dependencies; then
|
|
806
|
+
print_error "Failed to install dependencies"
|
|
807
|
+
exit 1
|
|
808
|
+
fi
|
|
554
809
|
else
|
|
555
810
|
print_error "Unsupported Linux distribution: $DISTRO"
|
|
556
|
-
print_info "Please install Ruby
|
|
811
|
+
print_info "Please install Ruby manually and run: gem install openclacky"
|
|
557
812
|
exit 1
|
|
558
813
|
fi
|
|
559
|
-
|
|
560
|
-
export MISE_TRUSTED_CONFIG_PATHS="/mnt/c/Windows/system32"
|
|
561
|
-
elif [ "$OS" != "macOS" ]; then
|
|
814
|
+
else
|
|
562
815
|
print_error "Unsupported OS: $OS"
|
|
563
|
-
print_info "Please install Ruby
|
|
564
|
-
exit 1
|
|
565
|
-
fi
|
|
566
|
-
|
|
567
|
-
if ! ensure_ruby; then
|
|
568
|
-
print_error "Could not install a compatible Ruby"
|
|
816
|
+
print_info "Please install Ruby manually and run: gem install openclacky"
|
|
569
817
|
exit 1
|
|
570
818
|
fi
|
|
571
819
|
|
|
820
|
+
# Install via gem
|
|
572
821
|
if install_via_gem; then
|
|
573
822
|
setup_brand
|
|
574
823
|
show_post_install_info
|
|
@@ -579,4 +828,64 @@ main() {
|
|
|
579
828
|
fi
|
|
580
829
|
}
|
|
581
830
|
|
|
831
|
+
# Install agent-browser (browser automation tool)
|
|
832
|
+
# This step is optional — failures are silently skipped with a hint.
|
|
833
|
+
install_chrome_devtools_mcp() {
|
|
834
|
+
print_step "Installing chrome-devtools-mcp..."
|
|
835
|
+
|
|
836
|
+
if ! command_exists npm; then
|
|
837
|
+
local mise_bin=""
|
|
838
|
+
if command_exists mise; then
|
|
839
|
+
mise_bin="mise"
|
|
840
|
+
elif [ -x "$HOME/.local/bin/mise" ]; then
|
|
841
|
+
mise_bin="$HOME/.local/bin/mise"
|
|
842
|
+
fi
|
|
843
|
+
|
|
844
|
+
if [ -n "$mise_bin" ]; then
|
|
845
|
+
print_info "Installing Node.js via mise..."
|
|
846
|
+
"$mise_bin" install node@22 > /dev/null 2>&1 || true
|
|
847
|
+
"$mise_bin" use -g node@22 > /dev/null 2>&1 || true
|
|
848
|
+
eval "$("$mise_bin" activate bash 2>/dev/null)" 2>/dev/null || true
|
|
849
|
+
fi
|
|
850
|
+
else
|
|
851
|
+
print_success "Node.js already installed — $(node --version 2>/dev/null)"
|
|
852
|
+
fi
|
|
853
|
+
|
|
854
|
+
if ! command_exists npm; then
|
|
855
|
+
print_warning "Node.js/npm not found. Browser automation will not be available."
|
|
856
|
+
print_info "To enable browser support, install Node.js and run: npm install -g chrome-devtools-mcp"
|
|
857
|
+
return 0
|
|
858
|
+
fi
|
|
859
|
+
|
|
860
|
+
if npm install -g chrome-devtools-mcp > /dev/null 2>&1; then
|
|
861
|
+
print_success "chrome-devtools-mcp installed"
|
|
862
|
+
else
|
|
863
|
+
print_warning "chrome-devtools-mcp installation failed. Browser automation may not work."
|
|
864
|
+
print_info "To install manually: npm install -g chrome-devtools-mcp"
|
|
865
|
+
fi
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
# Post-installation information
|
|
869
|
+
show_post_install_info() {
|
|
870
|
+
local cmd="${BRAND_COMMAND:-openclacky}"
|
|
871
|
+
|
|
872
|
+
echo ""
|
|
873
|
+
echo -e " ${GREEN}${DISPLAY_NAME} installed successfully!${NC}"
|
|
874
|
+
echo ""
|
|
875
|
+
echo " First, reload your shell environment:"
|
|
876
|
+
echo ""
|
|
877
|
+
echo -e " ${YELLOW}source ${SHELL_RC}${NC}"
|
|
878
|
+
echo ""
|
|
879
|
+
echo " Then pick how you want to start:"
|
|
880
|
+
echo ""
|
|
881
|
+
echo -e " ${GREEN}Web UI${NC} (recommended):"
|
|
882
|
+
echo " $cmd server"
|
|
883
|
+
echo " Open http://localhost:7070 in your browser"
|
|
884
|
+
echo ""
|
|
885
|
+
echo -e " ${GREEN}Terminal mode${NC}:"
|
|
886
|
+
echo " $cmd"
|
|
887
|
+
echo ""
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
# Run main installation
|
|
582
891
|
main "$@"
|