openclacky 0.9.19 → 0.9.21
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 +27 -0
- data/docs/c-end-user-positioning.md +64 -0
- data/lib/clacky/agent/llm_caller.rb +1 -1
- data/lib/clacky/default_skills/channel-setup/feishu_setup.rb +4 -4
- data/lib/clacky/default_skills/cron-task-creator/SKILL.md +65 -58
- data/lib/clacky/default_skills/skill-creator/SKILL.md +6 -0
- data/lib/clacky/default_skills/skill-creator/scripts/validate_skill_frontmatter.rb +143 -0
- data/lib/clacky/server/http_server.rb +60 -91
- data/lib/clacky/server/scheduler.rb +55 -0
- data/lib/clacky/tools/browser.rb +2 -2
- data/lib/clacky/utils/encoding.rb +21 -0
- data/lib/clacky/utils/environment_detector.rb +9 -6
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +1 -1
- data/lib/clacky/web/tasks.js +10 -26
- data/scripts/install.ps1 +4 -4
- data/scripts/install.sh +50 -31
- metadata +3 -6
- data/lib/clacky/default_skills/cron-task-creator/scripts/list_tasks.rb +0 -121
- data/lib/clacky/default_skills/cron-task-creator/scripts/manage_schedule.rb +0 -149
- data/lib/clacky/default_skills/cron-task-creator/scripts/manage_task.rb +0 -81
- data/lib/clacky/default_skills/cron-task-creator/scripts/task_history.rb +0 -137
- data/scripts/install_simple.sh +0 -630
data/scripts/install_simple.sh
DELETED
|
@@ -1,630 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# OpenClacky Installation Script
|
|
3
|
-
# This script automatically detects your system and installs OpenClacky
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
# Brand configuration (populated by --brand-name / --command flags)
|
|
8
|
-
BRAND_NAME=""
|
|
9
|
-
BRAND_COMMAND=""
|
|
10
|
-
|
|
11
|
-
# Colors for output
|
|
12
|
-
RED='\033[0;31m'
|
|
13
|
-
GREEN='\033[0;32m'
|
|
14
|
-
YELLOW='\033[1;33m'
|
|
15
|
-
BLUE='\033[0;34m'
|
|
16
|
-
NC='\033[0m' # No Color
|
|
17
|
-
|
|
18
|
-
print_info() {
|
|
19
|
-
echo -e "${BLUE}ℹ${NC} $1"
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
print_success() {
|
|
23
|
-
echo -e "${GREEN}✓${NC} $1"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
print_warning() {
|
|
27
|
-
echo -e "${YELLOW}⚠${NC} $1"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
print_error() {
|
|
31
|
-
echo -e "${RED}✗${NC} $1"
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
print_step() {
|
|
35
|
-
echo -e "\n${BLUE}==>${NC} $1"
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
# Detect OS
|
|
39
|
-
detect_os() {
|
|
40
|
-
case "$(uname -s)" in
|
|
41
|
-
Linux*) OS=Linux;;
|
|
42
|
-
Darwin*) OS=macOS;;
|
|
43
|
-
CYGWIN*) OS=Windows;;
|
|
44
|
-
MINGW*) OS=Windows;;
|
|
45
|
-
*) OS=Unknown;;
|
|
46
|
-
esac
|
|
47
|
-
print_info "Detected OS: $OS"
|
|
48
|
-
|
|
49
|
-
if [ "$OS" = "Linux" ]; then
|
|
50
|
-
if [ -f /etc/os-release ]; then
|
|
51
|
-
. /etc/os-release
|
|
52
|
-
DISTRO=$ID
|
|
53
|
-
print_info "Detected Linux distribution: $DISTRO"
|
|
54
|
-
else
|
|
55
|
-
DISTRO=unknown
|
|
56
|
-
fi
|
|
57
|
-
fi
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
# Check if command exists
|
|
61
|
-
command_exists() {
|
|
62
|
-
command -v "$1" >/dev/null 2>&1
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
# Detect current shell type
|
|
66
|
-
detect_shell() {
|
|
67
|
-
local shell_name
|
|
68
|
-
shell_name=$(basename "$SHELL")
|
|
69
|
-
|
|
70
|
-
case "$shell_name" in
|
|
71
|
-
zsh)
|
|
72
|
-
CURRENT_SHELL="zsh"
|
|
73
|
-
SHELL_RC="$HOME/.zshrc"
|
|
74
|
-
;;
|
|
75
|
-
bash)
|
|
76
|
-
CURRENT_SHELL="bash"
|
|
77
|
-
if [ "$OS" = "macOS" ]; then
|
|
78
|
-
SHELL_RC="$HOME/.bash_profile"
|
|
79
|
-
else
|
|
80
|
-
SHELL_RC="$HOME/.bashrc"
|
|
81
|
-
fi
|
|
82
|
-
;;
|
|
83
|
-
fish)
|
|
84
|
-
CURRENT_SHELL="fish"
|
|
85
|
-
SHELL_RC="$HOME/.config/fish/config.fish"
|
|
86
|
-
;;
|
|
87
|
-
*)
|
|
88
|
-
CURRENT_SHELL="bash"
|
|
89
|
-
SHELL_RC="$HOME/.bashrc"
|
|
90
|
-
;;
|
|
91
|
-
esac
|
|
92
|
-
|
|
93
|
-
print_info "Detected shell: $CURRENT_SHELL (rc file: $SHELL_RC)"
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
# --------------------------------------------------------------------------
|
|
97
|
-
# Network region detection & mirror selection
|
|
98
|
-
# --------------------------------------------------------------------------
|
|
99
|
-
SLOW_THRESHOLD_MS=5000
|
|
100
|
-
NETWORK_REGION="global"
|
|
101
|
-
USE_CN_MIRRORS=false
|
|
102
|
-
|
|
103
|
-
GITHUB_RAW_BASE_URL="https://raw.githubusercontent.com"
|
|
104
|
-
DEFAULT_RUBYGEMS_URL="https://rubygems.org"
|
|
105
|
-
DEFAULT_MISE_INSTALL_URL="https://mise.run"
|
|
106
|
-
|
|
107
|
-
CN_CDN_BASE_URL="https://oss.1024code.com"
|
|
108
|
-
CN_MISE_INSTALL_URL="${CN_CDN_BASE_URL}/mise.sh"
|
|
109
|
-
CN_RUBY_PRECOMPILED_URL="${CN_CDN_BASE_URL}/ruby/ruby-{version}.{platform}.tar.gz"
|
|
110
|
-
CN_RUBYGEMS_URL="https://mirrors.aliyun.com/rubygems/"
|
|
111
|
-
CN_GEM_BASE_URL="${CN_CDN_BASE_URL}/openclacky"
|
|
112
|
-
CN_GEM_LATEST_URL="${CN_GEM_BASE_URL}/latest.txt"
|
|
113
|
-
|
|
114
|
-
# Active values (overridden by detect_network_region)
|
|
115
|
-
MISE_INSTALL_URL="$DEFAULT_MISE_INSTALL_URL"
|
|
116
|
-
RUBYGEMS_INSTALL_URL="$DEFAULT_RUBYGEMS_URL"
|
|
117
|
-
RUBY_VERSION_SPEC="ruby@3" # mise will pick latest stable
|
|
118
|
-
|
|
119
|
-
_probe_url() {
|
|
120
|
-
local url="$1"
|
|
121
|
-
local timeout_sec=5
|
|
122
|
-
local curl_output http_code total_time elapsed_ms
|
|
123
|
-
|
|
124
|
-
curl_output=$(curl -s -o /dev/null -w "%{http_code} %{time_total}" \
|
|
125
|
-
--connect-timeout "$timeout_sec" \
|
|
126
|
-
--max-time "$timeout_sec" \
|
|
127
|
-
"$url" 2>/dev/null) || true
|
|
128
|
-
http_code="${curl_output%% *}"
|
|
129
|
-
total_time="${curl_output#* }"
|
|
130
|
-
|
|
131
|
-
if [ -z "$http_code" ] || [ "$http_code" = "000" ] || [ "$http_code" = "$curl_output" ]; then
|
|
132
|
-
echo "timeout"
|
|
133
|
-
else
|
|
134
|
-
elapsed_ms=$(awk -v seconds="$total_time" 'BEGIN { printf "%d", seconds * 1000 }')
|
|
135
|
-
echo "$elapsed_ms"
|
|
136
|
-
fi
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
_is_slow_or_unreachable() {
|
|
140
|
-
local result="$1"
|
|
141
|
-
if [ "$result" = "timeout" ]; then
|
|
142
|
-
return 0
|
|
143
|
-
fi
|
|
144
|
-
[ "$result" -ge "$SLOW_THRESHOLD_MS" ] 2>/dev/null
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
_format_probe_time() {
|
|
148
|
-
local result="$1"
|
|
149
|
-
if [ "$result" = "timeout" ]; then
|
|
150
|
-
echo "timeout"
|
|
151
|
-
else
|
|
152
|
-
awk -v ms="$result" 'BEGIN { printf "%.1fs", ms / 1000 }'
|
|
153
|
-
fi
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
_print_probe_result() {
|
|
157
|
-
local label="$1"
|
|
158
|
-
local result="$2"
|
|
159
|
-
|
|
160
|
-
if [ "$result" = "timeout" ]; then
|
|
161
|
-
print_warning "UNREACHABLE ${label}"
|
|
162
|
-
elif _is_slow_or_unreachable "$result"; then
|
|
163
|
-
print_warning "SLOW ($(_format_probe_time "$result")) ${label}"
|
|
164
|
-
else
|
|
165
|
-
print_success "OK ($(_format_probe_time "$result")) ${label}"
|
|
166
|
-
fi
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
_probe_url_with_retry() {
|
|
170
|
-
local url="$1"
|
|
171
|
-
local max_retries="${2:-2}"
|
|
172
|
-
local result
|
|
173
|
-
|
|
174
|
-
for _ in $(seq 1 "$max_retries"); do
|
|
175
|
-
result=$(_probe_url "$url")
|
|
176
|
-
if ! _is_slow_or_unreachable "$result"; then
|
|
177
|
-
echo "$result"
|
|
178
|
-
return 0
|
|
179
|
-
fi
|
|
180
|
-
done
|
|
181
|
-
echo "$result"
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
detect_network_region() {
|
|
185
|
-
print_step "Network pre-flight check..."
|
|
186
|
-
echo ""
|
|
187
|
-
|
|
188
|
-
print_info "Detecting network region..."
|
|
189
|
-
local google_result baidu_result
|
|
190
|
-
google_result=$(_probe_url "https://www.google.com")
|
|
191
|
-
baidu_result=$(_probe_url "https://www.baidu.com")
|
|
192
|
-
|
|
193
|
-
_print_probe_result "google.com" "$google_result"
|
|
194
|
-
_print_probe_result "baidu.com" "$baidu_result"
|
|
195
|
-
|
|
196
|
-
local google_ok=false baidu_ok=false
|
|
197
|
-
! _is_slow_or_unreachable "$google_result" && google_ok=true
|
|
198
|
-
! _is_slow_or_unreachable "$baidu_result" && baidu_ok=true
|
|
199
|
-
|
|
200
|
-
if [ "$google_ok" = true ]; then
|
|
201
|
-
NETWORK_REGION="global"
|
|
202
|
-
print_success "Region: global"
|
|
203
|
-
elif [ "$baidu_ok" = true ]; then
|
|
204
|
-
NETWORK_REGION="china"
|
|
205
|
-
print_success "Region: china"
|
|
206
|
-
else
|
|
207
|
-
NETWORK_REGION="unknown"
|
|
208
|
-
print_warning "Region: unknown (both unreachable)"
|
|
209
|
-
fi
|
|
210
|
-
echo ""
|
|
211
|
-
|
|
212
|
-
if [ "$NETWORK_REGION" = "china" ]; then
|
|
213
|
-
local cdn_result mirror_result
|
|
214
|
-
cdn_result=$(_probe_url_with_retry "$CN_MISE_INSTALL_URL")
|
|
215
|
-
mirror_result=$(_probe_url_with_retry "$CN_RUBYGEMS_URL")
|
|
216
|
-
|
|
217
|
-
_print_probe_result "CN CDN (mise/Ruby)" "$cdn_result"
|
|
218
|
-
_print_probe_result "Aliyun (gem)" "$mirror_result"
|
|
219
|
-
|
|
220
|
-
local cdn_ok=false mirror_ok=false
|
|
221
|
-
! _is_slow_or_unreachable "$cdn_result" && cdn_ok=true
|
|
222
|
-
! _is_slow_or_unreachable "$mirror_result" && mirror_ok=true
|
|
223
|
-
|
|
224
|
-
if [ "$cdn_ok" = true ] || [ "$mirror_ok" = true ]; then
|
|
225
|
-
USE_CN_MIRRORS=true
|
|
226
|
-
MISE_INSTALL_URL="$CN_MISE_INSTALL_URL"
|
|
227
|
-
RUBYGEMS_INSTALL_URL="$CN_RUBYGEMS_URL"
|
|
228
|
-
RUBY_VERSION_SPEC="ruby@3.4.8"
|
|
229
|
-
print_info "CN mirrors applied."
|
|
230
|
-
else
|
|
231
|
-
print_warning "CN mirrors unreachable — falling back to global sources."
|
|
232
|
-
fi
|
|
233
|
-
else
|
|
234
|
-
local rubygems_result mise_result
|
|
235
|
-
rubygems_result=$(_probe_url_with_retry "$DEFAULT_RUBYGEMS_URL")
|
|
236
|
-
mise_result=$(_probe_url_with_retry "$DEFAULT_MISE_INSTALL_URL")
|
|
237
|
-
|
|
238
|
-
_print_probe_result "RubyGems" "$rubygems_result"
|
|
239
|
-
_print_probe_result "mise.run" "$mise_result"
|
|
240
|
-
|
|
241
|
-
_is_slow_or_unreachable "$rubygems_result" && print_warning "RubyGems is slow/unreachable."
|
|
242
|
-
_is_slow_or_unreachable "$mise_result" && print_warning "mise.run is slow/unreachable."
|
|
243
|
-
fi
|
|
244
|
-
|
|
245
|
-
echo ""
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
# --------------------------------------------------------------------------
|
|
249
|
-
# Version comparison
|
|
250
|
-
# --------------------------------------------------------------------------
|
|
251
|
-
version_ge() {
|
|
252
|
-
printf '%s\n%s\n' "$2" "$1" | sort -V -C
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
# --------------------------------------------------------------------------
|
|
256
|
-
# Ruby check (>= 2.6.0)
|
|
257
|
-
# --------------------------------------------------------------------------
|
|
258
|
-
check_ruby() {
|
|
259
|
-
if command_exists ruby; then
|
|
260
|
-
RUBY_VERSION=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
|
|
261
|
-
print_info "Found Ruby $RUBY_VERSION"
|
|
262
|
-
|
|
263
|
-
if version_ge "$RUBY_VERSION" "2.6.0"; then
|
|
264
|
-
print_success "Ruby $RUBY_VERSION is compatible (>= 2.6.0)"
|
|
265
|
-
return 0
|
|
266
|
-
else
|
|
267
|
-
print_warning "Ruby $RUBY_VERSION is too old (need >= 2.6.0)"
|
|
268
|
-
return 1
|
|
269
|
-
fi
|
|
270
|
-
else
|
|
271
|
-
print_warning "Ruby not found"
|
|
272
|
-
return 1
|
|
273
|
-
fi
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
# --------------------------------------------------------------------------
|
|
277
|
-
# Configure gem source (CN mirror if needed)
|
|
278
|
-
# --------------------------------------------------------------------------
|
|
279
|
-
configure_gem_source() {
|
|
280
|
-
local gemrc="$HOME/.gemrc"
|
|
281
|
-
|
|
282
|
-
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
283
|
-
# CN: point gem source to Aliyun mirror
|
|
284
|
-
if [ -f "$gemrc" ] && grep -q "${CN_RUBYGEMS_URL}" "$gemrc" 2>/dev/null; then
|
|
285
|
-
print_success "gem source already → ${CN_RUBYGEMS_URL}"
|
|
286
|
-
else
|
|
287
|
-
[ -f "$gemrc" ] && mv "$gemrc" "$HOME/.gemrc_clackybak"
|
|
288
|
-
cat > "$gemrc" <<GEMRC
|
|
289
|
-
:sources:
|
|
290
|
-
- ${CN_RUBYGEMS_URL}
|
|
291
|
-
GEMRC
|
|
292
|
-
print_success "gem source → ${CN_RUBYGEMS_URL}"
|
|
293
|
-
fi
|
|
294
|
-
else
|
|
295
|
-
# Global: restore original gemrc if we were the ones who changed it
|
|
296
|
-
if [ -f "$gemrc" ] && grep -q "${CN_RUBYGEMS_URL}" "$gemrc" 2>/dev/null; then
|
|
297
|
-
if [ -f "$HOME/.gemrc_clackybak" ]; then
|
|
298
|
-
mv "$HOME/.gemrc_clackybak" "$gemrc"
|
|
299
|
-
print_info "gem source restored from backup"
|
|
300
|
-
else
|
|
301
|
-
rm "$gemrc"
|
|
302
|
-
print_info "gem source restored to default"
|
|
303
|
-
fi
|
|
304
|
-
fi
|
|
305
|
-
fi
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
# --------------------------------------------------------------------------
|
|
309
|
-
# mise: install (if missing) and optionally activate
|
|
310
|
-
# --------------------------------------------------------------------------
|
|
311
|
-
install_mise() {
|
|
312
|
-
if ! command_exists mise && [ ! -x "$HOME/.local/bin/mise" ]; then
|
|
313
|
-
print_info "Installing mise..."
|
|
314
|
-
if curl -fsSL "$MISE_INSTALL_URL" | sh; then
|
|
315
|
-
# Add mise activation to shell rc
|
|
316
|
-
local mise_init_line='eval "$(~/.local/bin/mise activate '"$CURRENT_SHELL"')"'
|
|
317
|
-
if [ -f "$SHELL_RC" ]; then
|
|
318
|
-
echo "$mise_init_line" >> "$SHELL_RC"
|
|
319
|
-
else
|
|
320
|
-
echo "$mise_init_line" > "$SHELL_RC"
|
|
321
|
-
fi
|
|
322
|
-
print_info "Added mise activation to $SHELL_RC"
|
|
323
|
-
export PATH="$HOME/.local/bin:$PATH"
|
|
324
|
-
eval "$(~/.local/bin/mise activate bash)"
|
|
325
|
-
print_success "mise installed"
|
|
326
|
-
else
|
|
327
|
-
print_error "Failed to install mise"
|
|
328
|
-
return 1
|
|
329
|
-
fi
|
|
330
|
-
else
|
|
331
|
-
export PATH="$HOME/.local/bin:$PATH"
|
|
332
|
-
eval "$(~/.local/bin/mise activate bash)" 2>/dev/null || true
|
|
333
|
-
print_success "mise already installed"
|
|
334
|
-
fi
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
# --------------------------------------------------------------------------
|
|
338
|
-
# Install Ruby via mise (precompiled when CN mirrors active)
|
|
339
|
-
# --------------------------------------------------------------------------
|
|
340
|
-
install_ruby_via_mise() {
|
|
341
|
-
print_info "Installing Ruby via mise ($RUBY_VERSION_SPEC)..."
|
|
342
|
-
|
|
343
|
-
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
344
|
-
~/.local/bin/mise settings ruby.compile=false
|
|
345
|
-
~/.local/bin/mise settings ruby.precompiled_url="$CN_RUBY_PRECOMPILED_URL"
|
|
346
|
-
print_info "Using precompiled Ruby from CN CDN"
|
|
347
|
-
else
|
|
348
|
-
~/.local/bin/mise settings unset ruby.compile >/dev/null 2>&1 || true
|
|
349
|
-
~/.local/bin/mise settings unset ruby.precompiled_url >/dev/null 2>&1 || true
|
|
350
|
-
fi
|
|
351
|
-
|
|
352
|
-
if ~/.local/bin/mise use -g "$RUBY_VERSION_SPEC"; then
|
|
353
|
-
eval "$(~/.local/bin/mise activate bash)"
|
|
354
|
-
print_success "Ruby installed via mise"
|
|
355
|
-
else
|
|
356
|
-
print_error "Failed to install Ruby via mise"
|
|
357
|
-
return 1
|
|
358
|
-
fi
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
# --------------------------------------------------------------------------
|
|
362
|
-
# Ensure Ruby >= 2.6 is available (install if needed)
|
|
363
|
-
# --------------------------------------------------------------------------
|
|
364
|
-
ensure_ruby() {
|
|
365
|
-
print_step "Checking Ruby..."
|
|
366
|
-
|
|
367
|
-
if check_ruby; then
|
|
368
|
-
return 0
|
|
369
|
-
fi
|
|
370
|
-
|
|
371
|
-
# Linux: try apt first (fast, Ubuntu 22.04 ships Ruby 3.0)
|
|
372
|
-
if [ "$OS" = "Linux" ] && ([ "$DISTRO" = "ubuntu" ] || [ "$DISTRO" = "debian" ]); then
|
|
373
|
-
print_info "Installing Ruby via apt..."
|
|
374
|
-
if sudo apt-get install -y ruby ruby-dev 2>/dev/null && check_ruby; then
|
|
375
|
-
return 0
|
|
376
|
-
fi
|
|
377
|
-
print_warning "apt Ruby install failed or version too old, falling back to mise..."
|
|
378
|
-
fi
|
|
379
|
-
|
|
380
|
-
# Fallback: install via mise (compiles from source)
|
|
381
|
-
print_step "Installing Ruby via mise..."
|
|
382
|
-
detect_shell
|
|
383
|
-
install_linux_build_deps
|
|
384
|
-
|
|
385
|
-
if ! install_mise; then
|
|
386
|
-
return 1
|
|
387
|
-
fi
|
|
388
|
-
|
|
389
|
-
if ! install_ruby_via_mise; then
|
|
390
|
-
return 1
|
|
391
|
-
fi
|
|
392
|
-
|
|
393
|
-
# Verify
|
|
394
|
-
if check_ruby; then
|
|
395
|
-
return 0
|
|
396
|
-
else
|
|
397
|
-
print_error "Ruby installation verification failed"
|
|
398
|
-
return 1
|
|
399
|
-
fi
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
# --------------------------------------------------------------------------
|
|
403
|
-
# Linux: configure apt mirror + update (always runs before any apt install)
|
|
404
|
-
# --------------------------------------------------------------------------
|
|
405
|
-
setup_apt_mirror() {
|
|
406
|
-
if [ "$DISTRO" != "ubuntu" ] && [ "$DISTRO" != "debian" ]; then return 0; fi
|
|
407
|
-
|
|
408
|
-
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
409
|
-
print_info "Configuring apt mirror (Aliyun)..."
|
|
410
|
-
local codename="${VERSION_CODENAME:-jammy}"
|
|
411
|
-
local mirror_base="https://mirrors.aliyun.com/ubuntu/"
|
|
412
|
-
local components="main restricted universe multiverse"
|
|
413
|
-
sudo tee /etc/apt/sources.list > /dev/null <<EOF
|
|
414
|
-
deb ${mirror_base} ${codename} ${components}
|
|
415
|
-
deb ${mirror_base} ${codename}-updates ${components}
|
|
416
|
-
deb ${mirror_base} ${codename}-backports ${components}
|
|
417
|
-
deb ${mirror_base} ${codename}-security ${components}
|
|
418
|
-
EOF
|
|
419
|
-
fi
|
|
420
|
-
|
|
421
|
-
sudo apt-get update -qq
|
|
422
|
-
print_success "apt updated"
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
# --------------------------------------------------------------------------
|
|
426
|
-
# Linux: install build deps (only needed when compiling Ruby via mise)
|
|
427
|
-
# --------------------------------------------------------------------------
|
|
428
|
-
install_linux_build_deps() {
|
|
429
|
-
if [ "$DISTRO" != "ubuntu" ] && [ "$DISTRO" != "debian" ]; then return 0; fi
|
|
430
|
-
|
|
431
|
-
print_step "Installing build dependencies..."
|
|
432
|
-
sudo apt-get install -y build-essential libssl-dev libyaml-dev zlib1g-dev libgmp-dev git
|
|
433
|
-
print_success "Build dependencies installed"
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
# --------------------------------------------------------------------------
|
|
437
|
-
# Set GEM_HOME to user directory when system Ruby gem dir is not writable
|
|
438
|
-
# (avoids needing sudo for gem install)
|
|
439
|
-
# --------------------------------------------------------------------------
|
|
440
|
-
setup_gem_home() {
|
|
441
|
-
local gem_dir
|
|
442
|
-
gem_dir=$(gem environment gemdir 2>/dev/null || true)
|
|
443
|
-
|
|
444
|
-
# Gem dir is writable (e.g. mise-managed Ruby) — nothing to do
|
|
445
|
-
if [ -w "$gem_dir" ]; then
|
|
446
|
-
return 0
|
|
447
|
-
fi
|
|
448
|
-
|
|
449
|
-
# System Ruby: redirect gems to ~/.gem/ruby/<api_version>
|
|
450
|
-
local ruby_api
|
|
451
|
-
ruby_api=$(ruby -e 'puts RbConfig::CONFIG["ruby_version"]' 2>/dev/null)
|
|
452
|
-
|
|
453
|
-
export GEM_HOME="$HOME/.gem/ruby/${ruby_api}"
|
|
454
|
-
export GEM_PATH="$HOME/.gem/ruby/${ruby_api}"
|
|
455
|
-
export PATH="$HOME/.local/bin:$HOME/.gem/ruby/${ruby_api}/bin:$PATH"
|
|
456
|
-
|
|
457
|
-
print_info "System Ruby detected — gems will install to ~/.gem/ruby/${ruby_api}"
|
|
458
|
-
|
|
459
|
-
# Persist to shell rc (use $HOME so the line is portable)
|
|
460
|
-
# Also add ~/.local/bin so brand wrapper commands installed there are found
|
|
461
|
-
if [ -n "$SHELL_RC" ] && ! grep -q "GEM_HOME" "$SHELL_RC" 2>/dev/null; then
|
|
462
|
-
{
|
|
463
|
-
echo ""
|
|
464
|
-
echo "# Ruby user gem dir (added by openclacky installer)"
|
|
465
|
-
echo "export GEM_HOME=\"\$HOME/.gem/ruby/${ruby_api}\""
|
|
466
|
-
echo "export GEM_PATH=\"\$HOME/.gem/ruby/${ruby_api}\""
|
|
467
|
-
echo "export PATH=\"\$HOME/.local/bin:\$HOME/.gem/ruby/${ruby_api}/bin:\$PATH\""
|
|
468
|
-
} >> "$SHELL_RC"
|
|
469
|
-
print_info "GEM_HOME written to $SHELL_RC"
|
|
470
|
-
fi
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
# --------------------------------------------------------------------------
|
|
474
|
-
# gem install openclacky
|
|
475
|
-
# --------------------------------------------------------------------------
|
|
476
|
-
install_via_gem() {
|
|
477
|
-
print_step "Installing ${DISPLAY_NAME} via gem..."
|
|
478
|
-
|
|
479
|
-
configure_gem_source
|
|
480
|
-
setup_gem_home
|
|
481
|
-
|
|
482
|
-
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
483
|
-
# CN: download .gem from OSS, install dependencies from Aliyun mirror
|
|
484
|
-
print_info "Fetching latest version from OSS..."
|
|
485
|
-
local cn_version
|
|
486
|
-
cn_version=$(curl -fsSL "$CN_GEM_LATEST_URL" | tr -d '[:space:]')
|
|
487
|
-
print_info "Latest version: ${cn_version}"
|
|
488
|
-
|
|
489
|
-
local gem_url="${CN_GEM_BASE_URL}/openclacky-${cn_version}.gem"
|
|
490
|
-
local gem_file="/tmp/openclacky-${cn_version}.gem"
|
|
491
|
-
print_info "Downloading openclacky-${cn_version}.gem from OSS..."
|
|
492
|
-
curl -fsSL "$gem_url" -o "$gem_file"
|
|
493
|
-
print_info "Installing gem and dependencies from Aliyun mirror..."
|
|
494
|
-
gem install "$gem_file" --no-document --source "$CN_RUBYGEMS_URL"
|
|
495
|
-
else
|
|
496
|
-
print_info "Installing gem and dependencies from RubyGems..."
|
|
497
|
-
gem install openclacky --no-document
|
|
498
|
-
fi
|
|
499
|
-
|
|
500
|
-
if [ $? -eq 0 ]; then
|
|
501
|
-
print_success "${DISPLAY_NAME} installed successfully!"
|
|
502
|
-
return 0
|
|
503
|
-
else
|
|
504
|
-
print_error "gem install failed"
|
|
505
|
-
return 1
|
|
506
|
-
fi
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
# --------------------------------------------------------------------------
|
|
510
|
-
# Parse CLI args
|
|
511
|
-
# --------------------------------------------------------------------------
|
|
512
|
-
parse_args() {
|
|
513
|
-
for arg in "$0" "$@"; do
|
|
514
|
-
case "$arg" in
|
|
515
|
-
--brand-name=*)
|
|
516
|
-
BRAND_NAME="${arg#--brand-name=}"
|
|
517
|
-
;;
|
|
518
|
-
--command=*)
|
|
519
|
-
BRAND_COMMAND="${arg#--command=}"
|
|
520
|
-
;;
|
|
521
|
-
esac
|
|
522
|
-
done
|
|
523
|
-
DISPLAY_NAME="${BRAND_NAME:-OpenClacky}"
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
# --------------------------------------------------------------------------
|
|
527
|
-
# Brand setup
|
|
528
|
-
# --------------------------------------------------------------------------
|
|
529
|
-
setup_brand() {
|
|
530
|
-
[ -z "$BRAND_NAME" ] && return 0
|
|
531
|
-
|
|
532
|
-
local clacky_dir="$HOME/.clacky"
|
|
533
|
-
local brand_file="$clacky_dir/brand.yml"
|
|
534
|
-
mkdir -p "$clacky_dir"
|
|
535
|
-
|
|
536
|
-
print_step "Configuring brand: $BRAND_NAME"
|
|
537
|
-
|
|
538
|
-
cat > "$brand_file" <<YAML
|
|
539
|
-
product_name: "${BRAND_NAME}"
|
|
540
|
-
package_name: "${BRAND_COMMAND}"
|
|
541
|
-
YAML
|
|
542
|
-
print_success "Brand config written to $brand_file"
|
|
543
|
-
|
|
544
|
-
if [ -n "$BRAND_COMMAND" ]; then
|
|
545
|
-
local bin_dir="$HOME/.local/bin"
|
|
546
|
-
mkdir -p "$bin_dir"
|
|
547
|
-
local wrapper="$bin_dir/$BRAND_COMMAND"
|
|
548
|
-
cat > "$wrapper" <<WRAPPER
|
|
549
|
-
#!/bin/sh
|
|
550
|
-
exec openclacky "\$@"
|
|
551
|
-
WRAPPER
|
|
552
|
-
chmod +x "$wrapper"
|
|
553
|
-
print_success "Wrapper installed: $wrapper"
|
|
554
|
-
|
|
555
|
-
case ":$PATH:" in
|
|
556
|
-
*":$bin_dir:"*) ;;
|
|
557
|
-
*)
|
|
558
|
-
print_warning "Add to your shell profile: export PATH=\"\$HOME/.local/bin:\$PATH\""
|
|
559
|
-
;;
|
|
560
|
-
esac
|
|
561
|
-
fi
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
# --------------------------------------------------------------------------
|
|
565
|
-
# Post-install info
|
|
566
|
-
# --------------------------------------------------------------------------
|
|
567
|
-
show_post_install_info() {
|
|
568
|
-
local cmd="${BRAND_COMMAND:-openclacky}"
|
|
569
|
-
|
|
570
|
-
echo ""
|
|
571
|
-
echo -e " ${GREEN}${DISPLAY_NAME} installed successfully!${NC}"
|
|
572
|
-
echo ""
|
|
573
|
-
echo " Reload your shell:"
|
|
574
|
-
echo ""
|
|
575
|
-
echo -e " ${YELLOW}source ${SHELL_RC}${NC}"
|
|
576
|
-
echo ""
|
|
577
|
-
echo -e " ${GREEN}Web UI${NC} (recommended):"
|
|
578
|
-
echo " $cmd server"
|
|
579
|
-
echo " Open http://localhost:7070"
|
|
580
|
-
echo ""
|
|
581
|
-
echo -e " ${GREEN}Terminal${NC}:"
|
|
582
|
-
echo " $cmd"
|
|
583
|
-
echo ""
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
# --------------------------------------------------------------------------
|
|
587
|
-
# Main
|
|
588
|
-
# --------------------------------------------------------------------------
|
|
589
|
-
main() {
|
|
590
|
-
parse_args "$@"
|
|
591
|
-
|
|
592
|
-
echo ""
|
|
593
|
-
echo "${DISPLAY_NAME} Installation"
|
|
594
|
-
echo ""
|
|
595
|
-
|
|
596
|
-
detect_os
|
|
597
|
-
detect_shell
|
|
598
|
-
detect_network_region
|
|
599
|
-
|
|
600
|
-
# Linux: configure apt mirror + update (always runs; build deps deferred to mise fallback)
|
|
601
|
-
if [ "$OS" = "Linux" ]; then
|
|
602
|
-
if [ "$DISTRO" = "ubuntu" ] || [ "$DISTRO" = "debian" ]; then
|
|
603
|
-
setup_apt_mirror
|
|
604
|
-
else
|
|
605
|
-
print_error "Unsupported Linux distribution: $DISTRO"
|
|
606
|
-
print_info "Please install Ruby >= 2.6.0 manually and run: gem install openclacky"
|
|
607
|
-
exit 1
|
|
608
|
-
fi
|
|
609
|
-
elif [ "$OS" != "macOS" ]; then
|
|
610
|
-
print_error "Unsupported OS: $OS"
|
|
611
|
-
print_info "Please install Ruby >= 2.6.0 manually and run: gem install openclacky"
|
|
612
|
-
exit 1
|
|
613
|
-
fi
|
|
614
|
-
|
|
615
|
-
if ! ensure_ruby; then
|
|
616
|
-
print_error "Could not install a compatible Ruby"
|
|
617
|
-
exit 1
|
|
618
|
-
fi
|
|
619
|
-
|
|
620
|
-
if install_via_gem; then
|
|
621
|
-
setup_brand
|
|
622
|
-
show_post_install_info
|
|
623
|
-
exit 0
|
|
624
|
-
else
|
|
625
|
-
print_error "Failed to install ${DISPLAY_NAME}"
|
|
626
|
-
exit 1
|
|
627
|
-
fi
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
main "$@"
|