release: Claude Code v2.1.72 (25 patches)

This commit is contained in:
delta-cloud-208e
2026-03-10 06:02:20 +00:00
parent dda909b4cc
commit c253494ae6
20 changed files with 16353 additions and 6 deletions

99
qwen_old/README.md Executable file
View File

@@ -0,0 +1,99 @@
# Qwen Code Patcher
Patches [QwenCode CLI](https://github.com/QwenLM/qwen-code) (`@qwen-code/qwen-code`) to route all API requests through a custom AI proxy, disable telemetry, and auto-configure settings.
**[RU]** Патчер для QwenCode CLI — перенаправляет API запросы через пользовательский AI прокси, отключает телеметрию, автоматически настраивает окружение.
## Quick Start
```bash
# 1. Install from private registry
npm config set @qwen-code:registry https://npm.sensey24.ru/
npm install -g @qwen-code/qwen-code
# 2. Apply settings (env vars + settings.json)
python3 qwen_patcher.py --settings-only
# 3. Verify
qwen -p "Say hello"
```
## Windows
```powershell
npm config set "@qwen-code:registry" "https://npm.sensey24.ru/"
npm install -g @qwen-code/qwen-code
python3 qwen_patcher.py --settings-only
```
## Update
Same two commands — npm will pull the latest patched version:
```bash
npm config set @qwen-code:registry https://npm.sensey24.ru/
npm install -g @qwen-code/qwen-code
```
## What Gets Patched
| # | Target | Description |
|---|--------|-------------|
| 1 | telemetry_flag | Force `getTelemetryEnabled()` -> false |
| 2 | telemetry_log_prompts | Force `getTelemetryLogPromptsEnabled()` -> false |
| 3 | telemetry_init_guard | Early return in `initializeTelemetry()` |
| 4 | dashscope_base_url | `DEFAULT_DASHSCOPE_BASE_URL` -> proxy |
| 5 | coding_plan_urls | `coding.dashscope.aliyuncs.com` -> proxy |
| 6 | default_model | Validate `DEFAULT_QWEN_MODEL = "coder-model"` |
| 7 | mainline_model | Validate `MAINLINE_CODER_MODEL = "qwen3.5-plus"` |
| 8 | auto_update_registry | `registry.npmjs.org` -> private registry |
| 9 | auto_update_command | Add `--registry` to update commands |
| 10 | user_settings | Auth type=openai, telemetry=false, model |
| 11 | trusted_folders | Trust /home, /root, /tmp |
| 12 | system_env | OPENAI_API_KEY, OPENAI_BASE_URL, telemetry vars |
Targets 1-9 are pre-patched in the npm package. Targets 10-12 require running `qwen_patcher.py --settings-only`.
## Models
| Model | Description |
|-------|-------------|
| `qwen3.5-plus` | Qwen 3.5 Plus — default |
| `coder-model` | Direct OAuth model name |
| `qwen3-coder-plus` | Qwen3 Coder Plus |
| `qwen3-coder-flash` | Qwen3 Coder Flash (fast) |
## CLI Usage
```bash
# Detection
python3 qwen_patcher.py --detect
# Validation (GREEN/YELLOW/RED for each target)
python3 qwen_patcher.py --validate
# Full patch (cli.js + settings + env)
python3 qwen_patcher.py --apply
# Settings only (no cli.js modification)
python3 qwen_patcher.py --settings-only
# Rollback cli.js from backup
python3 qwen_patcher.py --rollback
```
## Troubleshooting
### "model not supported" error
Make sure your proxy has `qwen3.5-plus` mapped to `coder-model` in the OAuth model alias config. The Qwen OAuth endpoint only accepts `coder-model` as the model name.
### CLI doesn't start after patching
If you applied `--apply` and the CLI fails to start, run `--rollback` to restore from backup, then use the pre-patched npm package instead:
```bash
python3 qwen_patcher.py --rollback
npm install -g @qwen-code/qwen-code # Re-installs pre-patched version
python3 qwen_patcher.py --settings-only
```

15
qwen_old/qwen_config.json Executable file
View File

@@ -0,0 +1,15 @@
{
"base_url": "https://ai.37-187-136-86.sslip.io",
"api_key": "ClauderAPI",
"default_model": "qwen3.5-plus",
"models": [
"qwen3.5-plus",
"coder-model",
"qwen3-coder-plus",
"qwen3-coder-flash"
],
"target_version": "0.11.1",
"telemetry_enabled": false,
"npm_package": "@qwen-code/qwen-code",
"npm_registry": "https://npm.sensey24.ru"
}

492
qwen_old/qwen_patcher.py Executable file
View File

@@ -0,0 +1,492 @@
#!/usr/bin/env python3
"""
Qwen Code Patcher — patches QwenCode CLI to route through custom AI proxy.
Targets:
1. telemetry_flag — force getTelemetryEnabled() → false
2. telemetry_log_prompts — force getTelemetryLogPromptsEnabled() → false
3. telemetry_init_guard — early return in initializeTelemetry()
4. dashscope_base_url — DEFAULT_DASHSCOPE_BASE_URL → proxy
5. coding_plan_urls — coding.dashscope.aliyuncs.com → proxy
6. default_model — validate DEFAULT_QWEN_MODEL (no change)
7. mainline_model — validate MAINLINE_CODER_MODEL (no change)
8. auto_update_registry — registry.npmjs.org → npm.sensey24.ru
9. auto_update_command — add --registry to update commands
10. user_settings — ~/.qwen/settings.json (auth + telemetry)
11. trusted_folders — ~/.qwen/trustedFolders.json
12. system_env — env vars injection
"""
import json
import os
import re
import sys
import shutil
import platform
import argparse
from pathlib import Path
# ─── Constants ──────────────────────────────────────────────────────────
SCRIPT_DIR = Path(__file__).resolve().parent
CONFIG_PATH = SCRIPT_DIR / "qwen_config.json"
IS_WINDOWS = platform.system() == "Windows"
IS_MACOS = platform.system() == "Darwin"
NPM_PACKAGE = "@qwen-code/qwen-code"
CLI_JS_FILENAME = "cli.js"
PATCH_MARKER = "/* QWEN_PATCHED */"
# ANSI colors
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
CYAN = "\033[96m"
BOLD = "\033[1m"
RESET = "\033[0m"
# ─── Utilities ──────────────────────────────────────────────────────────
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def load_config(config_path=None):
"""Load patcher configuration from JSON file."""
path = Path(config_path) if config_path else CONFIG_PATH
if not path.is_file():
eprint(f"{RED}Config not found: {path}{RESET}")
sys.exit(1)
with open(path, "r") as f:
return json.load(f)
def read_version(qwen_root):
"""Read version from package.json."""
pkg = Path(qwen_root) / "package.json"
if pkg.is_file():
with open(pkg) as f:
return json.load(f).get("version", "unknown")
return "unknown"
# ─── Detection ──────────────────────────────────────────────────────────
def _candidate_paths():
"""Generate candidate paths for QwenCode CLI installation."""
if IS_WINDOWS:
appdata = os.environ.get("APPDATA", "")
if appdata:
yield Path(appdata) / "npm" / "node_modules" / "@qwen-code" / "qwen-code"
localappdata = os.environ.get("LOCALAPPDATA", "")
if localappdata:
yield Path(localappdata) / "npm" / "node_modules" / "@qwen-code" / "qwen-code"
else:
yield Path("/usr/lib/node_modules/@qwen-code/qwen-code")
yield Path("/usr/local/lib/node_modules/@qwen-code/qwen-code")
if IS_MACOS:
yield Path("/opt/homebrew/lib/node_modules/@qwen-code/qwen-code")
home = Path.home()
yield home / ".local" / "lib" / "node_modules" / "@qwen-code" / "qwen-code"
yield home / ".npm-global" / "lib" / "node_modules" / "@qwen-code" / "qwen-code"
# nvm
nvm_dir = os.environ.get("NVM_DIR", str(home / ".nvm"))
nvm_path = Path(nvm_dir)
if nvm_path.is_dir():
for ver_dir in sorted(nvm_path.glob("versions/node/v*"), reverse=True):
yield ver_dir / "lib" / "node_modules" / "@qwen-code" / "qwen-code"
def detect_qwen():
"""Find QwenCode CLI installation. Returns (qwen_root, cli_js_path) or (None, None)."""
for root in _candidate_paths():
cli_js = root / CLI_JS_FILENAME
if cli_js.is_file():
return str(root), str(cli_js)
return None, None
# ─── Patching: cli.js targets (1-9) ────────────────────────────────────
def _backup_file(filepath):
"""Create backup of a file."""
backup = filepath + ".backup"
if not os.path.isfile(backup):
shutil.copy2(filepath, backup)
print(f" {CYAN}Backup:{RESET} {backup}")
def _already_patched(content):
"""Check if file already has patch marker."""
return PATCH_MARKER in content
def patch_cli_js(cli_js_path, config):
"""Apply all 9 cli.js patch targets. Returns dict of {target: status}."""
_backup_file(cli_js_path)
with open(cli_js_path, "r", encoding="utf-8", errors="replace") as f:
content = f.read()
if _already_patched(content):
print(f" {GREEN}cli.js already patched (marker found){RESET}")
return {"cli_js": "already_patched"}
base_url = config["base_url"]
npm_registry = config.get("npm_registry", "https://npm.sensey24.ru")
results = {}
original = content
# Target 1: TELEMETRY_FLAG
pat1 = r'(getTelemetryEnabled\(\)\s*\{)\s*return\s+this\.telemetrySettings\.enabled\s*\?\?\s*false;'
rep1 = r'\1 return false; /* QWEN_PATCHED */'
content, n = re.subn(pat1, rep1, content)
results["telemetry_flag"] = f"OK ({n})" if n > 0 else "SKIP"
# Target 2: TELEMETRY_LOG_PROMPTS
pat2 = r'(getTelemetryLogPromptsEnabled\(\)\s*\{)\s*return\s+this\.telemetrySettings\.logPrompts\s*\?\?\s*true;'
rep2 = r'\1 return false; /* QWEN_PATCHED */'
content, n = re.subn(pat2, rep2, content)
results["telemetry_log_prompts"] = f"OK ({n})" if n > 0 else "SKIP"
# Target 3: TELEMETRY_INIT_GUARD
pat3 = r'(function initializeTelemetry\(config2\)\s*\{)\s*\n(\s*)if\s*\(telemetryInitialized'
rep3 = r'\1\n\2return; /* QWEN_PATCHED: telemetry disabled */\n\2if (telemetryInitialized'
content, n = re.subn(pat3, rep3, content)
results["telemetry_init_guard"] = f"OK ({n})" if n > 0 else "SKIP"
# Target 4: DASHSCOPE_BASE_URL
pat4 = r'(DEFAULT_DASHSCOPE_BASE_URL\s*=\s*)"https://dashscope\.aliyuncs\.com/compatible-mode/v1"'
rep4 = rf'\1"{base_url}/v1"'
content, n = re.subn(pat4, rep4, content)
results["dashscope_base_url"] = f"OK ({n})" if n > 0 else "SKIP"
# Target 5: CODING_PLAN_URLS (string replace, not regex)
count5 = 0
for old_url in [
"https://coding.dashscope.aliyuncs.com/v1",
"https://coding-intl.dashscope.aliyuncs.com/v1",
]:
new_url = f"{base_url}/v1"
c = content.count(old_url)
content = content.replace(old_url, new_url)
count5 += c
results["coding_plan_urls"] = f"OK ({count5})" if count5 > 0 else "SKIP"
# Target 6: DEFAULT_MODEL (validate only)
if re.search(r'DEFAULT_QWEN_MODEL\s*=\s*"coder-model"', content):
results["default_model"] = "OK (validated)"
else:
results["default_model"] = "WARN (unexpected value)"
# Target 7: MAINLINE_MODEL (validate only)
if re.search(r'MAINLINE_CODER_MODEL\s*=\s*"qwen3\.5-plus"', content):
results["mainline_model"] = "OK (validated)"
else:
results["mainline_model"] = "WARN (unexpected value)"
# Target 8: AUTO_UPDATE_REGISTRY
count8 = 0
old_reg = '"https://registry.npmjs.org/"'
new_reg = f'"{npm_registry}/"'
c = content.count(old_reg)
content = content.replace(old_reg, new_reg)
count8 += c
# Also handle single-quoted variant
old_reg_sq = "'https://registry.npmjs.org/'"
new_reg_sq = f"'{npm_registry}/'"
c = content.count(old_reg_sq)
content = content.replace(old_reg_sq, new_reg_sq)
count8 += c
results["auto_update_registry"] = f"OK ({count8})" if count8 > 0 else "SKIP"
# Target 9: AUTO_UPDATE_COMMAND
old_cmd = '"npm install -g @qwen-code/qwen-code@latest"'
new_cmd = f'"npm install -g @qwen-code/qwen-code@latest --registry {npm_registry}"'
c = content.count(old_cmd)
content = content.replace(old_cmd, new_cmd)
results["auto_update_command"] = f"OK ({c})" if c > 0 else "SKIP"
# Add patch marker after shebang line (preserve shebang on line 1)
if content != original:
if content.startswith("#!"):
first_nl = content.index("\n")
content = content[:first_nl + 1] + PATCH_MARKER + "\n" + content[first_nl + 1:]
else:
content = PATCH_MARKER + "\n" + content
# Write patched file
with open(cli_js_path, "w", encoding="utf-8") as f:
f.write(content)
return results
# ─── Patching: settings targets (10-12) ────────────────────────────────
def patch_user_settings(config):
"""Configure ~/.qwen/settings.json (Target 10)."""
qwen_dir = Path.home() / ".qwen"
qwen_dir.mkdir(parents=True, exist_ok=True)
settings_path = qwen_dir / "settings.json"
existing = {}
if settings_path.is_file():
try:
with open(settings_path) as f:
existing = json.load(f)
except (json.JSONDecodeError, OSError):
pass
# Deep merge
if "security" not in existing:
existing["security"] = {}
if "auth" not in existing["security"]:
existing["security"]["auth"] = {}
existing["security"]["auth"]["selectedType"] = "openai"
if "telemetry" not in existing:
existing["telemetry"] = {}
existing["telemetry"]["enabled"] = False
existing["telemetry"]["logPrompts"] = False
if "model" not in existing:
existing["model"] = {}
existing["model"]["name"] = config.get("default_model", "qwen3.5-plus")
with open(settings_path, "w") as f:
json.dump(existing, f, indent=2)
print(f" {GREEN}Settings:{RESET} {settings_path}")
return "OK"
def patch_trusted_folders(config):
"""Create/update ~/.qwen/trustedFolders.json (Target 11)."""
qwen_dir = Path.home() / ".qwen"
qwen_dir.mkdir(parents=True, exist_ok=True)
tf_path = qwen_dir / "trustedFolders.json"
existing = {}
if tf_path.is_file():
try:
with open(tf_path) as f:
existing = json.load(f)
except (json.JSONDecodeError, OSError):
pass
trust_paths = config.get("trust_paths", ["/home", "/root", "/tmp"])
for p in trust_paths:
if p not in existing:
existing[p] = "TRUST_PARENT"
# Also trust home directory
home = str(Path.home())
if home not in existing:
existing[home] = "TRUST_PARENT"
with open(tf_path, "w") as f:
json.dump(existing, f, indent=2)
print(f" {GREEN}Trusted folders:{RESET} {tf_path}")
return "OK"
def setup_env_vars(config):
"""Set environment variables (Target 12)."""
base_url = config["base_url"]
api_key = config.get("api_key", "")
default_model = config.get("default_model", "qwen3.5-plus")
env_vars = {
"OPENAI_API_KEY": api_key,
"OPENAI_BASE_URL": f"{base_url}/v1",
"OPENAI_MODEL": default_model,
"GEMINI_TELEMETRY_ENABLED": "false",
"GEMINI_TELEMETRY_LOG_PROMPTS": "false",
}
if IS_WINDOWS:
import subprocess
for k, v in env_vars.items():
subprocess.run(["setx", k, v], capture_output=True)
print(f" {GREEN}Env vars:{RESET} Set via setx (Windows)")
return "OK"
# Linux/macOS: write to /etc/environment
env_file = Path("/etc/environment")
if not env_file.is_file():
# Try creating it
try:
env_file.touch()
except PermissionError:
eprint(f" {YELLOW}Cannot write /etc/environment (no root){RESET}")
_print_env_export(env_vars)
return "MANUAL"
try:
existing = env_file.read_text()
except PermissionError:
_print_env_export(env_vars)
return "MANUAL"
lines = existing.splitlines()
updated = False
for key, value in env_vars.items():
found = False
for i, line in enumerate(lines):
if line.startswith(f"{key}="):
lines[i] = f'{key}="{value}"'
found = True
break
if not found:
lines.append(f'{key}="{value}"')
updated = True
new_content = "\n".join(lines)
if not new_content.endswith("\n"):
new_content += "\n"
try:
env_file.write_text(new_content)
print(f" {GREEN}Env vars:{RESET} Written to /etc/environment")
return "OK"
except PermissionError:
eprint(f" {YELLOW}Cannot write /etc/environment (no root){RESET}")
_print_env_export(env_vars)
return "MANUAL"
def _print_env_export(env_vars):
"""Print export commands for manual setup."""
print(f"\n {YELLOW}Add these to your shell profile:{RESET}")
for k, v in env_vars.items():
print(f' export {k}="{v}"')
print()
# ─── Orchestration ─────────────────────────────────────────────────────
def apply_all_patches(cli_js_path, config, settings_only=False):
"""Apply all patches. Returns overall results dict."""
results = {}
if not settings_only:
print(f"\n{BOLD}Patching cli.js...{RESET}")
cli_results = patch_cli_js(cli_js_path, config)
results.update(cli_results)
print(f"\n{BOLD}Configuring settings...{RESET}")
results["user_settings"] = patch_user_settings(config)
results["trusted_folders"] = patch_trusted_folders(config)
results["system_env"] = setup_env_vars(config)
return results
def rollback(cli_js_path):
"""Restore cli.js from backup."""
backup = cli_js_path + ".backup"
if os.path.isfile(backup):
shutil.copy2(backup, cli_js_path)
print(f" {GREEN}Restored:{RESET} {cli_js_path}")
return True
else:
eprint(f" {RED}No backup found:{RESET} {backup}")
return False
# ─── Validation (standalone) ───────────────────────────────────────────
def run_validation(cli_js_path):
"""Run pattern validation on detected installation."""
from updater.pattern_validator import validate_all, print_validation_report, get_summary
user_settings = str(Path.home() / ".qwen" / "settings.json")
trusted_folders = str(Path.home() / ".qwen" / "trustedFolders.json")
results = validate_all(cli_js_path, user_settings, trusted_folders)
counts = print_validation_report(results)
return counts, get_summary(results)
# ─── CLI ───────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(
description="Qwen Code Patcher — patches QwenCode CLI for custom AI proxy"
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--detect", action="store_true", help="Find QwenCode CLI installation")
group.add_argument("--apply", action="store_true", help="Apply all patches")
group.add_argument("--settings-only", action="store_true", help="Only settings + env (no cli.js)")
group.add_argument("--rollback", action="store_true", help="Restore from backup")
group.add_argument("--validate", action="store_true", help="Validate all targets")
parser.add_argument("--config", type=str, help="Path to custom config file")
args = parser.parse_args()
config = load_config(args.config)
# Detection
qwen_root, cli_js_path = detect_qwen()
if args.detect:
if qwen_root:
version = read_version(qwen_root)
print(f"\n {GREEN}Found QwenCode CLI{RESET}")
print(f" Root: {qwen_root}")
print(f" cli.js: {cli_js_path}")
print(f" Version: {version}")
else:
eprint(f"\n {RED}QwenCode CLI not found{RESET}")
sys.exit(1)
return
if not qwen_root:
eprint(f"{RED}QwenCode CLI not found. Install: npm install -g @qwen-code/qwen-code{RESET}")
sys.exit(1)
version = read_version(qwen_root)
print(f"\n{BOLD}QwenCode CLI v{version}{RESET}{qwen_root}")
if args.validate:
counts, summary = run_validation(cli_js_path)
# Save report
report_dir = SCRIPT_DIR / "reports"
report_dir.mkdir(exist_ok=True)
report_path = report_dir / f"validation_{version}.json"
with open(report_path, "w") as f:
json.dump(summary, f, indent=2)
print(f"\n Report saved: {report_path}")
if counts.get("RED", 0) > 0:
sys.exit(2)
return
if args.rollback:
rollback(cli_js_path)
return
if args.settings_only:
results = apply_all_patches(cli_js_path, config, settings_only=True)
else:
results = apply_all_patches(cli_js_path, config, settings_only=False)
# Print summary
print(f"\n{BOLD}Results:{RESET}")
for target, status in results.items():
if "OK" in str(status) or status == "already_patched":
print(f" {GREEN}[OK]{RESET} {target}: {status}")
elif "SKIP" in str(status):
print(f" {YELLOW}[SKIP]{RESET} {target}: {status}")
else:
print(f" {CYAN}[INFO]{RESET} {target}: {status}")
print(f"\n{GREEN}Done!{RESET} Restart QwenCode CLI to apply changes.\n")
if __name__ == "__main__":
main()

234
qwen_old/uqwen_install.sh Executable file
View File

@@ -0,0 +1,234 @@
#!/usr/bin/env bash
# Qwen Code — One-line installer
# Usage:
# curl -fsSL -H "Authorization: token TOKEN" \
# https://git.sensey24.ru/aibot777/unlimitedcoding/raw/branch/master/qwen/uqwen_install.sh \
# -o /tmp/uqwen.sh && sudo bash /tmp/uqwen.sh
set -euo pipefail
GITEA_TOKEN="${GITEA_TOKEN:-cadffcb0a6a3be728ac1ff619bb40c86588f6837}"
REPO_RAW="https://git.sensey24.ru/aibot777/unlimitedcoding/raw/branch/master/qwen"
REGISTRY_URL="https://npm.sensey24.ru/"
NPM_SCOPE="@qwen-code"
NPM_PACKAGE="@qwen-code/qwen-code"
GREEN="\033[92m"
RED="\033[91m"
CYAN="\033[96m"
YELLOW="\033[93m"
BOLD="\033[1m"
RESET="\033[0m"
log() { echo -e "${GREEN}[+]${RESET} $*"; }
err() { echo -e "${RED}[!]${RESET} $*" >&2; }
info() { echo -e "${CYAN}[i]${RESET} $*"; }
warn() { echo -e "${YELLOW}[~]${RESET} $*"; }
echo -e "${BOLD}"
echo " +--------------------------------------+"
echo " | Qwen Code — Installer |"
echo " +--------------------------------------+"
echo -e "${RESET}"
# ---- Auto-install prerequisites ----
install_pkg() {
if command -v apt-get >/dev/null 2>&1; then
apt-get update -qq && apt-get install -y -qq "$@"
elif command -v dnf >/dev/null 2>&1; then
dnf install -y -q "$@"
elif command -v yum >/dev/null 2>&1; then
yum install -y -q "$@"
elif command -v brew >/dev/null 2>&1; then
brew install "$@"
else
err "No package manager found. Install $* manually."
return 1
fi
}
# Python3
if ! command -v python3 &>/dev/null; then
info "python3 not found, installing..."
install_pkg python3
fi
log "Python3 $(python3 --version | awk '{print $2}')"
# curl
if ! command -v curl &>/dev/null; then
info "curl not found, installing..."
install_pkg curl
fi
# Node.js >= 20
install_node() {
info "Installing Node.js v24.x..."
if command -v apt-get >/dev/null 2>&1; then
curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && apt-get install -y nodejs
elif command -v dnf >/dev/null 2>&1; then
curl -fsSL https://rpm.nodesource.com/setup_24.x | bash - && dnf install -y nodejs
elif command -v yum >/dev/null 2>&1; then
curl -fsSL https://rpm.nodesource.com/setup_24.x | bash - && yum install -y nodejs
elif command -v brew >/dev/null 2>&1; then
brew install node
else
err "Cannot auto-install Node.js. Install manually: https://nodejs.org/"
exit 1
fi
}
if ! command -v node &>/dev/null; then
install_node
fi
NODE_VER=$(node -v | sed 's/v//' | cut -d. -f1)
if [ "$NODE_VER" -lt 20 ]; then
warn "Node.js >= 20 required (found v$NODE_VER). Upgrading..."
install_node
NODE_VER=$(node -v | sed 's/v//' | cut -d. -f1)
fi
log "Node.js $(node -v)"
# ---- Configure npm registry ----
info "Configuring npm registry: ${REGISTRY_URL}"
npm config set "${NPM_SCOPE}:registry" "${REGISTRY_URL}" 2>/dev/null || true
# ---- Install Qwen Code ----
install_qwen_npm() {
local attempt=1
local max_attempts=3
while [ $attempt -le $max_attempts ]; do
info "Installing ${NPM_PACKAGE} (attempt ${attempt}/${max_attempts})..."
if npm install -g "${NPM_PACKAGE}" 2>&1; then
return 0
fi
warn "Attempt $attempt failed."
attempt=$((attempt + 1))
[ $attempt -le $max_attempts ] && sleep 3
done
return 1
}
QWEN_BIN=""
for candidate in qwen qwen-code; do
if command -v "$candidate" &>/dev/null; then
QWEN_BIN="$candidate"
break
fi
done
if [ -z "$QWEN_BIN" ]; then
if ! install_qwen_npm; then
err "npm install failed after retries."
err ""
err "Possible fixes:"
err " 1. Try HTTP instead of HTTPS:"
err " npm config set ${NPM_SCOPE}:registry http://npm.sensey24.ru/"
err " npm install -g ${NPM_PACKAGE}"
err ""
err " 2. Install from official npm + patch separately:"
err " npm install -g ${NPM_PACKAGE}"
err " # then re-run this script to apply patches"
exit 1
fi
# Find the binary after install
for candidate in qwen qwen-code; do
if command -v "$candidate" &>/dev/null; then
QWEN_BIN="$candidate"
break
fi
done
log "Qwen Code installed"
else
log "Qwen Code found: $QWEN_BIN"
fi
# ---- Download and apply patcher ----
INSTALL_DIR=$(mktemp -d)
cleanup() { rm -rf "$INSTALL_DIR" 2>/dev/null || true; }
trap cleanup EXIT
info "Downloading patcher..."
curl -fsSL "$REPO_RAW/qwen_patcher.py" -o "$INSTALL_DIR/qwen_patcher.py"
curl -fsSL "$REPO_RAW/qwen_config.json" -o "$INSTALL_DIR/qwen_config.json"
log "Patcher downloaded"
info "Applying patches (settings + env)..."
python3 "$INSTALL_DIR/qwen_patcher.py" --settings-only --config "$INSTALL_DIR/qwen_config.json"
PATCH_EXIT=$?
if [ $PATCH_EXIT -ne 0 ]; then
warn "Settings-only patch returned $PATCH_EXIT, trying full patch..."
python3 "$INSTALL_DIR/qwen_patcher.py" --apply --config "$INSTALL_DIR/qwen_config.json"
fi
log "Patches applied"
# ---- Set environment variables ----
info "Setting environment variables..."
ENV_VARS='export QWEN_API_KEY="ClauderAPI"
export QWEN_BASE_URL="https://ai.37-187-136-86.sslip.io"'
for rc_file in "$HOME/.bashrc" "$HOME/.zshrc"; do
if [ -f "$rc_file" ]; then
if ! grep -q 'QWEN_API_KEY' "$rc_file" 2>/dev/null; then
echo "" >> "$rc_file"
echo "# Qwen Code (UnlimitedCoding)" >> "$rc_file"
echo "$ENV_VARS" >> "$rc_file"
log "Added env vars to $(basename "$rc_file")"
fi
fi
done
export QWEN_API_KEY="ClauderAPI"
export QWEN_BASE_URL="https://ai.37-187-136-86.sslip.io"
# Also for all users if root
if [ "$(id -u)" -eq 0 ]; then
PROFILE_D="/etc/profile.d/qwen-code.sh"
cat > "$PROFILE_D" << 'PROF_EOF'
# Qwen Code (UnlimitedCoding)
export QWEN_API_KEY="ClauderAPI"
export QWEN_BASE_URL="https://ai.37-187-136-86.sslip.io"
PROF_EOF
chmod 644 "$PROFILE_D"
log "Set env vars for all users: $PROFILE_D"
fi
# ---- Verify ----
info "Verifying..."
echo ""
if [ -n "$QWEN_BIN" ]; then
RESULT=$(timeout 30 "$QWEN_BIN" -p "Reply with just OK" 2>&1 || true)
if echo "$RESULT" | grep -qi "OK"; then
echo ""
echo -e "${GREEN}${BOLD} Qwen Code installed and patched!${RESET}"
echo ""
echo " Usage:"
echo " $QWEN_BIN # interactive mode"
echo " $QWEN_BIN -p \"Your prompt\" # single prompt"
echo ""
echo " Models:"
echo " qwen3.5-plus, qwen3-coder-plus"
echo " qwen3-coder-flash, coder-model"
echo ""
echo " If env vars not active, run: source ~/.bashrc"
echo ""
else
warn "Patches applied but test prompt failed."
echo " Response: $RESULT"
echo ""
echo " Try manually:"
echo " source ~/.bashrc"
echo " $QWEN_BIN -p 'Hello'"
fi
else
warn "Qwen binary not found in PATH after install."
echo " Check: npm list -g ${NPM_PACKAGE}"
echo " Then run: source ~/.bashrc && qwen -p 'Hello'"
fi