claude-glm-alt-installer 2.0.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/LICENSE +21 -0
- package/README.md +711 -0
- package/adapters/anthropic-gateway.ts +153 -0
- package/adapters/map.ts +83 -0
- package/adapters/providers/anthropic-pass.ts +64 -0
- package/adapters/providers/gemini.ts +89 -0
- package/adapters/providers/openai.ts +90 -0
- package/adapters/providers/openrouter.ts +98 -0
- package/adapters/sse.ts +62 -0
- package/adapters/types.ts +36 -0
- package/bin/ccx +109 -0
- package/bin/ccx.ps1 +137 -0
- package/bin/cli.js +75 -0
- package/bin/preinstall.js +29 -0
- package/install.ps1 +1018 -0
- package/install.sh +1015 -0
- package/package.json +63 -0
- package/tsconfig.json +14 -0
package/install.sh
ADDED
|
@@ -0,0 +1,1015 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Claude-GLM Server-Friendly Installer
|
|
3
|
+
# Works without sudo, installs to user's home directory
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Test error reporting:
|
|
7
|
+
# CLAUDE_GLM_TEST_ERROR=1 bash <(curl -fsSL https://raw.githubusercontent.com/JoeInnsp23/claude-glm-wrapper/main/install.sh)
|
|
8
|
+
# OR: ./install.sh --test-error
|
|
9
|
+
#
|
|
10
|
+
# Enable debug mode:
|
|
11
|
+
# CLAUDE_GLM_DEBUG=1 bash <(curl -fsSL https://raw.githubusercontent.com/JoeInnsp23/claude-glm-wrapper/main/install.sh)
|
|
12
|
+
# OR: ./install.sh --debug
|
|
13
|
+
|
|
14
|
+
# Parse command-line arguments
|
|
15
|
+
TEST_ERROR=false
|
|
16
|
+
DEBUG=false
|
|
17
|
+
|
|
18
|
+
for arg in "$@"; do
|
|
19
|
+
case $arg in
|
|
20
|
+
--test-error)
|
|
21
|
+
TEST_ERROR=true
|
|
22
|
+
shift
|
|
23
|
+
;;
|
|
24
|
+
--debug)
|
|
25
|
+
DEBUG=true
|
|
26
|
+
shift
|
|
27
|
+
;;
|
|
28
|
+
*)
|
|
29
|
+
# Unknown option
|
|
30
|
+
;;
|
|
31
|
+
esac
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
# Support environment variables for parameters
|
|
35
|
+
if [ "$CLAUDE_GLM_TEST_ERROR" = "1" ] || [ "$CLAUDE_GLM_TEST_ERROR" = "true" ]; then
|
|
36
|
+
TEST_ERROR=true
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if [ "$CLAUDE_GLM_DEBUG" = "1" ] || [ "$CLAUDE_GLM_DEBUG" = "true" ]; then
|
|
40
|
+
DEBUG=true
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Configuration
|
|
44
|
+
USER_BIN_DIR="$HOME/.local/bin"
|
|
45
|
+
GLM_CONFIG_DIR="$HOME/.claude-glm"
|
|
46
|
+
GLM_46_CONFIG_DIR="$HOME/.claude-glm-46"
|
|
47
|
+
GLM_45_CONFIG_DIR="$HOME/.claude-glm-45"
|
|
48
|
+
GLM_FAST_CONFIG_DIR="$HOME/.claude-glm-fast"
|
|
49
|
+
ZAI_API_KEY="YOUR_ZAI_API_KEY_HERE"
|
|
50
|
+
|
|
51
|
+
# Report installation errors to GitHub
|
|
52
|
+
report_error() {
|
|
53
|
+
local error_msg="$1"
|
|
54
|
+
local error_line="$2"
|
|
55
|
+
local error_code="$3"
|
|
56
|
+
|
|
57
|
+
echo ""
|
|
58
|
+
echo "============================================="
|
|
59
|
+
echo "❌ Installation failed!"
|
|
60
|
+
echo "============================================="
|
|
61
|
+
echo ""
|
|
62
|
+
|
|
63
|
+
# Collect system information
|
|
64
|
+
local os_info="$(uname -s) $(uname -r) ($(uname -m))"
|
|
65
|
+
local shell_info="bash $BASH_VERSION"
|
|
66
|
+
local timestamp=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
|
|
67
|
+
|
|
68
|
+
# Sanitize error message (remove API keys)
|
|
69
|
+
local sanitized_error=$(echo "$error_msg" | sed \
|
|
70
|
+
-e 's/ANTHROPIC_AUTH_TOKEN="[^"]*"/ANTHROPIC_AUTH_TOKEN="[REDACTED]"/g' \
|
|
71
|
+
-e 's/ZAI_API_KEY="[^"]*"/ZAI_API_KEY="[REDACTED]"/g' \
|
|
72
|
+
-e 's/\$ZAI_API_KEY="[^"]*"/\$ZAI_API_KEY="[REDACTED]"/g')
|
|
73
|
+
|
|
74
|
+
# Display error details to user
|
|
75
|
+
echo "Error Details:"
|
|
76
|
+
echo "$sanitized_error"
|
|
77
|
+
if [ -n "$error_line" ]; then
|
|
78
|
+
echo "Location: $error_line"
|
|
79
|
+
fi
|
|
80
|
+
echo ""
|
|
81
|
+
|
|
82
|
+
# Ask if user wants to report the error
|
|
83
|
+
echo "Would you like to report this error to GitHub?"
|
|
84
|
+
echo "This will open your browser with a pre-filled issue report."
|
|
85
|
+
read -p "Report error? (y/n): " report_choice
|
|
86
|
+
echo ""
|
|
87
|
+
|
|
88
|
+
if [ "$report_choice" != "y" ] && [ "$report_choice" != "Y" ]; then
|
|
89
|
+
echo "Error not reported. You can get help at:"
|
|
90
|
+
echo " https://github.com/JoeInnsp23/claude-glm-wrapper/issues"
|
|
91
|
+
echo ""
|
|
92
|
+
echo "Press Enter to finish..."
|
|
93
|
+
read
|
|
94
|
+
return
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Get additional context
|
|
98
|
+
local claude_found="No"
|
|
99
|
+
if command -v claude &> /dev/null; then
|
|
100
|
+
claude_found="Yes ($(which claude))"
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Build error report
|
|
104
|
+
local issue_body="## Installation Error (Unix/Linux/macOS)
|
|
105
|
+
|
|
106
|
+
**OS:** $os_info
|
|
107
|
+
**Shell:** $shell_info
|
|
108
|
+
**Timestamp:** $timestamp
|
|
109
|
+
|
|
110
|
+
### Error Details:
|
|
111
|
+
\`\`\`
|
|
112
|
+
$sanitized_error
|
|
113
|
+
\`\`\`
|
|
114
|
+
"
|
|
115
|
+
|
|
116
|
+
if [ -n "$error_line" ]; then
|
|
117
|
+
issue_body+="
|
|
118
|
+
**Error Location:** $error_line
|
|
119
|
+
"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
if [ -n "$error_code" ]; then
|
|
123
|
+
issue_body+="
|
|
124
|
+
**Exit Code:** $error_code
|
|
125
|
+
"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
issue_body+="
|
|
129
|
+
### System Information:
|
|
130
|
+
- Installation Location: $USER_BIN_DIR
|
|
131
|
+
- Claude Code Found: $claude_found
|
|
132
|
+
- PATH: \`$(echo $PATH | sed 's/:/\n /g')\`
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
*This error was automatically reported by the installer. Please add any additional context below.*
|
|
136
|
+
"
|
|
137
|
+
|
|
138
|
+
# URL encode using Python (most compatible)
|
|
139
|
+
local encoded_body=""
|
|
140
|
+
local encoded_title=""
|
|
141
|
+
|
|
142
|
+
if command -v python3 &> /dev/null; then
|
|
143
|
+
encoded_body=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$issue_body'''))" 2>/dev/null)
|
|
144
|
+
encoded_title=$(python3 -c "import urllib.parse; print(urllib.parse.quote('Installation Error: Unix/Linux/macOS'))" 2>/dev/null)
|
|
145
|
+
elif command -v python &> /dev/null; then
|
|
146
|
+
encoded_body=$(python -c "import urllib; print urllib.quote('''$issue_body''')" 2>/dev/null)
|
|
147
|
+
encoded_title=$(python -c "import urllib; print urllib.quote('Installation Error: Unix/Linux/macOS')" 2>/dev/null)
|
|
148
|
+
else
|
|
149
|
+
# Fallback: basic URL encoding with sed
|
|
150
|
+
encoded_body=$(echo "$issue_body" | sed 's/ /%20/g; s/\n/%0A/g')
|
|
151
|
+
encoded_title="Installation%20Error%3A%20Unix%2FLinux%2FmacOS"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
local issue_url="https://github.com/JoeInnsp23/claude-glm-wrapper/issues/new?title=${encoded_title}&body=${encoded_body}&labels=bug,unix,installation"
|
|
155
|
+
|
|
156
|
+
echo "📋 Error details have been prepared for reporting."
|
|
157
|
+
echo ""
|
|
158
|
+
|
|
159
|
+
# Try to open in browser
|
|
160
|
+
local browser_opened=false
|
|
161
|
+
if command -v xdg-open &> /dev/null; then
|
|
162
|
+
if xdg-open "$issue_url" 2>/dev/null; then
|
|
163
|
+
browser_opened=true
|
|
164
|
+
echo "✅ Browser opened with pre-filled error report."
|
|
165
|
+
fi
|
|
166
|
+
elif command -v open &> /dev/null; then
|
|
167
|
+
if open "$issue_url" 2>/dev/null; then
|
|
168
|
+
browser_opened=true
|
|
169
|
+
echo "✅ Browser opened with pre-filled error report."
|
|
170
|
+
fi
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
if [ "$browser_opened" = false ]; then
|
|
174
|
+
echo "⚠️ Could not open browser automatically."
|
|
175
|
+
echo ""
|
|
176
|
+
echo "Please copy and open this URL manually:"
|
|
177
|
+
echo "$issue_url"
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
echo ""
|
|
181
|
+
|
|
182
|
+
# Add instructions and wait for user
|
|
183
|
+
if [ "$browser_opened" = true ]; then
|
|
184
|
+
echo "Please review the error report in your browser and submit the issue."
|
|
185
|
+
echo "After submitting (or if you choose not to), return here."
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
echo ""
|
|
189
|
+
echo "Press Enter to continue..."
|
|
190
|
+
read
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Find all existing wrapper installations
|
|
194
|
+
find_all_installations() {
|
|
195
|
+
local locations=(
|
|
196
|
+
"/usr/local/bin"
|
|
197
|
+
"/usr/bin"
|
|
198
|
+
"$HOME/.local/bin"
|
|
199
|
+
"$HOME/bin"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
local found_files=()
|
|
203
|
+
|
|
204
|
+
for location in "${locations[@]}"; do
|
|
205
|
+
if [ -d "$location" ]; then
|
|
206
|
+
# Find all claude-glm* files in this location
|
|
207
|
+
while IFS= read -r file; do
|
|
208
|
+
if [ -f "$file" ]; then
|
|
209
|
+
found_files+=("$file")
|
|
210
|
+
fi
|
|
211
|
+
done < <(find "$location" -maxdepth 1 -name "claude-glm*" 2>/dev/null)
|
|
212
|
+
fi
|
|
213
|
+
done
|
|
214
|
+
|
|
215
|
+
# Return found files (print them)
|
|
216
|
+
printf '%s\n' "${found_files[@]}"
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
# Clean up old wrapper installations
|
|
220
|
+
cleanup_old_wrappers() {
|
|
221
|
+
local current_location="$USER_BIN_DIR"
|
|
222
|
+
local all_wrappers=($(find_all_installations))
|
|
223
|
+
|
|
224
|
+
if [ ${#all_wrappers[@]} -eq 0 ]; then
|
|
225
|
+
return 0
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
# Separate current location files from old ones
|
|
229
|
+
local old_wrappers=()
|
|
230
|
+
local current_wrappers=()
|
|
231
|
+
|
|
232
|
+
for wrapper in "${all_wrappers[@]}"; do
|
|
233
|
+
if [[ "$wrapper" == "$current_location"* ]]; then
|
|
234
|
+
current_wrappers+=("$wrapper")
|
|
235
|
+
else
|
|
236
|
+
old_wrappers+=("$wrapper")
|
|
237
|
+
fi
|
|
238
|
+
done
|
|
239
|
+
|
|
240
|
+
# If no old wrappers found, nothing to clean
|
|
241
|
+
if [ ${#old_wrappers[@]} -eq 0 ]; then
|
|
242
|
+
return 0
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
echo ""
|
|
246
|
+
echo "🔍 Found existing wrappers in multiple locations:"
|
|
247
|
+
echo ""
|
|
248
|
+
|
|
249
|
+
for wrapper in "${old_wrappers[@]}"; do
|
|
250
|
+
echo " ❌ $wrapper (old location)"
|
|
251
|
+
done
|
|
252
|
+
|
|
253
|
+
if [ ${#current_wrappers[@]} -gt 0 ]; then
|
|
254
|
+
for wrapper in "${current_wrappers[@]}"; do
|
|
255
|
+
echo " ✅ $wrapper (current location)"
|
|
256
|
+
done
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
echo ""
|
|
260
|
+
read -p "Would you like to clean up old installations? (y/n): " cleanup_choice
|
|
261
|
+
|
|
262
|
+
if [[ "$cleanup_choice" == "y" || "$cleanup_choice" == "Y" ]]; then
|
|
263
|
+
echo ""
|
|
264
|
+
echo "Removing old wrappers..."
|
|
265
|
+
for wrapper in "${old_wrappers[@]}"; do
|
|
266
|
+
if rm "$wrapper" 2>/dev/null; then
|
|
267
|
+
echo " ✅ Removed: $wrapper"
|
|
268
|
+
else
|
|
269
|
+
echo " ⚠️ Could not remove: $wrapper (permission denied)"
|
|
270
|
+
fi
|
|
271
|
+
done
|
|
272
|
+
echo ""
|
|
273
|
+
echo "✅ Cleanup complete!"
|
|
274
|
+
else
|
|
275
|
+
echo ""
|
|
276
|
+
echo "⚠️ Skipping cleanup. Old wrappers may interfere with the new installation."
|
|
277
|
+
echo " You may want to manually remove them later."
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
echo ""
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# Detect shell and rc file
|
|
284
|
+
detect_shell_rc() {
|
|
285
|
+
local shell_name=$(basename "$SHELL")
|
|
286
|
+
local rc_file=""
|
|
287
|
+
|
|
288
|
+
case "$shell_name" in
|
|
289
|
+
bash)
|
|
290
|
+
rc_file="$HOME/.bashrc"
|
|
291
|
+
[ -f "$HOME/.bash_profile" ] && rc_file="$HOME/.bash_profile"
|
|
292
|
+
;;
|
|
293
|
+
zsh)
|
|
294
|
+
rc_file="$HOME/.zshrc"
|
|
295
|
+
;;
|
|
296
|
+
ksh)
|
|
297
|
+
rc_file="$HOME/.kshrc"
|
|
298
|
+
[ -f "$HOME/.profile" ] && rc_file="$HOME/.profile"
|
|
299
|
+
;;
|
|
300
|
+
csh|tcsh)
|
|
301
|
+
rc_file="$HOME/.cshrc"
|
|
302
|
+
;;
|
|
303
|
+
*)
|
|
304
|
+
rc_file="$HOME/.profile"
|
|
305
|
+
;;
|
|
306
|
+
esac
|
|
307
|
+
|
|
308
|
+
echo "$rc_file"
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# Ensure user bin directory exists and is in PATH
|
|
312
|
+
setup_user_bin() {
|
|
313
|
+
# Create user bin directory
|
|
314
|
+
mkdir -p "$USER_BIN_DIR"
|
|
315
|
+
|
|
316
|
+
local rc_file=$(detect_shell_rc)
|
|
317
|
+
|
|
318
|
+
# Check if PATH includes user bin
|
|
319
|
+
if [[ ":$PATH:" != *":$USER_BIN_DIR:"* ]]; then
|
|
320
|
+
echo "📝 Adding $USER_BIN_DIR to PATH in $rc_file"
|
|
321
|
+
|
|
322
|
+
# Add to PATH based on shell type
|
|
323
|
+
if [[ "$rc_file" == *".cshrc" ]]; then
|
|
324
|
+
echo "setenv PATH \$PATH:$USER_BIN_DIR" >> "$rc_file"
|
|
325
|
+
else
|
|
326
|
+
echo "export PATH=\"\$PATH:$USER_BIN_DIR\"" >> "$rc_file"
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
echo ""
|
|
330
|
+
echo "⚠️ IMPORTANT: You will need to run this command after installation:"
|
|
331
|
+
echo " source $rc_file"
|
|
332
|
+
echo ""
|
|
333
|
+
fi
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
# Create the standard GLM-4.7 wrapper
|
|
337
|
+
create_claude_glm_wrapper() {
|
|
338
|
+
local wrapper_path="$USER_BIN_DIR/claude-glm"
|
|
339
|
+
|
|
340
|
+
cat > "$wrapper_path" << EOF
|
|
341
|
+
#!/bin/bash
|
|
342
|
+
# Claude-GLM - Claude Code with Z.AI GLM-4.7 (Standard Model)
|
|
343
|
+
|
|
344
|
+
# Set Z.AI environment variables
|
|
345
|
+
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
|
|
346
|
+
export ANTHROPIC_AUTH_TOKEN="$ZAI_API_KEY"
|
|
347
|
+
export ANTHROPIC_MODEL="glm-4.7"
|
|
348
|
+
export ANTHROPIC_SMALL_FAST_MODEL="glm-4.5-air"
|
|
349
|
+
|
|
350
|
+
# Use custom config directory to avoid conflicts
|
|
351
|
+
export CLAUDE_HOME="\$HOME/.claude-glm"
|
|
352
|
+
|
|
353
|
+
# Create config directory if it doesn't exist
|
|
354
|
+
mkdir -p "\$CLAUDE_HOME"
|
|
355
|
+
|
|
356
|
+
# Create/update settings file with GLM configuration
|
|
357
|
+
cat > "\$CLAUDE_HOME/settings.json" << SETTINGS
|
|
358
|
+
{
|
|
359
|
+
"env": {
|
|
360
|
+
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
|
361
|
+
"ANTHROPIC_AUTH_TOKEN": "$ZAI_API_KEY",
|
|
362
|
+
"ANTHROPIC_MODEL": "glm-4.7",
|
|
363
|
+
"ANTHROPIC_SMALL_FAST_MODEL": "glm-4.5-air"
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
SETTINGS
|
|
367
|
+
|
|
368
|
+
# Launch Claude Code with custom config
|
|
369
|
+
echo "🚀 Starting Claude Code with GLM-4.7 (Standard Model)..."
|
|
370
|
+
echo "📁 Config directory: \$CLAUDE_HOME"
|
|
371
|
+
echo ""
|
|
372
|
+
|
|
373
|
+
# Check if claude exists
|
|
374
|
+
if ! command -v claude &> /dev/null; then
|
|
375
|
+
echo "❌ Error: 'claude' command not found!"
|
|
376
|
+
echo "Please ensure Claude Code is installed and in your PATH"
|
|
377
|
+
exit 1
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
# Run the actual claude command
|
|
381
|
+
claude "\$@"
|
|
382
|
+
EOF
|
|
383
|
+
|
|
384
|
+
chmod +x "$wrapper_path"
|
|
385
|
+
echo "✅ Installed claude-glm at $wrapper_path"
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
# Create the GLM-4.6 wrapper
|
|
389
|
+
create_claude_glm_46_wrapper() {
|
|
390
|
+
local wrapper_path="$USER_BIN_DIR/claude-glm-4.6"
|
|
391
|
+
|
|
392
|
+
cat > "$wrapper_path" << EOF
|
|
393
|
+
#!/bin/bash
|
|
394
|
+
# Claude-GLM-4.6 - Claude Code with Z.AI GLM-4.6
|
|
395
|
+
|
|
396
|
+
# Set Z.AI environment variables
|
|
397
|
+
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
|
|
398
|
+
export ANTHROPIC_AUTH_TOKEN="$ZAI_API_KEY"
|
|
399
|
+
export ANTHROPIC_MODEL="glm-4.6"
|
|
400
|
+
export ANTHROPIC_SMALL_FAST_MODEL="glm-4.5-air"
|
|
401
|
+
|
|
402
|
+
# Use custom config directory to avoid conflicts
|
|
403
|
+
export CLAUDE_HOME="\$HOME/.claude-glm-46"
|
|
404
|
+
|
|
405
|
+
# Create config directory if it doesn't exist
|
|
406
|
+
mkdir -p "\$CLAUDE_HOME"
|
|
407
|
+
|
|
408
|
+
# Create/update settings file with GLM configuration
|
|
409
|
+
cat > "\$CLAUDE_HOME/settings.json" << SETTINGS
|
|
410
|
+
{
|
|
411
|
+
"env": {
|
|
412
|
+
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
|
413
|
+
"ANTHROPIC_AUTH_TOKEN": "$ZAI_API_KEY",
|
|
414
|
+
"ANTHROPIC_MODEL": "glm-4.6",
|
|
415
|
+
"ANTHROPIC_SMALL_FAST_MODEL": "glm-4.5-air"
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
SETTINGS
|
|
419
|
+
|
|
420
|
+
# Launch Claude Code with custom config
|
|
421
|
+
echo "🚀 Starting Claude Code with GLM-4.6..."
|
|
422
|
+
echo "📁 Config directory: \$CLAUDE_HOME"
|
|
423
|
+
echo ""
|
|
424
|
+
|
|
425
|
+
# Check if claude exists
|
|
426
|
+
if ! command -v claude &> /dev/null; then
|
|
427
|
+
echo "❌ Error: 'claude' command not found!"
|
|
428
|
+
echo "Please ensure Claude Code is installed and in your PATH"
|
|
429
|
+
exit 1
|
|
430
|
+
fi
|
|
431
|
+
|
|
432
|
+
# Run the actual claude command
|
|
433
|
+
claude "\$@"
|
|
434
|
+
EOF
|
|
435
|
+
|
|
436
|
+
chmod +x "$wrapper_path"
|
|
437
|
+
echo "✅ Installed claude-glm-4.6 at $wrapper_path"
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
# Create the GLM-4.5 wrapper
|
|
441
|
+
create_claude_glm_45_wrapper() {
|
|
442
|
+
local wrapper_path="$USER_BIN_DIR/claude-glm-4.5"
|
|
443
|
+
|
|
444
|
+
cat > "$wrapper_path" << EOF
|
|
445
|
+
#!/bin/bash
|
|
446
|
+
# Claude-GLM-4.5 - Claude Code with Z.AI GLM-4.5
|
|
447
|
+
|
|
448
|
+
# Set Z.AI environment variables
|
|
449
|
+
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
|
|
450
|
+
export ANTHROPIC_AUTH_TOKEN="$ZAI_API_KEY"
|
|
451
|
+
export ANTHROPIC_MODEL="glm-4.5"
|
|
452
|
+
export ANTHROPIC_SMALL_FAST_MODEL="glm-4.5-air"
|
|
453
|
+
|
|
454
|
+
# Use custom config directory to avoid conflicts
|
|
455
|
+
export CLAUDE_HOME="\$HOME/.claude-glm-45"
|
|
456
|
+
|
|
457
|
+
# Create config directory if it doesn't exist
|
|
458
|
+
mkdir -p "\$CLAUDE_HOME"
|
|
459
|
+
|
|
460
|
+
# Create/update settings file with GLM configuration
|
|
461
|
+
cat > "\$CLAUDE_HOME/settings.json" << SETTINGS
|
|
462
|
+
{
|
|
463
|
+
"env": {
|
|
464
|
+
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
|
465
|
+
"ANTHROPIC_AUTH_TOKEN": "$ZAI_API_KEY",
|
|
466
|
+
"ANTHROPIC_MODEL": "glm-4.5",
|
|
467
|
+
"ANTHROPIC_SMALL_FAST_MODEL": "glm-4.5-air"
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
SETTINGS
|
|
471
|
+
|
|
472
|
+
# Launch Claude Code with custom config
|
|
473
|
+
echo "🚀 Starting Claude Code with GLM-4.5..."
|
|
474
|
+
echo "📁 Config directory: \$CLAUDE_HOME"
|
|
475
|
+
echo ""
|
|
476
|
+
|
|
477
|
+
# Check if claude exists
|
|
478
|
+
if ! command -v claude &> /dev/null; then
|
|
479
|
+
echo "❌ Error: 'claude' command not found!"
|
|
480
|
+
echo "Please ensure Claude Code is installed and in your PATH"
|
|
481
|
+
exit 1
|
|
482
|
+
fi
|
|
483
|
+
|
|
484
|
+
# Run the actual claude command
|
|
485
|
+
claude "\$@"
|
|
486
|
+
EOF
|
|
487
|
+
|
|
488
|
+
chmod +x "$wrapper_path"
|
|
489
|
+
echo "✅ Installed claude-glm-4.5 at $wrapper_path"
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
# Create the fast GLM-4.5-Air wrapper
|
|
493
|
+
create_claude_glm_fast_wrapper() {
|
|
494
|
+
local wrapper_path="$USER_BIN_DIR/claude-glm-fast"
|
|
495
|
+
|
|
496
|
+
cat > "$wrapper_path" << EOF
|
|
497
|
+
#!/bin/bash
|
|
498
|
+
# Claude-GLM-Fast - Claude Code with Z.AI GLM-4.5-Air (Fast Model)
|
|
499
|
+
|
|
500
|
+
# Set Z.AI environment variables
|
|
501
|
+
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
|
|
502
|
+
export ANTHROPIC_AUTH_TOKEN="$ZAI_API_KEY"
|
|
503
|
+
export ANTHROPIC_MODEL="glm-4.5-air"
|
|
504
|
+
export ANTHROPIC_SMALL_FAST_MODEL="glm-4.5-air"
|
|
505
|
+
|
|
506
|
+
# Use custom config directory to avoid conflicts
|
|
507
|
+
export CLAUDE_HOME="\$HOME/.claude-glm-fast"
|
|
508
|
+
|
|
509
|
+
# Create config directory if it doesn't exist
|
|
510
|
+
mkdir -p "\$CLAUDE_HOME"
|
|
511
|
+
|
|
512
|
+
# Create/update settings file with GLM-Air configuration
|
|
513
|
+
cat > "\$CLAUDE_HOME/settings.json" << SETTINGS
|
|
514
|
+
{
|
|
515
|
+
"env": {
|
|
516
|
+
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
|
517
|
+
"ANTHROPIC_AUTH_TOKEN": "$ZAI_API_KEY",
|
|
518
|
+
"ANTHROPIC_MODEL": "glm-4.5-air",
|
|
519
|
+
"ANTHROPIC_SMALL_FAST_MODEL": "glm-4.5-air"
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
SETTINGS
|
|
523
|
+
|
|
524
|
+
# Launch Claude Code with custom config
|
|
525
|
+
echo "⚡ Starting Claude Code with GLM-4.5-Air (Fast Model)..."
|
|
526
|
+
echo "📁 Config directory: \$CLAUDE_HOME"
|
|
527
|
+
echo ""
|
|
528
|
+
|
|
529
|
+
# Check if claude exists
|
|
530
|
+
if ! command -v claude &> /dev/null; then
|
|
531
|
+
echo "❌ Error: 'claude' command not found!"
|
|
532
|
+
echo "Please ensure Claude Code is installed and in your PATH"
|
|
533
|
+
exit 1
|
|
534
|
+
fi
|
|
535
|
+
|
|
536
|
+
# Run the actual claude command
|
|
537
|
+
claude "\$@"
|
|
538
|
+
EOF
|
|
539
|
+
|
|
540
|
+
chmod +x "$wrapper_path"
|
|
541
|
+
echo "✅ Installed claude-glm-fast at $wrapper_path"
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
# Create the Anthropic wrapper
|
|
545
|
+
create_claude_anthropic_wrapper() {
|
|
546
|
+
local wrapper_path="$USER_BIN_DIR/claude-anthropic"
|
|
547
|
+
|
|
548
|
+
cat > "$wrapper_path" << 'EOF'
|
|
549
|
+
#!/bin/bash
|
|
550
|
+
# Claude-Anthropic - Claude Code with original Anthropic models
|
|
551
|
+
|
|
552
|
+
# Clear any Z.AI environment variables
|
|
553
|
+
unset ANTHROPIC_BASE_URL
|
|
554
|
+
unset ANTHROPIC_AUTH_TOKEN
|
|
555
|
+
unset ANTHROPIC_MODEL
|
|
556
|
+
unset ANTHROPIC_SMALL_FAST_MODEL
|
|
557
|
+
|
|
558
|
+
# Use default Claude config directory
|
|
559
|
+
unset CLAUDE_HOME
|
|
560
|
+
|
|
561
|
+
echo "🚀 Starting Claude Code with Anthropic Claude models..."
|
|
562
|
+
echo ""
|
|
563
|
+
|
|
564
|
+
# Check if claude exists
|
|
565
|
+
if ! command -v claude &> /dev/null; then
|
|
566
|
+
echo "❌ Error: 'claude' command not found!"
|
|
567
|
+
echo "Please ensure Claude Code is installed and in your PATH"
|
|
568
|
+
exit 1
|
|
569
|
+
fi
|
|
570
|
+
|
|
571
|
+
# Run the actual claude command
|
|
572
|
+
claude "$@"
|
|
573
|
+
EOF
|
|
574
|
+
|
|
575
|
+
chmod +x "$wrapper_path"
|
|
576
|
+
echo "✅ Installed claude-anthropic at $wrapper_path"
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
# Install ccx multi-provider proxy
|
|
580
|
+
install_ccx() {
|
|
581
|
+
echo "🔧 Installing ccx (multi-provider proxy)..."
|
|
582
|
+
|
|
583
|
+
local ccx_home="$HOME/.claude-proxy"
|
|
584
|
+
local wrapper_path="$USER_BIN_DIR/ccx"
|
|
585
|
+
|
|
586
|
+
# Create ccx home directory
|
|
587
|
+
mkdir -p "$ccx_home"
|
|
588
|
+
|
|
589
|
+
# Copy adapters directory from the npm package
|
|
590
|
+
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
591
|
+
|
|
592
|
+
if [ -d "$script_dir/adapters" ]; then
|
|
593
|
+
echo " Copying adapters to $ccx_home/adapters..."
|
|
594
|
+
cp -r "$script_dir/adapters" "$ccx_home/"
|
|
595
|
+
else
|
|
596
|
+
echo "⚠️ Warning: adapters directory not found. Proxy may not work."
|
|
597
|
+
fi
|
|
598
|
+
|
|
599
|
+
# Create ccx wrapper script
|
|
600
|
+
cat > "$wrapper_path" << 'CCXEOF'
|
|
601
|
+
#!/usr/bin/env bash
|
|
602
|
+
set -euo pipefail
|
|
603
|
+
|
|
604
|
+
ROOT_DIR="$HOME/.claude-proxy"
|
|
605
|
+
ENV_FILE="$ROOT_DIR/.env"
|
|
606
|
+
PORT="${CLAUDE_PROXY_PORT:-17870}"
|
|
607
|
+
|
|
608
|
+
# Check if --setup flag is provided
|
|
609
|
+
if [ "${1:-}" = "--setup" ]; then
|
|
610
|
+
echo "Setting up ~/.claude-proxy/.env..."
|
|
611
|
+
mkdir -p "$ROOT_DIR"
|
|
612
|
+
|
|
613
|
+
if [ -f "$ENV_FILE" ]; then
|
|
614
|
+
echo "Existing .env found. Edit it manually at: $ENV_FILE"
|
|
615
|
+
exit 0
|
|
616
|
+
fi
|
|
617
|
+
|
|
618
|
+
cat > "$ENV_FILE" << 'EOF'
|
|
619
|
+
# Claude Proxy Configuration
|
|
620
|
+
# Edit this file to add your API keys
|
|
621
|
+
|
|
622
|
+
# OpenAI (optional)
|
|
623
|
+
OPENAI_API_KEY=
|
|
624
|
+
OPENAI_BASE_URL=https://api.openai.com/v1
|
|
625
|
+
|
|
626
|
+
# OpenRouter (optional)
|
|
627
|
+
OPENROUTER_API_KEY=
|
|
628
|
+
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
|
|
629
|
+
OPENROUTER_REFERER=
|
|
630
|
+
OPENROUTER_TITLE=Claude Code via ccx
|
|
631
|
+
|
|
632
|
+
# Gemini (optional)
|
|
633
|
+
GEMINI_API_KEY=
|
|
634
|
+
GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
|
|
635
|
+
|
|
636
|
+
# Z.AI GLM (optional - for glm: routing)
|
|
637
|
+
GLM_UPSTREAM_URL=https://api.z.ai/api/anthropic
|
|
638
|
+
ZAI_API_KEY=
|
|
639
|
+
|
|
640
|
+
# Anthropic (optional - for anthropic: routing)
|
|
641
|
+
ANTHROPIC_UPSTREAM_URL=https://api.anthropic.com
|
|
642
|
+
ANTHROPIC_API_KEY=
|
|
643
|
+
ANTHROPIC_VERSION=2023-06-01
|
|
644
|
+
|
|
645
|
+
# Proxy settings
|
|
646
|
+
CLAUDE_PROXY_PORT=17870
|
|
647
|
+
EOF
|
|
648
|
+
|
|
649
|
+
echo "✅ Created $ENV_FILE"
|
|
650
|
+
echo ""
|
|
651
|
+
echo "Edit it to add your API keys, then run: ccx"
|
|
652
|
+
echo ""
|
|
653
|
+
echo "Example:"
|
|
654
|
+
echo " nano $ENV_FILE"
|
|
655
|
+
exit 0
|
|
656
|
+
fi
|
|
657
|
+
|
|
658
|
+
# Source the .env file if it exists
|
|
659
|
+
if [ -f "$ENV_FILE" ]; then
|
|
660
|
+
set -a
|
|
661
|
+
source "$ENV_FILE"
|
|
662
|
+
set +a
|
|
663
|
+
fi
|
|
664
|
+
|
|
665
|
+
export ANTHROPIC_BASE_URL="http://127.0.0.1:${PORT}"
|
|
666
|
+
export ANTHROPIC_AUTH_TOKEN="${ANTHROPIC_AUTH_TOKEN:-local-proxy-token}"
|
|
667
|
+
|
|
668
|
+
echo "[ccx] Starting Claude Code with multi-provider proxy..."
|
|
669
|
+
echo "[ccx] Proxy will listen on: ${ANTHROPIC_BASE_URL}"
|
|
670
|
+
|
|
671
|
+
# Start proxy in background
|
|
672
|
+
npx -y tsx "${ROOT_DIR}/adapters/anthropic-gateway.ts" > /tmp/claude-proxy.log 2>&1 &
|
|
673
|
+
PROXY_PID=$!
|
|
674
|
+
|
|
675
|
+
cleanup() {
|
|
676
|
+
echo ""
|
|
677
|
+
echo "[ccx] Shutting down proxy..."
|
|
678
|
+
kill ${PROXY_PID} 2>/dev/null || true
|
|
679
|
+
}
|
|
680
|
+
trap cleanup EXIT INT TERM
|
|
681
|
+
|
|
682
|
+
# Wait for proxy to be ready (health check)
|
|
683
|
+
echo "[ccx] Waiting for proxy to start..."
|
|
684
|
+
for i in {1..30}; do
|
|
685
|
+
if curl -sf "http://127.0.0.1:${PORT}/healthz" >/dev/null 2>&1; then
|
|
686
|
+
echo "[ccx] Proxy ready!"
|
|
687
|
+
break
|
|
688
|
+
fi
|
|
689
|
+
if [ $i -eq 30 ]; then
|
|
690
|
+
echo "❌ Proxy failed to start. Check /tmp/claude-proxy.log"
|
|
691
|
+
cat /tmp/claude-proxy.log
|
|
692
|
+
exit 1
|
|
693
|
+
fi
|
|
694
|
+
sleep 0.5
|
|
695
|
+
done
|
|
696
|
+
|
|
697
|
+
echo ""
|
|
698
|
+
echo "🎯 Available model prefixes:"
|
|
699
|
+
echo " openai:<model> - OpenAI models (gpt-4o, gpt-4o-mini, etc.)"
|
|
700
|
+
echo " openrouter:<model> - OpenRouter models"
|
|
701
|
+
echo " gemini:<model> - Google Gemini models"
|
|
702
|
+
echo " glm:<model> - Z.AI GLM models (glm-4.7, glm-4.6, etc.)"
|
|
703
|
+
echo " anthropic:<model> - Anthropic Claude models"
|
|
704
|
+
echo ""
|
|
705
|
+
echo "💡 Switch models in-session with: /model <prefix>:<model-name>"
|
|
706
|
+
echo ""
|
|
707
|
+
|
|
708
|
+
# Hand off to Claude Code
|
|
709
|
+
exec claude "$@"
|
|
710
|
+
CCXEOF
|
|
711
|
+
|
|
712
|
+
chmod +x "$wrapper_path"
|
|
713
|
+
echo "✅ Installed ccx at $wrapper_path"
|
|
714
|
+
|
|
715
|
+
# Add ccx alias to shell config
|
|
716
|
+
add_ccx_alias
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
# Add ccx alias to shell configuration
|
|
720
|
+
add_ccx_alias() {
|
|
721
|
+
local rc_file=$(detect_shell_rc)
|
|
722
|
+
|
|
723
|
+
if [ -z "$rc_file" ] || [ ! -f "$rc_file" ]; then
|
|
724
|
+
echo "⚠️ Could not detect shell rc file, skipping ccx alias"
|
|
725
|
+
return
|
|
726
|
+
fi
|
|
727
|
+
|
|
728
|
+
# Check if alias already exists
|
|
729
|
+
if grep -q "alias ccx=" "$rc_file" 2>/dev/null; then
|
|
730
|
+
return
|
|
731
|
+
fi
|
|
732
|
+
|
|
733
|
+
# Add ccx alias
|
|
734
|
+
if [[ "$rc_file" == *".cshrc" ]]; then
|
|
735
|
+
echo "alias ccx 'ccx'" >> "$rc_file"
|
|
736
|
+
else
|
|
737
|
+
echo "alias ccx='ccx'" >> "$rc_file"
|
|
738
|
+
fi
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
# Create shell aliases
|
|
742
|
+
create_shell_aliases() {
|
|
743
|
+
local rc_file=$(detect_shell_rc)
|
|
744
|
+
|
|
745
|
+
if [ -z "$rc_file" ] || [ ! -f "$rc_file" ]; then
|
|
746
|
+
echo "⚠️ Could not detect shell rc file, skipping aliases"
|
|
747
|
+
return
|
|
748
|
+
fi
|
|
749
|
+
|
|
750
|
+
# Remove old aliases if they exist
|
|
751
|
+
if grep -q "# Claude Code Model Switcher Aliases" "$rc_file" 2>/dev/null; then
|
|
752
|
+
# Use temp file for compatibility
|
|
753
|
+
grep -v "# Claude Code Model Switcher Aliases" "$rc_file" | \
|
|
754
|
+
grep -v "alias cc=" | \
|
|
755
|
+
grep -v "alias ccg=" | \
|
|
756
|
+
grep -v "alias ccg46=" | \
|
|
757
|
+
grep -v "alias ccg45=" | \
|
|
758
|
+
grep -v "alias ccf=" > "$rc_file.tmp"
|
|
759
|
+
mv "$rc_file.tmp" "$rc_file"
|
|
760
|
+
fi
|
|
761
|
+
|
|
762
|
+
# Add aliases based on shell type
|
|
763
|
+
if [[ "$rc_file" == *".cshrc" ]]; then
|
|
764
|
+
cat >> "$rc_file" << 'EOF'
|
|
765
|
+
|
|
766
|
+
# Claude Code Model Switcher Aliases
|
|
767
|
+
alias cc 'claude'
|
|
768
|
+
alias ccg 'claude-glm'
|
|
769
|
+
alias ccg46 'claude-glm-4.6'
|
|
770
|
+
alias ccg45 'claude-glm-4.5'
|
|
771
|
+
alias ccf 'claude-glm-fast'
|
|
772
|
+
EOF
|
|
773
|
+
else
|
|
774
|
+
cat >> "$rc_file" << 'EOF'
|
|
775
|
+
|
|
776
|
+
# Claude Code Model Switcher Aliases
|
|
777
|
+
alias cc='claude'
|
|
778
|
+
alias ccg='claude-glm'
|
|
779
|
+
alias ccg46='claude-glm-4.6'
|
|
780
|
+
alias ccg45='claude-glm-4.5'
|
|
781
|
+
alias ccf='claude-glm-fast'
|
|
782
|
+
EOF
|
|
783
|
+
fi
|
|
784
|
+
|
|
785
|
+
echo "✅ Added aliases to $rc_file"
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
# Check Claude Code availability
|
|
789
|
+
check_claude_installation() {
|
|
790
|
+
echo "🔍 Checking Claude Code installation..."
|
|
791
|
+
|
|
792
|
+
if command -v claude &> /dev/null; then
|
|
793
|
+
echo "✅ Claude Code found at: $(which claude)"
|
|
794
|
+
return 0
|
|
795
|
+
else
|
|
796
|
+
echo "⚠️ Claude Code not found in PATH"
|
|
797
|
+
echo ""
|
|
798
|
+
echo "Options:"
|
|
799
|
+
echo "1. If Claude Code is installed elsewhere, add it to PATH first"
|
|
800
|
+
echo "2. Install Claude Code from: https://www.anthropic.com/claude-code"
|
|
801
|
+
echo "3. Continue anyway (wrappers will be created but won't work until claude is available)"
|
|
802
|
+
echo ""
|
|
803
|
+
read -p "Continue with installation? (y/n): " continue_choice
|
|
804
|
+
if [[ "$continue_choice" != "y" && "$continue_choice" != "Y" ]]; then
|
|
805
|
+
echo "Installation cancelled."
|
|
806
|
+
exit 1
|
|
807
|
+
fi
|
|
808
|
+
return 1
|
|
809
|
+
fi
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
# Main installation
|
|
813
|
+
main() {
|
|
814
|
+
echo "🔧 Claude-GLM Server-Friendly Installer"
|
|
815
|
+
echo "========================================"
|
|
816
|
+
echo ""
|
|
817
|
+
echo "This installer:"
|
|
818
|
+
echo " • Does NOT require sudo/root access"
|
|
819
|
+
echo " • Installs to: $USER_BIN_DIR"
|
|
820
|
+
echo " • Works on Unix/Linux servers"
|
|
821
|
+
echo ""
|
|
822
|
+
|
|
823
|
+
# Check Claude Code
|
|
824
|
+
check_claude_installation
|
|
825
|
+
|
|
826
|
+
# Setup user bin directory
|
|
827
|
+
setup_user_bin
|
|
828
|
+
|
|
829
|
+
# Clean up old installations from different locations
|
|
830
|
+
cleanup_old_wrappers
|
|
831
|
+
|
|
832
|
+
# Check if already installed
|
|
833
|
+
if [ -f "$USER_BIN_DIR/claude-glm" ] || [ -f "$USER_BIN_DIR/claude-glm-fast" ]; then
|
|
834
|
+
echo ""
|
|
835
|
+
echo "✅ Existing installation detected!"
|
|
836
|
+
echo "1) Update API key only"
|
|
837
|
+
echo "2) Reinstall everything"
|
|
838
|
+
echo "3) Cancel"
|
|
839
|
+
read -p "Choice (1-3): " update_choice
|
|
840
|
+
|
|
841
|
+
case "$update_choice" in
|
|
842
|
+
1)
|
|
843
|
+
read -p "Enter your Z.AI API key: " input_key
|
|
844
|
+
if [ -n "$input_key" ]; then
|
|
845
|
+
ZAI_API_KEY="$input_key"
|
|
846
|
+
create_claude_glm_wrapper
|
|
847
|
+
create_claude_glm_46_wrapper
|
|
848
|
+
create_claude_glm_45_wrapper
|
|
849
|
+
create_claude_glm_fast_wrapper
|
|
850
|
+
echo "✅ API key updated!"
|
|
851
|
+
exit 0
|
|
852
|
+
fi
|
|
853
|
+
;;
|
|
854
|
+
2)
|
|
855
|
+
echo "Reinstalling..."
|
|
856
|
+
;;
|
|
857
|
+
*)
|
|
858
|
+
exit 0
|
|
859
|
+
;;
|
|
860
|
+
esac
|
|
861
|
+
fi
|
|
862
|
+
|
|
863
|
+
# Get API key
|
|
864
|
+
echo ""
|
|
865
|
+
echo "Enter your Z.AI API key (from https://z.ai/manage-apikey/apikey-list)"
|
|
866
|
+
read -p "API Key: " input_key
|
|
867
|
+
|
|
868
|
+
if [ -n "$input_key" ]; then
|
|
869
|
+
ZAI_API_KEY="$input_key"
|
|
870
|
+
echo "✅ API key received (${#input_key} characters)"
|
|
871
|
+
else
|
|
872
|
+
echo "⚠️ No API key provided. Add it manually later to:"
|
|
873
|
+
echo " $USER_BIN_DIR/claude-glm"
|
|
874
|
+
echo " $USER_BIN_DIR/claude-glm-4.6"
|
|
875
|
+
echo " $USER_BIN_DIR/claude-glm-4.5"
|
|
876
|
+
echo " $USER_BIN_DIR/claude-glm-fast"
|
|
877
|
+
fi
|
|
878
|
+
|
|
879
|
+
# Create wrappers
|
|
880
|
+
create_claude_glm_wrapper
|
|
881
|
+
create_claude_glm_46_wrapper
|
|
882
|
+
create_claude_glm_45_wrapper
|
|
883
|
+
create_claude_glm_fast_wrapper
|
|
884
|
+
create_shell_aliases
|
|
885
|
+
|
|
886
|
+
# Ask about ccx installation
|
|
887
|
+
echo ""
|
|
888
|
+
echo "📦 Multi-Provider Proxy (ccx)"
|
|
889
|
+
echo "================================"
|
|
890
|
+
echo "ccx allows you to switch between multiple AI providers in a single session:"
|
|
891
|
+
echo " • OpenAI (GPT-4, GPT-4o, etc.)"
|
|
892
|
+
echo " • OpenRouter (access to many models)"
|
|
893
|
+
echo " • Google Gemini"
|
|
894
|
+
echo " • Z.AI GLM models"
|
|
895
|
+
echo " • Anthropic Claude"
|
|
896
|
+
echo ""
|
|
897
|
+
read -p "Install ccx? (Y/n): " install_ccx_choice
|
|
898
|
+
|
|
899
|
+
if [ "$install_ccx_choice" != "n" ] && [ "$install_ccx_choice" != "N" ]; then
|
|
900
|
+
install_ccx
|
|
901
|
+
echo ""
|
|
902
|
+
echo "✅ ccx installed! Run 'ccx --setup' to configure API keys."
|
|
903
|
+
fi
|
|
904
|
+
|
|
905
|
+
# Final instructions
|
|
906
|
+
local rc_file=$(detect_shell_rc)
|
|
907
|
+
|
|
908
|
+
echo ""
|
|
909
|
+
echo "✅ Installation complete!"
|
|
910
|
+
echo ""
|
|
911
|
+
echo "=========================================="
|
|
912
|
+
echo "⚡ IMPORTANT: Run this command now:"
|
|
913
|
+
echo "=========================================="
|
|
914
|
+
echo ""
|
|
915
|
+
echo " source $rc_file"
|
|
916
|
+
echo ""
|
|
917
|
+
echo "=========================================="
|
|
918
|
+
echo ""
|
|
919
|
+
echo "📝 After sourcing, you can use:"
|
|
920
|
+
echo ""
|
|
921
|
+
echo "Commands:"
|
|
922
|
+
echo " claude-glm - GLM-4.7 (latest)"
|
|
923
|
+
echo " claude-glm-4.6 - GLM-4.6"
|
|
924
|
+
echo " claude-glm-4.5 - GLM-4.5"
|
|
925
|
+
echo " claude-glm-fast - GLM-4.5-Air (fast)"
|
|
926
|
+
if [ "$install_ccx_choice" != "n" ] && [ "$install_ccx_choice" != "N" ]; then
|
|
927
|
+
echo " ccx - Multi-provider proxy (switch models in-session)"
|
|
928
|
+
fi
|
|
929
|
+
echo ""
|
|
930
|
+
echo "Aliases:"
|
|
931
|
+
echo " cc - claude (regular Claude)"
|
|
932
|
+
echo " ccg - claude-glm (GLM-4.7)"
|
|
933
|
+
echo " ccg46 - claude-glm-4.6 (GLM-4.6)"
|
|
934
|
+
echo " ccg45 - claude-glm-4.5 (GLM-4.5)"
|
|
935
|
+
echo " ccf - claude-glm-fast"
|
|
936
|
+
if [ "$install_ccx_choice" != "n" ] && [ "$install_ccx_choice" != "N" ]; then
|
|
937
|
+
echo " ccx - Multi-provider proxy"
|
|
938
|
+
fi
|
|
939
|
+
echo ""
|
|
940
|
+
|
|
941
|
+
if [ "$ZAI_API_KEY" = "YOUR_ZAI_API_KEY_HERE" ]; then
|
|
942
|
+
echo "⚠️ Don't forget to add your API key to:"
|
|
943
|
+
echo " $USER_BIN_DIR/claude-glm"
|
|
944
|
+
echo " $USER_BIN_DIR/claude-glm-4.6"
|
|
945
|
+
echo " $USER_BIN_DIR/claude-glm-4.5"
|
|
946
|
+
echo " $USER_BIN_DIR/claude-glm-fast"
|
|
947
|
+
fi
|
|
948
|
+
|
|
949
|
+
echo ""
|
|
950
|
+
echo "📁 Installation location: $USER_BIN_DIR"
|
|
951
|
+
echo "📁 Config directories: ~/.claude-glm, ~/.claude-glm-46, ~/.claude-glm-45, ~/.claude-glm-fast"
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
# Error handler
|
|
955
|
+
handle_error() {
|
|
956
|
+
local exit_code=$?
|
|
957
|
+
local line_number=$1
|
|
958
|
+
local bash_command="$2"
|
|
959
|
+
|
|
960
|
+
# Capture the error details
|
|
961
|
+
local error_msg="Command failed with exit code $exit_code"
|
|
962
|
+
if [ -n "$bash_command" ]; then
|
|
963
|
+
error_msg="$error_msg: $bash_command"
|
|
964
|
+
fi
|
|
965
|
+
|
|
966
|
+
local error_location="Line $line_number in install.sh"
|
|
967
|
+
|
|
968
|
+
report_error "$error_msg" "$error_location" "$exit_code"
|
|
969
|
+
|
|
970
|
+
# Give user time to read any final messages before stopping
|
|
971
|
+
echo ""
|
|
972
|
+
echo "Installation terminated due to error."
|
|
973
|
+
echo "Press Enter to finish (window will remain open)..."
|
|
974
|
+
read
|
|
975
|
+
# Return to stop script execution without closing terminal
|
|
976
|
+
return
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
# Test error functionality if requested
|
|
980
|
+
if [ "$TEST_ERROR" = true ]; then
|
|
981
|
+
echo "🔍 TEST: Testing error reporting functionality..."
|
|
982
|
+
echo ""
|
|
983
|
+
|
|
984
|
+
# Show how script was invoked
|
|
985
|
+
if [ -n "$CLAUDE_GLM_TEST_ERROR" ]; then
|
|
986
|
+
echo " (Invoked via environment variable)"
|
|
987
|
+
fi
|
|
988
|
+
echo ""
|
|
989
|
+
|
|
990
|
+
# Create a test error
|
|
991
|
+
local test_error_message="This is a test error to verify error reporting works correctly"
|
|
992
|
+
local test_error_line="Test mode - no actual error"
|
|
993
|
+
|
|
994
|
+
report_error "$test_error_message" "$test_error_line" "0"
|
|
995
|
+
|
|
996
|
+
echo "✅ Test complete. If a browser window opened, error reporting is working!"
|
|
997
|
+
echo ""
|
|
998
|
+
echo "To run normal installation, use:"
|
|
999
|
+
echo " curl -fsSL https://raw.githubusercontent.com/JoeInnsp23/claude-glm-wrapper/main/install.sh | bash"
|
|
1000
|
+
echo ""
|
|
1001
|
+
echo "Press Enter to finish (window will remain open)..."
|
|
1002
|
+
read
|
|
1003
|
+
# Script ends naturally here - terminal stays open
|
|
1004
|
+
exit 0
|
|
1005
|
+
fi
|
|
1006
|
+
|
|
1007
|
+
# Set up error handling
|
|
1008
|
+
set -eE # Exit on error, inherit ERR trap in functions
|
|
1009
|
+
trap 'handle_error ${LINENO} "$BASH_COMMAND"' ERR
|
|
1010
|
+
|
|
1011
|
+
# Only run installation if not in test mode
|
|
1012
|
+
if [ "$TEST_ERROR" != true ]; then
|
|
1013
|
+
# Run installation
|
|
1014
|
+
main "$@"
|
|
1015
|
+
fi
|