From c52b801cdec17d03e650b95f9e3759a1be757799 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 22 May 2026 16:29:45 +0400 Subject: [PATCH] =?UTF-8?q?v3.7.0:=20Intelligence=20Routing=20=E2=80=94=20?= =?UTF-8?q?self-healing=20parser=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Layer 1 (FIX 23): Deep URL extraction from nested JSON in explore_agent blocks. Layer 2 (FIX 24): Auto-proceed on require_escalation / request_escalation_permission. Layer 3 (FIX 25): Intent-based command synthesis with 5 heuristics when all parsers fail. Module-level _build_explore_cmd() for reuse across parser + stream path. 54 self-test patterns (up from 41). --- CHANGELOG.md | 43 ++++++ codex-launcher_3.7.0_all.deb | Bin 0 -> 77212 bytes install.sh | 8 +- src/codex-launcher-gui | 38 ++++- src/translate-proxy.py | 264 ++++++++++++++++++++++++++++++----- 5 files changed, 316 insertions(+), 37 deletions(-) create mode 100644 codex-launcher_3.7.0_all.deb diff --git a/CHANGELOG.md b/CHANGELOG.md index f24b2c7..f03b09d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,48 @@ # Changelog +## v3.7.0 (2026-05-22) + +**Intelligence Routing — Self-Healing Parser System** + +When the Command Code model produces output in unpredictable or unrecognized formats, the multi-format parser chain (DSML, XML, explore_agent, bash blocks, raw JSON, fallback regex) can return empty. This causes the Codex agent loop to stall — zero tool calls means nothing to execute. + +Intelligence Routing is a **three-layer self-healing system** that ensures the agent loop always continues: + +### Layer 1: Deep URL Extraction (FIX 23) +- **Problem**: `` body contained `messages: [{"content": "https://..."}]` — URLs hidden inside JSON values. Regex couldn't match because it excluded the `"` character that terminates JSON strings. +- **Solution**: `_build_explore_cmd()` extracted to module level (was a closure inside `_parse_commandcode_text_tool_calls`). After initial regex fails, tries `json.loads()`, iterates list items, extracts `content` field to find URLs. Added `"` to regex exclusion set. +- **Self-tests**: Pattern M, O, O2 verify URL extraction from nested JSON. + +### Layer 2: Escalation Block Handling (FIX 24) +- **Problem**: Model produces `` and `` blocks when it wants elevated permissions. CC adapter doesn't support escalation — blocks silently dropped → `parsed_tool_calls=0` → stall. +- **Solution**: Two handlers: + - FIX 24a: Closed-tag blocks — extracts URL if present and runs explore command; otherwise echoes auto-proceed. + - FIX 24b: Bare/unclosed tags (``) — auto-proceeds with diagnostic echo. +- **Self-tests**: Pattern N, N2 verify both closed and bare escalation blocks. + +### Layer 3: Intent-Based Command Synthesis (FIX 25 — THE CORE) +- **Problem**: After ALL parsers return empty, the agent loop has zero tool calls. Model may have written plain English ("I need to fetch the README"), partial JSON, or completely unrecognized formats. +- **Solution**: 5-heuristic synthesis chain in `cc_stream_to_sse()`, run when `parsed_tool_calls=0` and text has content: + 1. **URL in text** → `curl` to fetch it + 2. **File path reference** ("read the file /path/to/X") → `cat` or `ls` that file + 3. **Shell command in backticks/quotes** → extract and run it + 4. **"explore"/"fetch"/"investigate"/"repository" intent** + last user URL → `_build_explore_cmd()` with `_last_user_urls` deque + 5. **"I need to"/"let me"/"please" intent text** → echo diagnostic with the intent +- The system NEVER returns empty tool calls when there's text to analyze. +- **Self-tests**: Patterns M-O2 cover the full pipeline. + +### Architecture +``` +_parse_commandcode_text_tool_calls() ← Layer 1 + Layer 2 +cc_stream_to_sse() ← Layer 3 (after parser chain + fallback) +_last_user_urls deque (maxlen=20) ← Session-wide URL memory for heuristic 4 +``` + +### Test Coverage +- **54 self-test patterns** (up from 41 in v3.6.0) +- 13 new tests covering all three Intelligence Routing layers +- Tests verify: nested JSON URL extraction, closed/bare escalation blocks, module-level explore command builder + ## v3.6.0 (2026-05-22) **Performance & Stability Hardening — Connection Pooling, Stream Idle Timeouts, Retry-After** diff --git a/codex-launcher_3.7.0_all.deb b/codex-launcher_3.7.0_all.deb new file mode 100644 index 0000000000000000000000000000000000000000..38d9d5cd69b76b26444326fbfdd1cd423d81b130 GIT binary patch literal 77212 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%0DWef1h$Em|Afnx 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 literal 0 HcmV?d00001 diff --git a/install.sh b/install.sh index 6c844a9..70b0b75 100755 --- a/install.sh +++ b/install.sh @@ -3,11 +3,11 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -if [ -f "$SCRIPT_DIR/codex-launcher_3.6.0_all.deb" ]; then - echo "Installing codex-launcher_3.6.0_all.deb ..." - sudo dpkg -i "$SCRIPT_DIR/codex-launcher_3.6.0_all.deb" +if [ -f "$SCRIPT_DIR/codex-launcher_3.7.0_all.deb" ]; then + echo "Installing codex-launcher_3.7.0_all.deb ..." + sudo dpkg -i "$SCRIPT_DIR/codex-launcher_3.7.0_all.deb" echo "" - echo "Installed v3.6.0 via .deb package." + echo "Installed v3.7.0 via .deb package." echo " translate-proxy.py -> /usr/bin/translate-proxy.py" echo " codex-launcher-gui -> /usr/bin/codex-launcher-gui" echo " cleanup-codex-stale -> /usr/bin/cleanup-codex-stale.sh" diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui index e57a7e1..951e0e9 100755 --- a/src/codex-launcher-gui +++ b/src/codex-launcher-gui @@ -26,6 +26,42 @@ model_catalog_json = "" """ CHANGELOG = [ + ("3.7.0", "2026-05-22", [ + "Intelligence Routing — self-healing parser system for Command Code", + "Layer 1: Deep URL extraction from nested JSON in explore_agent blocks", + "Layer 2: Auto-proceed on require_escalation / request_escalation_permission blocks", + "Layer 3: Intent-based command synthesis when all parsers fail (5 heuristics)", + "Module-level _build_explore_cmd() — reuses URL extraction across parser + stream", + "54 self-test patterns covering all three Intelligence Routing layers", + ]), + ("3.6.0", "2026-05-22", [ + "Connection pooling — persistent HTTPS connections per host", + "Stream idle timeout (300s) — kills silent streams instead of hanging", + "Retry-After header support on all retry paths", + "Bounded stream buffers (8MB) — prevents OOM", + "Dual logging to proxy.log + stderr", + ]), + ("3.5.0", "2026-05-22", [ + "Command Code adapter overhaul — 17 patches for multi-format tool-call parsing", + "DSML, XML, explore_agent, bash blocks, raw JSON parser chain", + "Self-revive watchdog — auto-restarts proxy on crash", + "Debug-to-file logging in cc-debug.log", + "Inline self-test (19 patterns)", + ]), + ("3.3.0", "2026-05-20", [ + "Antigravity + Gemini CLI OAuth — full Codex agent loop working", + "Auto-continue on MAX_TOKENS for Gemini/Antigravity", + "BGP++ route scoring and provider policy layer", + ]), + ("3.0.0", "2026-05-20", [ + "Major overhaul — ThreadingHTTPServer, thread-safe state, graceful shutdown", + "Dynamic port allocation, proxy health gating, atomic config", + "Usage Dashboard v2 with dark theme", + ]), + ("2.7.0", "2026-05-20", [ + "Usage Dashboard redesigned (OpenUsage-inspired dark theme)", + "TCP_NODELAY streaming, Anthropic prompt caching", + ]), ("2.6.1", "2026-05-20", [ "Google OAuth rebuilt to emulate Gemini CLI — no client_secret.json needed", "Uses Google's public OAuth client_id (same as gemini-cli)", @@ -1107,7 +1143,7 @@ class LauncherWin(Gtk.Window): # header row hdr = Gtk.Box(spacing=8) vbox.pack_start(hdr, False, False, 0) - lbl = Gtk.Label(label="Codex Launcher v3.6.0") + lbl = Gtk.Label(label="Codex Launcher v3.7.0") lbl.set_use_markup(True) hdr.pack_start(lbl, False, False, 0) changelog_btn = Gtk.Button(label="Changelog") diff --git a/src/translate-proxy.py b/src/translate-proxy.py index ab635af..8946e15 100755 --- a/src/translate-proxy.py +++ b/src/translate-proxy.py @@ -98,7 +98,61 @@ FIX 21: DSML parser silently drops tool calls when model uses name="cmd" (THE HA Test: Pattern L self-test verifies DSML with name="cmd" is parsed correctly. Location: _parse_commandcode_text_tool_calls() DSML parameter loop, self-test Pattern L -═══════════════════════════════════════════════════════════════════ +════════════════════════════════════════════════════════════════════ +INTELLIGENCE ROUTING — Self-Healing Parser System (v3.7.0) +════════════════════════════════════════════════════════════════════ + +Problem: The Command Code model produces output in unpredictable formats +that change between sessions and models. When the multi-format parser chain +(DSML → → XML → raw JSON → +fallback regex) returns empty, the Codex agent loop has zero tool calls and +STALLS — the user sees the model "thinking" but nothing happens. + +Intelligence Routing is a three-layer self-healing system: + +LAYER 1 — Deep URL Extraction (FIX 23) + The handler was failing because URLs were hidden inside + nested JSON: messages: [{"content": "https://..."}]. The regex couldn't + find them because it excluded the " character that terminates JSON values. + + Solution: _build_explore_cmd() is now a module-level function (was a + closure). After the initial regex fails, it tries json.loads() on the + text, iterates list items, and extracts the "content" field to find URLs. + Also added " to the regex exclusion set and rstrip characters. + +LAYER 2 — Escalation Block Handling (FIX 24) + The model produces and + blocks when it wants elevated permissions. The CC adapter doesn't support + escalation — these blocks were silently dropped, causing parsed_tool_calls=0. + + Solution: Two handlers: + - FIX 24a: Closed-tag blocks — extracts URL if present, runs explore cmd; + otherwise echoes auto-proceed message. + - FIX 24b: Bare/unclosed tags () — auto-proceeds. + +LAYER 3 — Intent-Based Command Synthesis (FIX 25, THE CORE) + When ALL parsers return empty and text has content, the system plays + detective using 5 heuristics in priority order: + + 1. URL detected in text → curl to fetch it + 2. File path reference → cat or ls that file + 3. Shell command in backticks/quotes → extract and run + 4. "explore"/"fetch"/"investigate" intent + last user URL → explore cmd + 5. "I need to"/"let me"/"please" intent text → echo diagnostic + + This ensures the agent loop ALWAYS has a tool call to execute, even when + the model's output format is completely unrecognized. The loop never stalls. + +Architecture: + _parse_commandcode_text_tool_calls() — LAYER 1 + LAYER 2 + cc_stream_to_sse() — LAYER 3 (runs after parser chain + fallback) + + The _last_user_urls deque (maxlen=20) tracks URLs from user messages + across the session, giving Layer 3 heuristic 4 a URL to work with. + + Self-tests: 54 patterns (was 41) covering all three layers. + +════════════════════════════════════════════════════════════════════ """ import json, http.server, socketserver, urllib.request, urllib.parse, urllib.error, re @@ -1736,6 +1790,49 @@ def _unwrap_cmd(cmd_val): break return cmd_val +def _build_explore_cmd(text_for_url): + """Module-level explore command builder. Extracts repo URL from text, + builds a curl pipeline to fetch README, contents listing, and releases. + Used by _parse_commandcode_text_tool_calls (closure wrapper) and + cc_stream_to_sse (stuck recovery heuristic).""" + if not text_for_url: + return None, None + url_m = re.search(r"https?://[^\s\]'\\>\",]+", text_for_url) + repo_url = url_m.group(0).rstrip(")].,;'\\\"") if url_m else "" + if not repo_url and isinstance(text_for_url, str): + try: + _parsed = json.loads(text_for_url) + if isinstance(_parsed, list): + for _item in _parsed: + _c = _item.get("content", "") if isinstance(_item, dict) else str(_item) + url_m2 = re.search(r"https?://[^\s\]'\\>\",]+", _c) + if url_m2: + repo_url = url_m2.group(0).rstrip(")].,;'\\\"") + break + except Exception: + pass + if not repo_url: + return None, None + if repo_url.endswith(".git"): + repo_url = repo_url[:-4] + if "/api/v1/repos/" not in repo_url: + host_m = re.match(r"(https?://[^/]+)/(.*)", repo_url) + if host_m: + host, path = host_m.groups() + api_base = f"{host}/api/v1/repos/{path}" + else: + api_base = repo_url.replace("/admin/", "/api/v1/repos/") + else: + api_base = repo_url + cmd = ( + f"cd /tmp && " + f"curl -sL --max-time 15 '{api_base}/contents/README.md' 2>/dev/null | " + f"python3 -c \"import sys,json,base64; d=json.load(sys.stdin); print(base64.b64decode(d['content']).decode())\" 2>/dev/null | head -600 && " + f"curl -sL --max-time 15 '{api_base}/contents' 2>/dev/null | python3 -c \"import sys,json; d=json.load(sys.stdin); print('\\n'.join(f'{{x.get(\'path\')}} {{x.get(\'type\')}}' for x in d[:50]))\" 2>/dev/null && " + f"curl -sL --max-time 15 '{api_base}/releases' 2>/dev/null | python3 -c \"import sys,json; d=json.load(sys.stdin); print(json.dumps(d[:3], indent=2)[:2000])\" 2>/dev/null" + ) + return cmd, "Explore repository to understand the app and gather README, root contents, and releases for the landing page." + def _parse_commandcode_text_tool_calls(text): """Parse CommandCode's text-form tool calls into Responses function calls. @@ -1756,37 +1853,7 @@ def _parse_commandcode_text_tool_calls(text): if not text: return calls - # [FIX 20] Use the module-level _build_explore_cmd helper (moved to module level - # in FIX 22 so it can also be called from cc_stream_to_sse for escalation recovery). - # The function is defined above, before _parse_commandcode_text_tool_calls. - def _build_explore_cmd_local(text_for_url): - if not text_for_url: - return None, None - url_m = re.search(r"https?://[^\s\]'\\>\"]+", text_for_url) - repo_url = url_m.group(0).rstrip(")].,;'\\") if url_m else "" - if repo_url: - # Clean trailing .git if present - if repo_url.endswith(".git"): - repo_url = repo_url[:-4] - if "/api/v1/repos/" not in repo_url: - host_m = re.match(r"(https?://[^/]+)/(.*)", repo_url) - if host_m: - host, path = host_m.groups() - api_base = f"{host}/api/v1/repos/{path}" - else: - api_base = repo_url.replace("/admin/", "/api/v1/repos/") - else: - api_base = repo_url - - cmd = ( - f"cd /tmp && " - f"curl -sL --max-time 15 '{api_base}/contents/README.md' 2>/dev/null | " - f"python3 -c \"import sys,json,base64; d=json.load(sys.stdin); print(base64.b64decode(d['content']).decode())\" 2>/dev/null | head -600 && " - f"curl -sL --max-time 15 '{api_base}/contents' 2>/dev/null | python3 -c \"import sys,json; d=json.load(sys.stdin); print('\\n'.join(f'{{x.get(\'path\')}} {{x.get(\'type\')}}' for x in d[:50]))\" 2>/dev/null && " - f"curl -sL --max-time 15 '{api_base}/releases' 2>/dev/null | python3 -c \"import sys,json; d=json.load(sys.stdin); print(json.dumps(d[:3], indent=2)[:2000])\" 2>/dev/null" - ) - return cmd, "Explore repository to understand the app and gather README, root contents, and releases for the landing page." - return None, None + _build_explore_cmd_local = _build_explore_cmd # [FIX 17] DSML tool_call blocks used by the model now. # Example: @@ -1968,6 +2035,39 @@ def _parse_commandcode_text_tool_calls(text): "arguments": json.dumps({"cmd": cmd, "justification": justification or "Explore repository"}, ensure_ascii=False), }) + # [FIX 24] Handle and blocks. + # The model produces these when it wants elevated permissions but the CC + # adapter doesn't support them. Synthesize a proceed command so the loop continues. + if not calls: + for m in re.finditer(r"<(?:require_escalation|request_escalation_permission)>(.*?)", text, re.DOTALL | re.IGNORECASE): + body_escal = (m.group(1) or "").strip() + _inner_url_m = re.search(r"https?://[^\s\]'\\>\",]+", body_escal) + if _inner_url_m: + _e_url = _inner_url_m.group(0).rstrip(")].,;'\\\"") + _e_cmd, _e_just = _build_explore_cmd_local(_e_url) + if _e_cmd: + calls.append({ + "full_match": m.group(0), + "name": "exec_command", + "arguments": json.dumps({"cmd": _e_cmd, "justification": _e_just or "Escalation block with URL — auto-proceed"}, ensure_ascii=False), + }) + continue + if not calls: + calls.append({ + "full_match": m.group(0), + "name": "exec_command", + "arguments": json.dumps({"cmd": "echo 'escalation: auto-proceeding — no specific command in escalation block'", "justification": "Auto-proceed past escalation request"}, ensure_ascii=False), + }) + + # [FIX 24b] Bare or + # without closing tags. Just auto-proceed. + if not calls and re.search(r"<(?:require_escalation|request_escalation_permission)[\s/>]", text, re.IGNORECASE): + calls.append({ + "full_match": "", + "name": "exec_command", + "arguments": json.dumps({"cmd": "echo 'escalation: auto-proceeding past bare escalation tag'", "justification": "Auto-proceed past bare escalation tag"}, ensure_ascii=False), + }) + patterns = [ r"\s]+)['\"]?)?>(.*?)", r"(.*?)", @@ -2568,6 +2668,70 @@ def cc_stream_to_sse(cc_stream, model, req_id): else: _deflog(f"[CC-DEBUG] Fallback also failed. text_buf first 500: {text_buf[:500]!r}") + # [FIX 25] SELF-HEALING STUCK DETECTOR + # When ALL parsers returned empty and text has intent signals, synthesize a + # command so the agent loop doesn't stall. This catches: + # - Bare text with no tool call format at all + # - Unrecognized XML-ish blocks + # - Partial JSON (bare "{") + # - Model explaining what it wants to do but not producing a tool call + if not parsed_tool_calls and len(text_buf) > 10: + _synth_cmd = None + _synth_just = None + _tl = text_buf.lower() + + # Heuristic 1: URL in text → fetch it + _url_in_text = re.search(r"https?://[^\s\]'\\>\",]+", text_buf) + if _url_in_text: + _synth_url = _url_in_text.group(0).rstrip(")].,;'\\\"") + _synth_cmd = f"curl -sL --max-time 15 '{_synth_url}' 2>/dev/null | head -200" + _synth_just = "Auto-synthesized: URL detected in text, fetching" + + # Heuristic 2: File path references → list or read + if not _synth_cmd: + _file_m = re.search(r"(?:read|open|view|check|examine|cat|show)\s+(?:the\s+)?(?:file\s+)?[`'\"]?(/[^\s'\"]+\.\w+)", _tl) + if _file_m: + _fpath = _file_m.group(1) + _synth_cmd = f"cat '{_fpath}' 2>/dev/null | head -200 || ls -la '{_fpath}'" + _synth_just = f"Auto-synthesized: file reference detected ({_fpath})" + + # Heuristic 3: Shell command mentioned in backticks or quotes + if not _synth_cmd: + _shell_m = re.search(r"[`'\"]((?:curl|wget|git|npm|pip|python|ls|cat|grep|find|mkdir|cd|rm|cp|mv|chmod|docker|make|cargo|go)\s[^\s`'\"]+)", text_buf) + if _shell_m: + _synth_cmd = _shell_m.group(1) + _synth_just = "Auto-synthesized: shell command detected in text" + + # Heuristic 4: "explore" or "fetch" intent + last user URL + if not _synth_cmd and ("explore" in _tl or "fetch" in _tl or "investigate" in _tl or "repository" in _tl): + for _prev_url in _last_user_urls: + _url_m2 = re.search(r"https?://[^\s\]'\\>\",]+", _prev_url) + if _url_m2: + _pu = _url_m2.group(0).rstrip(")].,;'\\\"") + _ecmd, _ejust = _build_explore_cmd(_pu) + if _ecmd: + _synth_cmd = _ecmd + _synth_just = _ejust or "Auto-synthesized: explore intent with last user URL" + break + + # Heuristic 5: Generic "I need to" / "let me" / "I'll" intent with command-like text + if not _synth_cmd: + _intent_m = re.search(r"(?:I(?:'ll| will| need to| should)|let me|please)\s+(.+?)(?:\.|!|\n|$)", _tl, re.IGNORECASE) + if _intent_m: + _intent_text = _intent_m.group(1).strip() + if len(_intent_text) > 10 and len(_intent_text) < 200: + _synth_cmd = f"echo 'Stuck recovery: model intent was: {_intent_text[:100]}'" + _synth_just = f"Auto-synthesized from intent text: {_intent_text[:80]}" + + if _synth_cmd: + parsed_tool_calls = [{ + "full_match": "__synth_stuck_recovery__", + "name": "exec_command", + "arguments": json.dumps({"cmd": _synth_cmd, "justification": _synth_just or "Auto-synthesized stuck recovery"}, ensure_ascii=False), + }] + _deflog(f"[CC-DEBUG] [STUCK-RECOVERY] Synthesized: cmd={_synth_cmd[:120]!r}") + print(f"[CC-DEBUG] [STUCK-RECOVERY] Synthesized command from text intent", file=sys.stderr, flush=True) + # Also log to stderr for visibility when not piped print(f"[CC-DEBUG] text_buf={len(text_buf)} chars, tool_calls={len(parsed_tool_calls)}", file=sys.stderr, flush=True) @@ -4782,6 +4946,42 @@ Postamble text.""" except Exception as e: _check(f"DSML name=cmd: arguments parsing error: {e}", False) + # Pattern M: explore_agent with nested JSON messages containing URL (FIX 23) + _explore_nested = '\nmessages: [{"content": "Understand the Z.AI-Chat-for-Android repo at https://github.rommark.dev/admin/Z.AI-Chat-for-Android"}]\n' + _calls_m = _parse_commandcode_text_tool_calls(_explore_nested) + _check("FIX23 explore nested JSON: parsed", len(_calls_m) == 1, f"got {len(_calls_m)} calls") + if _calls_m: + _args_m = json.loads(_calls_m[0].get("arguments", "{}")) + _check("FIX23 explore nested JSON: cmd has curl", "curl" in _args_m.get("cmd", ""), f"got {_args_m.get('cmd')!r}") + _check("FIX23 explore nested JSON: URL in cmd", "github.rommark.dev" in _args_m.get("cmd", ""), f"missing URL in cmd") + + # Pattern N: require_escalation block (FIX 24) + _esc_text = 'I need to run a command with elevated permissions to access the repository at https://github.rommark.dev/admin/Z.AI-Chat-for-Android' + _calls_n = _parse_commandcode_text_tool_calls(_esc_text) + _check("FIX24 require_escalation: parsed", len(_calls_n) == 1, f"got {len(_calls_n)} calls") + if _calls_n: + _args_n = json.loads(_calls_n[0].get("arguments", "{}")) + _check("FIX24 require_escalation: name is exec_command", _calls_n[0].get("name") == "exec_command", f"got {_calls_n[0].get('name')}") + _check("FIX24 require_escalation: cmd has curl or echo", "curl" in _args_n.get("cmd", "") or "echo" in _args_n.get("cmd", ""), f"got {_args_n.get('cmd')!r}") + + # Pattern N2: bare request_escalation_permission tag (FIX 24b) + _esc_bare = 'I want to proceed.\n\nPlease let me continue.' + _calls_n2 = _parse_commandcode_text_tool_calls(_esc_bare) + _check("FIX24b bare escalation: parsed", len(_calls_n2) == 1, f"got {len(_calls_n2)} calls") + if _calls_n2: + _check("FIX24b bare escalation: name is exec_command", _calls_n2[0].get("name") == "exec_command", f"got {_calls_n2[0].get('name')}") + + # Pattern O: _build_explore_cmd module-level function (FIX 23/25) + _cmd_o, _just_o = _build_explore_cmd("https://github.rommark.dev/admin/Z.AI-Chat-for-Android") + _check("FIX23/25 _build_explore_cmd: returns cmd", _cmd_o is not None, "returned None") + _check("FIX23/25 _build_explore_cmd: has curl", _cmd_o and "curl" in _cmd_o, f"no curl in {_cmd_o!r}") + _check("FIX23/25 _build_explore_cmd: has api path", _cmd_o and "/api/v1/repos/" in _cmd_o, f"no api path in {_cmd_o!r}") + + # Pattern O2: _build_explore_cmd with JSON array containing URL + _cmd_o2, _ = _build_explore_cmd('[{"content": "https://github.rommark.dev/admin/Z.AI-Chat-for-Android"}]') + _check("FIX23/25 _build_explore_cmd from JSON array: returns cmd", _cmd_o2 is not None, "returned None") + _check("FIX23/25 _build_explore_cmd from JSON array: has curl", _cmd_o2 and "curl" in _cmd_o2, f"no curl in {_cmd_o2!r}") + print(f"[CC-SELF-TEST] Results: {_counts[0]} passed, {_counts[1]} failed", file=sys.stderr) if _counts[1]: