@anh3d0nic/qwen-code-termux-ice 16.0.4 → 16.0.7
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/bin/qwen-ice +25 -5
- package/package.json +6 -5
- package/scripts/build.js +88 -0
- package/scripts/build_package.js +37 -0
- package/scripts/build_sandbox.js +174 -0
- package/scripts/build_vscode_companion.js +30 -0
- package/scripts/check-build-status.js +148 -0
- package/scripts/check-i18n.ts +462 -0
- package/scripts/check-lockfile.js +74 -0
- package/scripts/clean.js +59 -0
- package/scripts/copy_bundle_assets.js +90 -0
- package/scripts/copy_files.js +86 -0
- package/scripts/create_alias.sh +39 -0
- package/scripts/dev.js +109 -0
- package/scripts/esbuild-shims.js +29 -0
- package/scripts/generate-git-commit-info.js +71 -0
- package/scripts/generate-settings-schema.ts +146 -0
- package/scripts/get-release-version.js +411 -0
- package/scripts/ice-mobile.js +5 -0
- package/scripts/ice-session.js +6 -0
- package/scripts/ice-skills.js +31 -0
- package/scripts/ice-teams.js +34 -0
- package/scripts/ice-v10.js +276 -0
- package/scripts/ice-v11.js +276 -0
- package/scripts/ice-v12.js +568 -0
- package/scripts/ice-v13.js +824 -0
- package/scripts/ice-v14.js +1059 -0
- package/scripts/ice-v15.js +1501 -0
- package/scripts/ice-v2.js +26 -0
- package/scripts/ice-v3-core.js +261 -0
- package/scripts/ice-v3.js +46 -0
- package/scripts/ice-v4.js +657 -0
- package/scripts/ice-v5.js +371 -0
- package/scripts/ice-v6.js +305 -0
- package/scripts/ice-v7.js +291 -0
- package/scripts/ice-v8.js +550 -0
- package/scripts/ice-v9.js +546 -0
- package/scripts/install-ice.sh +70 -0
- package/scripts/install.sh +136 -0
- package/scripts/installation/INSTALLATION_GUIDE.md +250 -0
- package/scripts/installation/install-qwen-with-source.bat +302 -0
- package/scripts/installation/install-qwen-with-source.sh +570 -0
- package/scripts/lint.js +205 -0
- package/scripts/local_telemetry.js +219 -0
- package/scripts/postinstall.cjs +235 -0
- package/scripts/pre-commit.js +22 -0
- package/scripts/prepare-package.js +186 -0
- package/scripts/prepare-termux.cjs +26 -0
- package/scripts/sandbox_command.js +128 -0
- package/scripts/start.js +86 -0
- package/scripts/telemetry.js +85 -0
- package/scripts/telemetry_gcp.js +188 -0
- package/scripts/telemetry_utils.js +450 -0
- package/scripts/test-v10.js +18 -0
- package/scripts/test-v11.js +18 -0
- package/scripts/test-v12.js +18 -0
- package/scripts/test-v13.js +18 -0
- package/scripts/test-v14.js +18 -0
- package/scripts/test-v3.js +47 -0
- package/scripts/test-v4.js +47 -0
- package/scripts/test-v6.js +59 -0
- package/scripts/test-v8.js +42 -0
- package/scripts/test-v9.js +18 -0
- package/scripts/test-windows-paths.js +51 -0
- package/scripts/tests/get-release-version.test.js +186 -0
- package/scripts/tests/test-setup.ts +12 -0
- package/scripts/tests/vitest.config.ts +26 -0
- package/scripts/unused-keys-only-in-locales.json +62 -0
- package/scripts/version.js +112 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Qwen Code Installation Script
|
|
4
|
+
# This script installs Node.js (via NVM) and Qwen Code CLI
|
|
5
|
+
# Supports Linux and macOS
|
|
6
|
+
#
|
|
7
|
+
# Usage: install-qwen-with-source.sh --source [github|npm|internal|local-build]
|
|
8
|
+
# install-qwen-with-source.sh -s [github|npm|internal|local-build]
|
|
9
|
+
|
|
10
|
+
# Re-execute with bash if running with sh or other shells
|
|
11
|
+
# This block must use POSIX-compliant syntax ([ not [[) since it runs before we know bash is available
|
|
12
|
+
if [ -z "${BASH_VERSION}" ] && [ -z "${__QWEN_INSTALL_REEXEC:-}" ]; then
|
|
13
|
+
# Check if we're in a git hook environment
|
|
14
|
+
case "${0}" in
|
|
15
|
+
*.git/hooks/*) export __QWEN_IN_GIT_HOOK=1 ;;
|
|
16
|
+
esac
|
|
17
|
+
if [ -n "${GIT_DIR:-}" ]; then
|
|
18
|
+
export __QWEN_IN_GIT_HOOK=1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Try to find bash
|
|
22
|
+
if command -v bash >/dev/null 2>&1; then
|
|
23
|
+
export __QWEN_INSTALL_REEXEC=1
|
|
24
|
+
# Re-exec with bash, preserving all arguments
|
|
25
|
+
exec bash -- "${0}" "$@"
|
|
26
|
+
else
|
|
27
|
+
echo "Error: This script requires bash. Please install bash first."
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Enable strict mode (bash-specific options)
|
|
33
|
+
# pipefail requires bash 3+; check before setting
|
|
34
|
+
if [ -n "${BASH_VERSION:-}" ]; then
|
|
35
|
+
# shellcheck disable=SC3040
|
|
36
|
+
set -eo pipefail
|
|
37
|
+
else
|
|
38
|
+
set -e
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# ============================================
|
|
42
|
+
# Color definitions
|
|
43
|
+
# ============================================
|
|
44
|
+
RED='\033[0;31m'
|
|
45
|
+
GREEN='\033[0;32m'
|
|
46
|
+
YELLOW='\033[1;33m'
|
|
47
|
+
BLUE='\033[0;34m'
|
|
48
|
+
NC='\033[0m' # No Color
|
|
49
|
+
|
|
50
|
+
# ============================================
|
|
51
|
+
# Log functions
|
|
52
|
+
# ============================================
|
|
53
|
+
log_info() {
|
|
54
|
+
echo -e "${BLUE}ℹ️ $1${NC}"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
log_success() {
|
|
58
|
+
echo -e "${GREEN}✅ $1${NC}"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
log_warning() {
|
|
62
|
+
echo -e "${YELLOW}⚠️ $1${NC}"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
log_error() {
|
|
66
|
+
echo -e "${RED}❌ $1${NC}"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# ============================================
|
|
70
|
+
# Utility functions
|
|
71
|
+
# ============================================
|
|
72
|
+
command_exists() {
|
|
73
|
+
command -v "$1" >/dev/null 2>&1
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get_shell_profile() {
|
|
77
|
+
local current_shell
|
|
78
|
+
current_shell=$(basename "${SHELL}")
|
|
79
|
+
case "${current_shell}" in
|
|
80
|
+
bash)
|
|
81
|
+
echo "${HOME}/.bashrc"
|
|
82
|
+
;;
|
|
83
|
+
zsh)
|
|
84
|
+
echo "${HOME}/.zshrc"
|
|
85
|
+
;;
|
|
86
|
+
fish)
|
|
87
|
+
# Fish uses its own syntax; bash/zsh export statements are not compatible.
|
|
88
|
+
# Return empty string to signal callers to skip automatic profile writes.
|
|
89
|
+
echo ""
|
|
90
|
+
;;
|
|
91
|
+
*)
|
|
92
|
+
echo "${HOME}/.profile"
|
|
93
|
+
;;
|
|
94
|
+
esac
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# ============================================
|
|
98
|
+
# Parse command line arguments
|
|
99
|
+
# ============================================
|
|
100
|
+
SOURCE="unknown"
|
|
101
|
+
while [[ $# -gt 0 ]]; do
|
|
102
|
+
case $1 in
|
|
103
|
+
-s|--source)
|
|
104
|
+
if [[ -z "$2" ]] || [[ "$2" == -* ]]; then
|
|
105
|
+
log_error "--source requires a value"
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
SOURCE="$2"
|
|
109
|
+
shift 2
|
|
110
|
+
;;
|
|
111
|
+
-h|--help)
|
|
112
|
+
echo "Usage: $0 [OPTIONS]"
|
|
113
|
+
echo ""
|
|
114
|
+
echo "Options:"
|
|
115
|
+
echo " -s, --source SOURCE Specify the installation source (e.g., github, npm, internal)"
|
|
116
|
+
echo " -h, --help Show this help message"
|
|
117
|
+
echo ""
|
|
118
|
+
exit 0
|
|
119
|
+
;;
|
|
120
|
+
*)
|
|
121
|
+
log_error "Unknown option: $1"
|
|
122
|
+
exit 1
|
|
123
|
+
;;
|
|
124
|
+
esac
|
|
125
|
+
done
|
|
126
|
+
|
|
127
|
+
# ============================================
|
|
128
|
+
# Print header
|
|
129
|
+
# ============================================
|
|
130
|
+
echo "=========================================="
|
|
131
|
+
echo " Qwen Code Installation Script"
|
|
132
|
+
echo "=========================================="
|
|
133
|
+
echo ""
|
|
134
|
+
log_info "System: $(uname -s) $(uname -r)" || true
|
|
135
|
+
log_info "Shell: $(basename "${SHELL}")"
|
|
136
|
+
echo ""
|
|
137
|
+
|
|
138
|
+
# ============================================
|
|
139
|
+
# Ensure download tool is available
|
|
140
|
+
# ============================================
|
|
141
|
+
ensure_download_tool() {
|
|
142
|
+
if command_exists curl; then
|
|
143
|
+
DOWNLOAD_CMD="curl"
|
|
144
|
+
DOWNLOAD_ARGS="-fsSL"
|
|
145
|
+
return 0
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
if command_exists wget; then
|
|
149
|
+
DOWNLOAD_CMD="wget"
|
|
150
|
+
DOWNLOAD_ARGS="-qO -"
|
|
151
|
+
return 0
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
log_error "Neither curl nor wget found"
|
|
155
|
+
log_info "Please install curl or wget manually:"
|
|
156
|
+
echo " - macOS: brew install curl"
|
|
157
|
+
echo " - Ubuntu/Debian: sudo apt-get install curl"
|
|
158
|
+
echo " - CentOS/RHEL: sudo yum install curl"
|
|
159
|
+
exit 1
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# ============================================
|
|
163
|
+
# Clean npm configuration conflicts
|
|
164
|
+
# ============================================
|
|
165
|
+
clean_npmrc_conflict() {
|
|
166
|
+
local npmrc="${HOME}/.npmrc"
|
|
167
|
+
if [[ -f "${npmrc}" ]]; then
|
|
168
|
+
# Only clean if conflicting entries actually exist
|
|
169
|
+
if grep -Eq '^(prefix|globalconfig) *= *' "${npmrc}" 2>/dev/null; then
|
|
170
|
+
log_info "Cleaning npmrc conflicts..."
|
|
171
|
+
# Backup original npmrc before modifying
|
|
172
|
+
cp -f "${npmrc}" "${npmrc}.bak"
|
|
173
|
+
log_info "Backed up original .npmrc to ${npmrc}.bak"
|
|
174
|
+
grep -Ev '^(prefix|globalconfig) *= *' "${npmrc}.bak" > "${npmrc}.tmp" || true
|
|
175
|
+
mv -f "${npmrc}.tmp" "${npmrc}" || true
|
|
176
|
+
log_success "Removed conflicting prefix/globalconfig entries from .npmrc"
|
|
177
|
+
fi
|
|
178
|
+
fi
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# ============================================
|
|
182
|
+
# Install NVM
|
|
183
|
+
# ============================================
|
|
184
|
+
install_nvm() {
|
|
185
|
+
local NVM_DIR="${NVM_DIR:-${HOME}/.nvm}"
|
|
186
|
+
local NVM_VERSION="${NVM_VERSION:-v0.40.3}"
|
|
187
|
+
|
|
188
|
+
if [[ -s "${NVM_DIR}/nvm.sh" ]]; then
|
|
189
|
+
log_info "NVM is already installed at ${NVM_DIR}"
|
|
190
|
+
return 0
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
log_info "Installing NVM ${NVM_VERSION}..."
|
|
194
|
+
|
|
195
|
+
# Download and install NVM from Aliyun OSS
|
|
196
|
+
# Use temporary file instead of pipe to avoid potential subshell issues
|
|
197
|
+
local NVM_INSTALL_TEMP
|
|
198
|
+
NVM_INSTALL_TEMP=$(mktemp)
|
|
199
|
+
if "${DOWNLOAD_CMD}" "${DOWNLOAD_ARGS}" "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install_nvm.sh" > "${NVM_INSTALL_TEMP}"; then
|
|
200
|
+
# Run the script in current shell environment
|
|
201
|
+
# shellcheck source=/dev/null
|
|
202
|
+
. "${NVM_INSTALL_TEMP}"
|
|
203
|
+
rm -f "${NVM_INSTALL_TEMP}"
|
|
204
|
+
log_success "NVM installed successfully"
|
|
205
|
+
else
|
|
206
|
+
rm -f "${NVM_INSTALL_TEMP}"
|
|
207
|
+
log_error "Failed to install NVM"
|
|
208
|
+
log_info "Please install NVM manually: https://github.com/nvm-sh/nvm#install--update-script"
|
|
209
|
+
exit 1
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# Configure shell profile
|
|
213
|
+
local PROFILE_FILE
|
|
214
|
+
PROFILE_FILE=$(get_shell_profile)
|
|
215
|
+
|
|
216
|
+
# Fish shell returns empty string from get_shell_profile because export/source
|
|
217
|
+
# syntax is incompatible with fish. Skip automatic profile writes for fish users.
|
|
218
|
+
if [[ -z "${PROFILE_FILE}" ]]; then
|
|
219
|
+
log_warning "Fish shell detected: automatic shell profile configuration is not supported."
|
|
220
|
+
log_info "Please add NVM configuration manually. See: https://github.com/nvm-sh/nvm#fish"
|
|
221
|
+
# Check if profile file is writable
|
|
222
|
+
elif [[ -f "${PROFILE_FILE}" ]] && [[ ! -w "${PROFILE_FILE}" ]]; then
|
|
223
|
+
log_warning "Cannot write to ${PROFILE_FILE} (permission denied)"
|
|
224
|
+
log_info "Skipping shell profile configuration"
|
|
225
|
+
log_info "You may need to manually add NVM configuration to your shell profile"
|
|
226
|
+
elif ! grep -q 'NVM_DIR' "${PROFILE_FILE}" 2>/dev/null; then
|
|
227
|
+
# shellcheck disable=SC2016
|
|
228
|
+
# The following echo statements intentionally use single quotes to write literal strings
|
|
229
|
+
{
|
|
230
|
+
echo ""
|
|
231
|
+
echo "# NVM configuration (added by Qwen Code installer)"
|
|
232
|
+
echo "export NVM_DIR=\"\$HOME/.nvm\""
|
|
233
|
+
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"'
|
|
234
|
+
echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"'
|
|
235
|
+
} >> "${PROFILE_FILE}" 2>/dev/null || {
|
|
236
|
+
log_warning "Failed to write to ${PROFILE_FILE}"
|
|
237
|
+
log_info "Skipping shell profile configuration"
|
|
238
|
+
return 0
|
|
239
|
+
}
|
|
240
|
+
log_info "Added NVM config to ${PROFILE_FILE}"
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Load NVM for current session
|
|
244
|
+
export NVM_DIR="${NVM_DIR}"
|
|
245
|
+
# shellcheck source=/dev/null
|
|
246
|
+
[[ -s "${NVM_DIR}/nvm.sh" ]] && \. "${NVM_DIR}/nvm.sh"
|
|
247
|
+
|
|
248
|
+
log_success "NVM configured successfully"
|
|
249
|
+
return 0
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
# ============================================
|
|
253
|
+
# Install Node.js via NVM
|
|
254
|
+
# ============================================
|
|
255
|
+
install_nodejs_with_nvm() {
|
|
256
|
+
local NODE_VERSION="${NODE_VERSION:-20}"
|
|
257
|
+
local NVM_DIR="${NVM_DIR:-${HOME}/.nvm}"
|
|
258
|
+
|
|
259
|
+
# Ensure NVM is loaded
|
|
260
|
+
export NVM_DIR="${NVM_DIR}"
|
|
261
|
+
# shellcheck source=/dev/null
|
|
262
|
+
[[ -s "${NVM_DIR}/nvm.sh" ]] && \. "${NVM_DIR}/nvm.sh"
|
|
263
|
+
|
|
264
|
+
if ! command_exists nvm; then
|
|
265
|
+
log_error "NVM not loaded properly"
|
|
266
|
+
return 1
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
# Set Node.js mirror source for faster downloads in China
|
|
270
|
+
export NVM_NODEJS_ORG_MIRROR="https://npmmirror.com/mirrors/node"
|
|
271
|
+
|
|
272
|
+
# Install Node.js
|
|
273
|
+
log_info "Installing Node.js v${NODE_VERSION}..."
|
|
274
|
+
if nvm install "${NODE_VERSION}"; then
|
|
275
|
+
nvm alias default "${NODE_VERSION}" || true
|
|
276
|
+
nvm use default || true
|
|
277
|
+
log_success "Node.js v${NODE_VERSION} installed successfully"
|
|
278
|
+
|
|
279
|
+
# Verify installation
|
|
280
|
+
log_info "Node.js version: $(node -v)" || true
|
|
281
|
+
log_info "npm version: $(npm -v)" || true
|
|
282
|
+
|
|
283
|
+
return 0
|
|
284
|
+
else
|
|
285
|
+
log_error "Failed to install Node.js"
|
|
286
|
+
return 1
|
|
287
|
+
fi
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
# ============================================
|
|
291
|
+
# Check Node.js version
|
|
292
|
+
# ============================================
|
|
293
|
+
check_node_version() {
|
|
294
|
+
if ! command_exists node; then
|
|
295
|
+
return 1
|
|
296
|
+
fi
|
|
297
|
+
|
|
298
|
+
local current_version
|
|
299
|
+
current_version=$(node -v | sed 's/v//')
|
|
300
|
+
local major_version
|
|
301
|
+
major_version=$(echo "${current_version}" | cut -d. -f1 | sed 's/[^0-9]//g')
|
|
302
|
+
|
|
303
|
+
# Handle cases where major_version is empty or non-numeric
|
|
304
|
+
if [[ -z "${major_version}" ]]; then
|
|
305
|
+
log_warning "Unable to determine Node.js version from: $(node -v)"
|
|
306
|
+
return 1
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
if [[ "${major_version}" -ge 20 ]]; then
|
|
310
|
+
log_success "Node.js v${current_version} is already installed (>= 20)"
|
|
311
|
+
return 0
|
|
312
|
+
else
|
|
313
|
+
log_warning "Node.js v${current_version} is installed but version < 20"
|
|
314
|
+
return 1
|
|
315
|
+
fi
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
# ============================================
|
|
319
|
+
# Install Node.js
|
|
320
|
+
# ============================================
|
|
321
|
+
install_nodejs() {
|
|
322
|
+
local platform
|
|
323
|
+
platform=$(uname -s)
|
|
324
|
+
|
|
325
|
+
case "${platform}" in
|
|
326
|
+
Linux|Darwin)
|
|
327
|
+
log_info "Installing Node.js on ${platform}..."
|
|
328
|
+
|
|
329
|
+
# Install NVM
|
|
330
|
+
if ! install_nvm; then
|
|
331
|
+
log_error "Failed to install NVM"
|
|
332
|
+
return 1
|
|
333
|
+
fi
|
|
334
|
+
|
|
335
|
+
# Load NVM
|
|
336
|
+
export NVM_DIR="${HOME}/.nvm"
|
|
337
|
+
# shellcheck source=/dev/null
|
|
338
|
+
[[ -s "${NVM_DIR}/nvm.sh" ]] && \. "${NVM_DIR}/nvm.sh"
|
|
339
|
+
|
|
340
|
+
# Install Node.js
|
|
341
|
+
if ! install_nodejs_with_nvm; then
|
|
342
|
+
log_error "Failed to install Node.js"
|
|
343
|
+
return 1
|
|
344
|
+
fi
|
|
345
|
+
;;
|
|
346
|
+
MINGW*|CYGWIN*|MSYS*)
|
|
347
|
+
log_error "Windows platform detected. Please use Windows installer or WSL."
|
|
348
|
+
log_info "Visit: https://nodejs.org/en/download/"
|
|
349
|
+
exit 1
|
|
350
|
+
;;
|
|
351
|
+
*)
|
|
352
|
+
log_error "Unsupported platform: ${platform}"
|
|
353
|
+
exit 1
|
|
354
|
+
;;
|
|
355
|
+
esac
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
# ============================================
|
|
359
|
+
# Check and install Node.js
|
|
360
|
+
# ============================================
|
|
361
|
+
check_and_install_nodejs() {
|
|
362
|
+
if check_node_version; then
|
|
363
|
+
log_info "Using existing Node.js installation"
|
|
364
|
+
clean_npmrc_conflict
|
|
365
|
+
else
|
|
366
|
+
log_warning "Installing or upgrading Node.js..."
|
|
367
|
+
install_nodejs
|
|
368
|
+
fi
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
# ============================================
|
|
372
|
+
# Fix npm permissions (without using sudo)
|
|
373
|
+
# ============================================
|
|
374
|
+
fix_npm_permissions() {
|
|
375
|
+
log_info "Checking npm permissions..."
|
|
376
|
+
|
|
377
|
+
local NPM_GLOBAL_DIR
|
|
378
|
+
NPM_GLOBAL_DIR=$(npm config get prefix 2>/dev/null) || true
|
|
379
|
+
|
|
380
|
+
# Determine whether we need to fall back to ~/.npm-global:
|
|
381
|
+
# 1. prefix is empty or contains an error string
|
|
382
|
+
# 2. prefix is a system directory (would break sudo setuid binaries)
|
|
383
|
+
# 3. prefix directory is not writable
|
|
384
|
+
local use_user_dir=false
|
|
385
|
+
|
|
386
|
+
if [[ -z "${NPM_GLOBAL_DIR}" ]] || [[ "${NPM_GLOBAL_DIR}" == *"error"* ]]; then
|
|
387
|
+
log_info "npm prefix is unset or invalid, switching to user directory"
|
|
388
|
+
use_user_dir=true
|
|
389
|
+
else
|
|
390
|
+
# SAFETY CHECK: Never use system directories
|
|
391
|
+
case "${NPM_GLOBAL_DIR}" in
|
|
392
|
+
/|/usr|/usr/local|/bin|/sbin|/lib|/lib64|/opt|/snap|/var|/etc)
|
|
393
|
+
log_warning "npm prefix is a system directory (${NPM_GLOBAL_DIR}), switching to user directory to avoid breaking system binaries."
|
|
394
|
+
use_user_dir=true
|
|
395
|
+
;;
|
|
396
|
+
esac
|
|
397
|
+
fi
|
|
398
|
+
|
|
399
|
+
if [[ "${use_user_dir}" == false ]] && [[ ! -w "${NPM_GLOBAL_DIR}" ]]; then
|
|
400
|
+
log_warning "npm global directory is not writable: ${NPM_GLOBAL_DIR}, switching to user directory."
|
|
401
|
+
use_user_dir=true
|
|
402
|
+
fi
|
|
403
|
+
|
|
404
|
+
if [[ "${use_user_dir}" == true ]]; then
|
|
405
|
+
NPM_GLOBAL_DIR="${HOME}/.npm-global"
|
|
406
|
+
# Create the directory before setting prefix so npm config set succeeds
|
|
407
|
+
mkdir -p "${NPM_GLOBAL_DIR}"
|
|
408
|
+
npm config set prefix "${NPM_GLOBAL_DIR}"
|
|
409
|
+
log_success "npm prefix set to: ${NPM_GLOBAL_DIR}"
|
|
410
|
+
|
|
411
|
+
# Only add ~/.npm-global/bin to PATH when we actually use it
|
|
412
|
+
local PROFILE_FILE
|
|
413
|
+
PROFILE_FILE=$(get_shell_profile)
|
|
414
|
+
if [[ -n "${PROFILE_FILE}" ]] && ! grep -q '.npm-global/bin' "${PROFILE_FILE}" 2>/dev/null; then
|
|
415
|
+
{
|
|
416
|
+
echo ""
|
|
417
|
+
echo "# NPM global bin (added by Qwen Code installer)"
|
|
418
|
+
echo "export PATH=\"\$HOME/.npm-global/bin:\$PATH\""
|
|
419
|
+
} >> "${PROFILE_FILE}" 2>/dev/null || log_warning "Failed to write PATH update to ${PROFILE_FILE}"
|
|
420
|
+
log_info "Added npm global bin to PATH in ${PROFILE_FILE}"
|
|
421
|
+
fi
|
|
422
|
+
else
|
|
423
|
+
log_info "npm global directory is writable: ${NPM_GLOBAL_DIR}"
|
|
424
|
+
fi
|
|
425
|
+
|
|
426
|
+
return 0
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
# ============================================
|
|
430
|
+
# Install Qwen Code
|
|
431
|
+
# ============================================
|
|
432
|
+
install_qwen_code() {
|
|
433
|
+
# Ensure NVM node is in PATH
|
|
434
|
+
export NVM_DIR="${HOME}/.nvm"
|
|
435
|
+
# shellcheck source=/dev/null
|
|
436
|
+
[[ -s "${NVM_DIR}/nvm.sh" ]] && \. "${NVM_DIR}/nvm.sh" 2>/dev/null || true
|
|
437
|
+
|
|
438
|
+
# Add npm global bin to PATH
|
|
439
|
+
local NPM_GLOBAL_BIN
|
|
440
|
+
NPM_GLOBAL_BIN=$(npm config get prefix 2>/dev/null)/bin
|
|
441
|
+
if [[ -n "${NPM_GLOBAL_BIN}" ]]; then
|
|
442
|
+
export PATH="${NPM_GLOBAL_BIN}:${PATH}"
|
|
443
|
+
fi
|
|
444
|
+
|
|
445
|
+
if command_exists qwen; then
|
|
446
|
+
local QWEN_VERSION
|
|
447
|
+
QWEN_VERSION=$(qwen --version 2>/dev/null || echo "unknown")
|
|
448
|
+
log_success "Qwen Code is already installed: ${QWEN_VERSION}"
|
|
449
|
+
log_info "Upgrading to the latest version..."
|
|
450
|
+
fi
|
|
451
|
+
|
|
452
|
+
# Clean npmrc conflicts
|
|
453
|
+
clean_npmrc_conflict
|
|
454
|
+
|
|
455
|
+
# Fix npm permissions if needed
|
|
456
|
+
fix_npm_permissions
|
|
457
|
+
|
|
458
|
+
# Install Qwen Code
|
|
459
|
+
log_info "Installing Qwen Code..."
|
|
460
|
+
if npm install -g @qwen-code/qwen-code@latest --registry https://registry.npmmirror.com; then
|
|
461
|
+
log_success "Qwen Code installed successfully!"
|
|
462
|
+
|
|
463
|
+
# Verify installation
|
|
464
|
+
if command_exists qwen; then
|
|
465
|
+
local qwen_version
|
|
466
|
+
qwen_version=$(qwen --version 2>/dev/null) || qwen_version="unknown"
|
|
467
|
+
log_info "Qwen Code version: ${qwen_version}"
|
|
468
|
+
fi
|
|
469
|
+
else
|
|
470
|
+
log_error "Failed to install Qwen Code!"
|
|
471
|
+
log_info "Please check your internet connection and try again"
|
|
472
|
+
exit 1
|
|
473
|
+
fi
|
|
474
|
+
|
|
475
|
+
# Create source.json if source parameter was provided
|
|
476
|
+
if [[ "${SOURCE}" != "unknown" ]]; then
|
|
477
|
+
create_source_json
|
|
478
|
+
fi
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
# ============================================
|
|
482
|
+
# Create source.json
|
|
483
|
+
# ============================================
|
|
484
|
+
create_source_json() {
|
|
485
|
+
local QWEN_DIR="${HOME}/.qwen"
|
|
486
|
+
|
|
487
|
+
mkdir -p "${QWEN_DIR}"
|
|
488
|
+
|
|
489
|
+
# Escape special characters in SOURCE for JSON
|
|
490
|
+
local ESCAPED_SOURCE
|
|
491
|
+
ESCAPED_SOURCE=$(printf '%s' "${SOURCE}" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
492
|
+
|
|
493
|
+
cat > "${QWEN_DIR}/source.json" <<EOF
|
|
494
|
+
{
|
|
495
|
+
"source": "${ESCAPED_SOURCE}"
|
|
496
|
+
}
|
|
497
|
+
EOF
|
|
498
|
+
|
|
499
|
+
log_success "Installation source saved to ~/.qwen/source.json"
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
# ============================================
|
|
503
|
+
# Main function
|
|
504
|
+
# ============================================
|
|
505
|
+
main() {
|
|
506
|
+
# Validate HOME variable
|
|
507
|
+
if [[ -z "${HOME}" ]]; then
|
|
508
|
+
log_warning "HOME environment variable is not set"
|
|
509
|
+
local MAIN_UID
|
|
510
|
+
MAIN_UID=$(id -u) || true
|
|
511
|
+
if [[ "${MAIN_UID}" -eq 0 ]]; then
|
|
512
|
+
export HOME="/root"
|
|
513
|
+
else
|
|
514
|
+
local CURRENT_USER
|
|
515
|
+
CURRENT_USER=$(whoami) || true
|
|
516
|
+
local user_home
|
|
517
|
+
user_home=$(eval echo "~${CURRENT_USER}") || true
|
|
518
|
+
export HOME="${user_home}"
|
|
519
|
+
fi
|
|
520
|
+
log_info "Using HOME=${HOME}"
|
|
521
|
+
fi
|
|
522
|
+
|
|
523
|
+
# Ensure download tool is available
|
|
524
|
+
ensure_download_tool
|
|
525
|
+
|
|
526
|
+
# Check and install Node.js
|
|
527
|
+
check_and_install_nodejs
|
|
528
|
+
echo ""
|
|
529
|
+
|
|
530
|
+
# Install Qwen Code
|
|
531
|
+
install_qwen_code
|
|
532
|
+
echo ""
|
|
533
|
+
|
|
534
|
+
# ============================================
|
|
535
|
+
# Final instructions
|
|
536
|
+
# ============================================
|
|
537
|
+
echo "=========================================="
|
|
538
|
+
echo "✅ Installation completed!"
|
|
539
|
+
echo "=========================================="
|
|
540
|
+
echo ""
|
|
541
|
+
|
|
542
|
+
# Ensure NVM and npm global bin are in PATH
|
|
543
|
+
export NVM_DIR="${HOME}/.nvm"
|
|
544
|
+
# shellcheck source=/dev/null
|
|
545
|
+
[[ -s "${NVM_DIR}/nvm.sh" ]] && \. "${NVM_DIR}/nvm.sh" 2>/dev/null || true
|
|
546
|
+
local NPM_GLOBAL_BIN
|
|
547
|
+
NPM_GLOBAL_BIN=$(npm config get prefix 2>/dev/null)/bin
|
|
548
|
+
if [[ -n "${NPM_GLOBAL_BIN}" ]]; then
|
|
549
|
+
export PATH="${NPM_GLOBAL_BIN}:${PATH}"
|
|
550
|
+
fi
|
|
551
|
+
|
|
552
|
+
# Check if qwen is immediately available
|
|
553
|
+
if command_exists qwen; then
|
|
554
|
+
log_success "Qwen Code is ready to use!"
|
|
555
|
+
echo ""
|
|
556
|
+
log_info "Tips: Please restart your terminal and run: qwen"
|
|
557
|
+
echo ""
|
|
558
|
+
else
|
|
559
|
+
log_warning "Tips: To start using Qwen Code, please run:"
|
|
560
|
+
echo ""
|
|
561
|
+
local PROFILE_FILE
|
|
562
|
+
PROFILE_FILE=$(get_shell_profile)
|
|
563
|
+
echo " source ${PROFILE_FILE}"
|
|
564
|
+
echo ""
|
|
565
|
+
log_info "Or simply restart your terminal, then run: qwen"
|
|
566
|
+
fi
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
# Run main function
|
|
570
|
+
main "$@"
|