fix(qwen): patch regional dashscope endpoints + inline validator
Qwen patcher had two issues: 1. Only patched dashscope.aliyuncs.com but missed regional endpoints (cn-hongkong, dashscope-intl, dashscope-us). Users in those regions would still hit Aliyun directly. 2. --validate raised ModuleNotFoundError (referenced removed updater/ package). Replaced with self-contained inline checker — 13 GREEN targets covering cli.js markers, settings.json, env vars. Also bump Codex version to v0.122.0 across all READMEs (was v0.116.0). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,3 +2,6 @@ __pycache__/
|
|||||||
.entire/
|
.entire/
|
||||||
.claude/
|
.claude/
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
|
|
||||||
|
# qwen validation reports — auto-generated, machine-specific
|
||||||
|
qwen/reports/
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Patched AI coding tools for use with custom API endpoints.
|
|||||||
| Folder | Tool | Status |
|
| Folder | Tool | Status |
|
||||||
|--------|------|--------|
|
|--------|------|--------|
|
||||||
| [claude/](claude/) | Claude Code | Active (v2.1.112) |
|
| [claude/](claude/) | Claude Code | Active (v2.1.112) |
|
||||||
| [codex/](codex/) | OpenAI Codex CLI | **Active (v0.116.0)** |
|
| [codex/](codex/) | OpenAI Codex CLI | **Active (v0.122.0)** |
|
||||||
| [gemini/](gemini/) | Gemini CLI | **Active (v0.35.3)** |
|
| [gemini/](gemini/) | Gemini CLI | **Active (v0.35.3)** |
|
||||||
| [qwen/](qwen/) | Qwen Code | **Active (v0.14.5)** |
|
| [qwen/](qwen/) | Qwen Code | **Active (v0.14.5)** |
|
||||||
| antigravity/ | Antigravity | Planned |
|
| antigravity/ | Antigravity | Planned |
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Herramientas de IA para codificación con soporte para puntos finales de API per
|
|||||||
| Carpeta | Herramienta | Estado |
|
| Carpeta | Herramienta | Estado |
|
||||||
|-------|-----------|--------|
|
|-------|-----------|--------|
|
||||||
| [claude/](claude/) | Claude Code | Activo (v2.1.112) |
|
| [claude/](claude/) | Claude Code | Activo (v2.1.112) |
|
||||||
| [codex/](codex/) | OpenAI Codex CLI | **Activo (v0.116.0)** |
|
| [codex/](codex/) | OpenAI Codex CLI | **Activo (v0.122.0)** |
|
||||||
| [gemini/](gemini/) | Gemini CLI | **Activo (v0.35.3)** |
|
| [gemini/](gemini/) | Gemini CLI | **Activo (v0.35.3)** |
|
||||||
| [qwen/](qwen/) | Qwen Code | **Activo (v0.14.5)** |
|
| [qwen/](qwen/) | Qwen Code | **Activo (v0.14.5)** |
|
||||||
| antigravity/ | Antigravity | Planeado |
|
| antigravity/ | Antigravity | Planeado |
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
| Папка | Инструмент | Статус |
|
| Папка | Инструмент | Статус |
|
||||||
|-------|-----------|--------|
|
|-------|-----------|--------|
|
||||||
| [claude/](claude/) | Claude Code | Активен (v2.1.112) |
|
| [claude/](claude/) | Claude Code | Активен (v2.1.112) |
|
||||||
| [codex/](codex/) | OpenAI Codex CLI | **Активен (v0.116.0)** |
|
| [codex/](codex/) | OpenAI Codex CLI | **Активен (v0.122.0)** |
|
||||||
| [gemini/](gemini/) | Gemini CLI | **Активен (v0.35.3)** |
|
| [gemini/](gemini/) | Gemini CLI | **Активен (v0.35.3)** |
|
||||||
| [qwen/](qwen/) | Qwen Code | **Активен (v0.14.5)** |
|
| [qwen/](qwen/) | Qwen Code | **Активен (v0.14.5)** |
|
||||||
| antigravity/ | Antigravity | Планируется |
|
| antigravity/ | Antigravity | Планируется |
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
| 文件夹 | 工具 | 状态 |
|
| 文件夹 | 工具 | 状态 |
|
||||||
|-------|-----------|--------|
|
|-------|-----------|--------|
|
||||||
| [claude/](claude/) | Claude Code | 活跃 (v2.1.112) |
|
| [claude/](claude/) | Claude Code | 活跃 (v2.1.112) |
|
||||||
| [codex/](codex/) | OpenAI Codex CLI | **活跃 (v0.116.0)** |
|
| [codex/](codex/) | OpenAI Codex CLI | **活跃 (v0.122.0)** |
|
||||||
| [gemini/](gemini/) | Gemini CLI | **活跃 (v0.35.3)** |
|
| [gemini/](gemini/) | Gemini CLI | **活跃 (v0.35.3)** |
|
||||||
| [qwen/](qwen/) | Qwen Code | **活跃 (v0.14.5)** |
|
| [qwen/](qwen/) | Qwen Code | **活跃 (v0.14.5)** |
|
||||||
| antigravity/ | Antigravity | 计划中 |
|
| antigravity/ | Antigravity | 计划中 |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Codex CLI — Patched
|
# Codex CLI — Patched
|
||||||
|
|
||||||
Patched OpenAI Codex CLI for use with custom API endpoints.
|
Patched OpenAI Codex CLI for use with custom API endpoints.
|
||||||
Latest: **v0.116.0** (6 config patches).
|
Latest: **v0.122.0** (6 config patches).
|
||||||
|
|
||||||
> Codex CLI — это compiled Rust binary. В отличие от Claude Code и Gemini CLI (JavaScript),
|
> Codex CLI — это compiled Rust binary. В отличие от Claude Code и Gemini CLI (JavaScript),
|
||||||
> патчинг выполняется через `config.toml` + переменные окружения.
|
> патчинг выполняется через `config.toml` + переменные окружения.
|
||||||
@@ -76,7 +76,7 @@ powershell -ExecutionPolicy Bypass -File ucodex_install.ps1
|
|||||||
```bash
|
```bash
|
||||||
# Скачать последнюю версию с GitHub
|
# Скачать последнюю версию с GitHub
|
||||||
sudo bash update-codex.sh
|
sudo bash update-codex.sh
|
||||||
codex --version # Должно показать: codex-cli 0.116.0
|
codex --version # Должно показать: codex-cli 0.122.0
|
||||||
```
|
```
|
||||||
|
|
||||||
**Шаг 2 — Настроить конфиг:**
|
**Шаг 2 — Настроить конфиг:**
|
||||||
|
|||||||
@@ -158,11 +158,19 @@ def patch_cli_js(cli_js_path, config):
|
|||||||
content, n = re.subn(pat3, rep3, content)
|
content, n = re.subn(pat3, rep3, content)
|
||||||
results["telemetry_init_guard"] = f"OK ({n})" if n > 0 else "SKIP"
|
results["telemetry_init_guard"] = f"OK ({n})" if n > 0 else "SKIP"
|
||||||
|
|
||||||
# Target 4: DASHSCOPE_BASE_URL
|
# Target 4: DASHSCOPE_BASE_URL — main + regional (HK/intl/us) endpoints
|
||||||
pat4 = r'(DEFAULT_DASHSCOPE_BASE_URL\s*=\s*)"https://dashscope\.aliyuncs\.com/compatible-mode/v1"'
|
count4 = 0
|
||||||
rep4 = rf'\1"{base_url}/v1"'
|
for old_url in [
|
||||||
content, n = re.subn(pat4, rep4, content)
|
"https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
results["dashscope_base_url"] = f"OK ({n})" if n > 0 else "SKIP"
|
"https://cn-hongkong.dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"https://dashscope-us.aliyuncs.com/compatible-mode/v1",
|
||||||
|
]:
|
||||||
|
new_url = f"{base_url}/v1"
|
||||||
|
c = content.count(old_url)
|
||||||
|
content = content.replace(old_url, new_url)
|
||||||
|
count4 += c
|
||||||
|
results["dashscope_base_url"] = f"OK ({count4})" if count4 > 0 else "SKIP"
|
||||||
|
|
||||||
# Target 5: CODING_PLAN_URLS (string replace, not regex)
|
# Target 5: CODING_PLAN_URLS (string replace, not regex)
|
||||||
count5 = 0
|
count5 = 0
|
||||||
@@ -403,15 +411,112 @@ def rollback(cli_js_path):
|
|||||||
# ─── Validation (standalone) ───────────────────────────────────────────
|
# ─── Validation (standalone) ───────────────────────────────────────────
|
||||||
|
|
||||||
def run_validation(cli_js_path):
|
def run_validation(cli_js_path):
|
||||||
"""Run pattern validation on detected installation."""
|
"""Lightweight validation — checks patch markers and key invariants in
|
||||||
from updater.pattern_validator import validate_all, print_validation_report, get_summary
|
cli.js + ~/.qwen/settings.json + trustedFolders.json."""
|
||||||
|
counts = {"green": 0, "yellow": 0, "red": 0}
|
||||||
|
print()
|
||||||
|
print(f" {BOLD}Validating Qwen patches{RESET}")
|
||||||
|
print(f" {'─' * 56}")
|
||||||
|
|
||||||
user_settings = str(Path.home() / ".qwen" / "settings.json")
|
def report(name, status, detail=""):
|
||||||
trusted_folders = str(Path.home() / ".qwen" / "trustedFolders.json")
|
if status == "GREEN":
|
||||||
|
counts["green"] += 1
|
||||||
|
color = GREEN
|
||||||
|
elif status == "YELLOW":
|
||||||
|
counts["yellow"] += 1
|
||||||
|
color = YELLOW
|
||||||
|
else:
|
||||||
|
counts["red"] += 1
|
||||||
|
color = RED
|
||||||
|
suffix = f" — {detail}" if detail else ""
|
||||||
|
print(f" {color}[{status}]{RESET} {name}{suffix}")
|
||||||
|
|
||||||
results = validate_all(cli_js_path, user_settings, trusted_folders)
|
# cli.js checks
|
||||||
counts = print_validation_report(results)
|
if cli_js_path and os.path.isfile(cli_js_path):
|
||||||
return counts, get_summary(results)
|
with open(cli_js_path, "r", encoding="utf-8", errors="replace") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
report("cli.js patch_marker",
|
||||||
|
"GREEN" if PATCH_MARKER in content else "RED",
|
||||||
|
"" if PATCH_MARKER in content else "marker not found")
|
||||||
|
|
||||||
|
report("telemetry_flag",
|
||||||
|
"GREEN" if "getTelemetryEnabled() { return false" in content else "YELLOW")
|
||||||
|
|
||||||
|
report("telemetry_log_prompts",
|
||||||
|
"GREEN" if "getTelemetryLogPromptsEnabled() { return false" in content else "YELLOW")
|
||||||
|
|
||||||
|
# dashscope_base_url: any /compatible-mode/v1 endpoint left = RED
|
||||||
|
leftover_ds = [u for u in [
|
||||||
|
"dashscope.aliyuncs.com/compatible-mode",
|
||||||
|
"cn-hongkong.dashscope.aliyuncs.com/compatible-mode",
|
||||||
|
"dashscope-intl.aliyuncs.com/compatible-mode",
|
||||||
|
"dashscope-us.aliyuncs.com/compatible-mode",
|
||||||
|
] if u in content]
|
||||||
|
report("dashscope_base_url",
|
||||||
|
"GREEN" if not leftover_ds else "RED",
|
||||||
|
f"unpatched: {', '.join(leftover_ds)}" if leftover_ds else "")
|
||||||
|
|
||||||
|
leftover_cp = [u for u in [
|
||||||
|
"coding.dashscope.aliyuncs.com",
|
||||||
|
"coding-intl.dashscope.aliyuncs.com",
|
||||||
|
] if u in content]
|
||||||
|
report("coding_plan_urls",
|
||||||
|
"GREEN" if not leftover_cp else "RED",
|
||||||
|
f"unpatched: {', '.join(leftover_cp)}" if leftover_cp else "")
|
||||||
|
|
||||||
|
report("default_model",
|
||||||
|
"GREEN" if 'DEFAULT_QWEN_MODEL = "coder-model"' in content else "YELLOW")
|
||||||
|
|
||||||
|
report("mainline_model",
|
||||||
|
"GREEN" if 'MAINLINE_CODER_MODEL = "qwen3.5-plus"' in content else "YELLOW")
|
||||||
|
|
||||||
|
report("auto_update_registry",
|
||||||
|
"GREEN" if '"https://registry.npmjs.org/"' not in content else "YELLOW")
|
||||||
|
else:
|
||||||
|
report("cli.js", "RED", f"not found: {cli_js_path}")
|
||||||
|
|
||||||
|
# settings.json checks
|
||||||
|
settings_path = Path.home() / ".qwen" / "settings.json"
|
||||||
|
if settings_path.is_file():
|
||||||
|
try:
|
||||||
|
with open(settings_path, "r", encoding="utf-8") as f:
|
||||||
|
settings = json.load(f)
|
||||||
|
sec = settings.get("security", {})
|
||||||
|
auth = sec.get("auth", {})
|
||||||
|
telemetry = settings.get("telemetry", {})
|
||||||
|
report("user_settings.auth.selectedType",
|
||||||
|
"GREEN" if auth.get("selectedType") == "openai" else "YELLOW",
|
||||||
|
f"value={auth.get('selectedType')!r}")
|
||||||
|
report("user_settings.telemetry.enabled",
|
||||||
|
"GREEN" if telemetry.get("enabled") is False else "YELLOW")
|
||||||
|
except Exception as e:
|
||||||
|
report("user_settings", "RED", f"parse error: {e}")
|
||||||
|
else:
|
||||||
|
report("user_settings", "YELLOW", f"missing: {settings_path}")
|
||||||
|
|
||||||
|
# trustedFolders.json checks
|
||||||
|
trusted_path = Path.home() / ".qwen" / "trustedFolders.json"
|
||||||
|
if trusted_path.is_file():
|
||||||
|
report("trusted_folders", "GREEN", "present")
|
||||||
|
else:
|
||||||
|
report("trusted_folders", "YELLOW", "missing")
|
||||||
|
|
||||||
|
# env vars
|
||||||
|
has_api = bool(os.environ.get("OPENAI_API_KEY"))
|
||||||
|
has_url = bool(os.environ.get("OPENAI_BASE_URL"))
|
||||||
|
report("env.OPENAI_API_KEY",
|
||||||
|
"GREEN" if has_api else "YELLOW",
|
||||||
|
"" if has_api else "not set in current shell")
|
||||||
|
report("env.OPENAI_BASE_URL",
|
||||||
|
"GREEN" if has_url else "YELLOW",
|
||||||
|
"" if has_url else "not set in current shell")
|
||||||
|
|
||||||
|
print(f" {'─' * 56}")
|
||||||
|
print(f" {GREEN}GREEN: {counts['green']}{RESET} "
|
||||||
|
f"{YELLOW}YELLOW: {counts['yellow']}{RESET} "
|
||||||
|
f"{RED}RED: {counts['red']}{RESET}")
|
||||||
|
return counts, f"{counts['green']}G/{counts['yellow']}Y/{counts['red']}R"
|
||||||
|
|
||||||
|
|
||||||
# ─── CLI ───────────────────────────────────────────────────────────────
|
# ─── CLI ───────────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user