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:
delta-cloud-208e
2026-04-21 10:26:55 +00:00
parent 0a3de88e65
commit 82830c971d
7 changed files with 126 additions and 18 deletions

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@ __pycache__/
.entire/ .entire/
.claude/ .claude/
CLAUDE.md CLAUDE.md
# qwen validation reports — auto-generated, machine-specific
qwen/reports/

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 | Планируется |

View File

@@ -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 | 计划中 |

View File

@@ -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 — Настроить конфиг:**

View File

@@ -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 ───────────────────────────────────────────────────────────────