any路由器因为跟claude code有一些参数适配的问题,所以我们可以在本地架设一个简单的网关,将参数在本地拦截,然后修改一下,再传给any大善人,就可以绕过这些参数适配的小问题了。 claudecode最新版本适用,不需要回退版本 这个本地网关做了什么 在本地监听 127.0.0.1:1998。 把 Claude Code 的请求转发到上游any的端口。 自动补认证头(Authorization / x-api-key)。 对 haiku 请求额外修正:补 context-1m-2025-08-07,并加 thinking.budget_tokens=1024。 把请求和响应写到 gateway_requests.jsonl 方便排错。 极简启动步骤 先开网关 export ANTHROPIC_BASE_URL=“any大善人地址” export ANTHROPIC_AUTH_TOKEN=“你的真实token” python3 /Users/Apple/Desktop/code/claude_gateway.py 新开一个终端再开 Claude Code ANTHROPIC_BASE_URL=“ http://127.0.0.1:1998 ” claude --enable-auto-mode 截图为证: 网关代码如下(vibe写的,很多冗余,大佬可以自行修改): #!/usr/bin/env python3 import base64 import json import os import threading from datetime import datetime, timezone from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from urllib.error import HTTPError, URLError from urllib.parse import urlsplit, urlunsplit from urllib.request import Request, urlopen LISTEN_HOST = os.getenv("CLAUDE_GATEWAY_HOST", "127.0.0.1") LISTEN_PORT = int(os.getenv("CLAUDE_GATEWAY_PORT", "1998")) UPSTREAM_BASE_URL = os.getenv( "ANTHROPIC_BASE_URL", "https://a-ocnfniawgw.cn-shanghai.fcapp.run" ) UPSTREAM_AUTH_TOKEN = os.getenv("ANTHROPIC_AUTH_TOKEN", "") UPSTREAM_TIMEOUT = float(os.getenv("CLAUDE_GATEWAY_TIMEOUT", "120")) LOG_PATH = os.getenv( "CLAUDE_GATEWAY_LOG", os.path.join(os.path.dirname(__file__), "gateway_requests.jsonl") ) LOG_LOCK = threading.Lock() def utc_now_iso() -> str: return datetime.now(timezone.utc).isoformat() def ensure_log_parent_exists() -> None: parent = os.path.dirname(LOG_PATH) if parent: os.makedirs(parent, exist_ok=True) def decode_body_for_log(body: bytes) -> dict: if not body: return {"encoding": "utf-8", "text": ""} try: return {"encoding": "utf-8", "text": body.decode("utf-8")} except UnicodeDecodeError: return {"encoding": "base64", "text": base64.b64encode(body).decode("ascii")} def append_log(record: dict) -> None: ensure_log_parent_exists() line = json.dumps(record, ensure_ascii=False) with LOG_LOCK: with open(LOG_PATH, "a", encoding="utf-8") as f: f.write(line + "\n") def build_upstream_url(base_url: str, incoming_path: str) -> str: base = urlsplit(base_url) incoming = urlsplit(incoming_path) incoming_path_only = incoming.path or "/" base_path = base.path.rstrip("/") if base_path: merged_path = f"{base_path}{incoming_path_only}" else: merged_path = incoming_path_only return urlunsplit((base.scheme, base.netloc, merged_path, incoming.query, "")) def rewrite_request_headers(headers: dict, path: str) -> dict: rewritten = dict(headers) if UPSTREAM_AUTH_TOKEN: has_x_api_key = any(k.lower() == "x-api-key" for k in rewritten) has_authorization = any(k.lower() == "authorization" for k in rewritten) if not has_x_api_key: rewritten["x-api-key"] = UPSTREAM_AUTH_TOKEN if not has_authorization: rewritten["Authorization"] = f"Bearer {UPSTREAM_AUTH_TOKEN}" # 先做骨架,后续按 any 规则逐步覆写。 return rewritten def rewrite_request_body(body: bytes, headers: dict, path: str) -> bytes: if not body: return body content_type = "" for k, v in headers.items(): if k.lower() == "content-type": content_type = v break if "application/json" not in content_type.lower(): return body try: payload = json.loads(body.decode("utf-8")) except (UnicodeDecodeError, json.JSONDecodeError): return body model = str(payload.get("model", "")).lower() if not model.startswith("claude-haiku"): return body beta_key = None for k in headers.keys(): if k.lower() == "anthropic-beta": beta_key = k break raw_beta = headers.get(beta_key, "") if beta_key else "" beta_features = [item.strip() for item in raw_beta.split(",") if item.strip()] if "context-1m-2025-08-07" not in beta_features: beta_features.append("context-1m-2025-08-07") merged_beta = ",".join(beta_features) if beta_key: headers[beta_key] = merged_beta else: headers["anthropic-beta"] = merged_beta payload["thinking"] = {"type": "enabled", "budget_tokens": 1024} return json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8") class ClaudeGatewayHandler(BaseHTTPRequestHandler): protocol_version = "HTTP/1.1" def do_GET(self): self._handle_proxy() def do_POST(self): self._handle_proxy() def do_PUT(self): self._handle_proxy() def do_PATCH(self): self._handle_proxy() def do_DELETE(self): self._handle_proxy() def do_OPTIONS(self): self._handle_proxy() def do_HEAD(self): self._handle_proxy() def log_message(self, fmt, *args): return def _read_request_body(self) -> bytes: content_length = int(self.headers.get("Content-Length", "0") or "0") if content_length <= 0: return b"" return self.rfile.read(content_length) def _copy_request_headers(self) -> dict: headers = {} for key, value in self.headers.items(): key_l = key.lower() if key_l in {"host", "content-length", "connection", "accept-encoding"}: continue headers[key] = value return headers def _send_response(self, status: int, headers: dict, body: bytes) -> None: self.send_response(status) ignored = {"transfer-encoding", "content-length", "connection"} for k, v in headers.items(): if k.lower() in ignored: continue self.send_header(k, v) self.send_header("Content-Length", str(len(body))) self.send_header("Connection", "close") self.end_headers() if self.command != "HEAD" and body: self.wfile.write(body) def _handle_proxy(self): req_body = self._read_request_body() req_headers = self._copy_request_headers() req_headers = rewrite_request_headers(req_headers, self.path) req_body = rewrite_request_body(req_body, req_headers, self.path) upstream_url = build_upstream_url(UPSTREAM_BASE_URL, self.path) request_log = { "timestamp": utc_now_iso(), "client_ip": self.client_address[0] if self.client_address else "", "method": self.command, "path": self.path, "upstream_url": upstream_url, "headers": dict(self.headers.items()), "body": decode_body_for_log(req_body), "body_length": len(req_body), } try: upstream_req = Request( url=upstream_url, data=req_body if req_body else None, headers=req_headers, method=self.command, ) with urlopen(upstream_req, timeout=UPSTREAM_TIMEOUT) as resp: resp_status = resp.getcode() resp_headers = dict(resp.headers.items()) resp_body = resp.read() request_log["response"] = { "status": resp_status, "headers": resp_headers, "body": decode_body_for_log(resp_body), "body_length": len(resp_body), } append_log(request_log) self._send_response(resp_status, resp_headers, resp_body) return except HTTPError as e: err_body = e.read() if hasattr(e, "read") else b"" err_headers = dict(e.headers.items()) if getattr(e, "headers", None) else {} request_log["response"] = { "status": e.code, "headers": err_headers, "body": decode_body_for_log(err_body), "body_length": len(err_body), } append_log(request_log) self._send_response(e.code, err_headers, err_body) return except (URLError, TimeoutError, Exception) as e: error_payload = { "error": "gateway_upstream_error", "message": str(e), } error_body = json.dumps(error_payload, ensure_ascii=False).encode("utf-8") request_log["response"] = { "status": 502, "headers": {"Content-Type": "application/json; charset=utf-8"}, "body": {"encoding": "utf-8", "text": error_body.decode("utf-8")}, "body_length": len(error_body), } append_log(request_log) self._send_response( 502, {"Content-Type": "application/json; charset=utf-8"}, error_body, ) def main(): server = ThreadingHTTPServer((LISTEN_HOST, LISTEN_PORT), ClaudeGatewayHandler) print(f"[gateway] listening on http://{LISTEN_HOST}:{LISTEN_PORT}") print(f"[gateway] upstream: {UPSTREAM_BASE_URL}") print(f"[gateway] auth token configured: {bool(UPSTREAM_AUTH_TOKEN)}") print(f"[gateway] log file: {LOG_PATH}") server.serve_forever() if __name__ == "__main__": main() 3 个帖子 - 2 位参与者 阅读完整话题
基于最新版的Claude Code,大概半个小时就调好了六个类别的前端样式。 没有复杂的提示词,只有简单的截图。 1 个帖子 - 1 位参与者 阅读完整话题
刚登录没看几个贴就登录掉了,要重新登录,一直这样子好麻烦,最新版 fluxdo 5 个帖子 - 5 位参与者 阅读完整话题
我发现最新Claude code已无法直接在Android termux用npm安装来直接使用,会有报错,肯定是Termux环境的兼容问题,毕竟不是标准的Linux。如何解决: 1.非proot方案(推荐) #!/data/data/com.termux/files/usr/bin/bash set -euo pipefail readonly SCRIPT_NAME="$(basename "$0")" readonly PREFIX_DIR="${PREFIX:-/data/data/com.termux/files/usr}" readonly STATE_DIR="${CLAUDE_CODE_HOME:-$HOME/.claude-code-termux}" readonly NODE_DIR="$STATE_DIR/node" readonly WRAPPER_BIN_DIR="$STATE_DIR/bin" readonly PATCH_DIR="$STATE_DIR/patches" readonly GLOBAL_PREFIX_DIR="$STATE_DIR/npm-global" readonly GLOBAL_BIN_DIR="$GLOBAL_PREFIX_DIR/bin" readonly NPM_CACHE_DIR="$STATE_DIR/npm-cache" readonly TMP_ROOT_DIR="${TMPDIR:-$PREFIX_DIR/tmp}" readonly GLIBC_LDSO="$PREFIX_DIR/glibc/lib/ld-linux-aarch64.so.1" readonly GLIBC_RUNNER_BIN="$PREFIX_DIR/bin/grun" readonly GLIBC_MARKER="$STATE_DIR/.glibc-arch" readonly HOST_CLAUDE_PATH="$PREFIX_DIR/bin/claude" readonly BACKUP_DIR="$STATE_DIR/backups" readonly CLAUDE_PACKAGE_NAME="@anthropic-ai/claude-code" readonly CLAUDE_PACKAGE_VERSION="${CLAUDE_CODE_VERSION:-latest}" readonly NODE_VERSION="${CLAUDE_CODE_NODE_VERSION:-22.22.0}" readonly NODE_TARBALL="node-v${NODE_VERSION}-linux-arm64.tar.xz" readonly NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}" readonly COMPAT_PATCH_PATH="$PATCH_DIR/claude-glibc-compat.js" readonly CLAUDE_EXE_PATH="$GLOBAL_PREFIX_DIR/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe" readonly HOST_WRAPPER_MARKER="# claude-code-termux-nonproot-wrapper" readonly C_BOLD_BLUE="\033[1;34m" readonly C_BOLD_GREEN="\033[1;32m" readonly C_BOLD_YELLOW="\033[1;33m" readonly C_BOLD_RED="\033[1;31m" readonly C_RESET="\033[0m" info() { printf '%b[INFO]%b %s\n' "$C_BOLD_BLUE" "$C_RESET" "$*" } success() { printf '%b[ OK ]%b %s\n' "$C_BOLD_GREEN" "$C_RESET" "$*" } warn() { printf '%b[WARN]%b %s\n' "$C_BOLD_YELLOW" "$C_RESET" "$*" >&2 } die() { printf '%b[ERR ]%b %s\n' "$C_BOLD_RED" "$C_RESET" "$*" >&2 exit 1 } usage() { cat <<EOF Usage: bash $SCRIPT_NAME What it does: 1. Installs Termux dependencies needed for a glibc-based Node runtime. 2. Installs glibc-runner through pacman (no proot distro). 3. Downloads official Node.js ${NODE_VERSION} linux-arm64. 4. Wraps node/npm with ld.so so they run on Termux. 5. Installs ${CLAUDE_PACKAGE_NAME} and exposes it as: $HOST_CLAUDE_PATH Environment overrides: CLAUDE_CODE_HOME install state dir, default: $STATE_DIR CLAUDE_CODE_VERSION npm package version/tag, default: $CLAUDE_PACKAGE_VERSION CLAUDE_CODE_NODE_VERSION Node.js linux-arm64 version, default: $NODE_VERSION Notes: - This follows the non-proot glibc-wrapper approach used by openclaw-android. - Only aarch64 Termux is supported. - Existing $HOST_CLAUDE_PATH will be backed up if it is not already managed. EOF } command_exists() { command -v "$1" >/dev/null 2>&1 } require_termux() { [ -d "$PREFIX_DIR" ] || die "This script must run in Termux." command_exists pkg || die "pkg not found. This script must run in Termux." } ensure_tmp_root() { mkdir -p "$TMP_ROOT_DIR" } ensure_state_dirs() { mkdir -p "$STATE_DIR" "$WRAPPER_BIN_DIR" "$PATCH_DIR" "$GLOBAL_PREFIX_DIR" \ "$GLOBAL_BIN_DIR" "$NPM_CACHE_DIR" "$BACKUP_DIR" } ensure_termux_package() { local package_name="$1" if dpkg -s "$package_name" >/dev/null 2>&1; then success "Termux package already installed: $package_name" return 0 fi info "Installing Termux package: $package_name" pkg install -y "$package_name" success "Installed Termux package: $package_name" } ensure_glibc_runner() { local arch local pacman_conf local siglevel_patched=0 arch="$(uname -m)" [ "$arch" = "aarch64" ] || die "glibc mode only supports aarch64, got: $arch" if [ -f "$GLIBC_MARKER" ] && [ -x "$GLIBC_LDSO" ]; then success "glibc-runner already available" return 0 fi ensure_termux_package "pacman" pacman_conf="$PREFIX_DIR/etc/pacman.conf" info "Initializing pacman for glibc-runner" if [ -f "$pacman_conf" ] && ! grep -q '^SigLevel = Never' "$pacman_conf"; then cp "$pacman_conf" "${pacman_conf}.bak" sed -i 's/^SigLevel\s*=.*/SigLevel = Never/' "$pacman_conf" siglevel_patched=1 warn "Applied temporary pacman SigLevel workaround" fi pacman-key --init 2>/dev/null || true pacman-key --populate 2>/dev/null || true info "Installing glibc-runner" if ! pacman -Sy glibc-runner --noconfirm --assume-installed bash,patchelf,resolv-conf; then if [ "$siglevel_patched" -eq 1 ] && [ -f "${pacman_conf}.bak" ]; then mv "${pacman_conf}.bak" "$pacman_conf" fi die "Failed to install glibc-runner" fi if [ "$siglevel_patched" -eq 1 ] && [ -f "${pacman_conf}.bak" ]; then mv "${pacman_conf}.bak" "$pacman_conf" success "Restored pacman SigLevel" fi [ -x "$GLIBC_LDSO" ] || die "glibc dynamic linker not found at $GLIBC_LDSO" touch "$GLIBC_MARKER" success "glibc-runner is ready" } write_compat_patch() { info "Writing Node compatibility patch" cat >"$COMPAT_PATCH_PATH" <<'EOF' 'use strict'; const childProcess = require('child_process'); const dns = require('dns'); const fs = require('fs'); const os = require('os'); const path = require('path'); const prefix = process.env.PREFIX || '/data/data/com.termux/files/usr'; const home = process.env.HOME || '/data/data/com.termux/files/home'; const wrapperPath = process.env._CLAUDE_WRAPPER_PATH || path.join(home, '.claude-code-termux', 'bin', 'node'); const termuxExec = path.join(prefix, 'lib', 'libtermux-exec-ld-preload.so'); const termuxShell = path.join(prefix, 'bin', 'sh'); try { if (fs.existsSync(wrapperPath)) { Object.defineProperty(process, 'execPath', { value: wrapperPath, writable: true, configurable: true, }); } } catch {} if (process.env._CLAUDE_ORIG_LD_PRELOAD) { process.env.LD_PRELOAD = process.env._CLAUDE_ORIG_LD_PRELOAD; delete process.env._CLAUDE_ORIG_LD_PRELOAD; } else if (!process.env.LD_PRELOAD) { try { if (fs.existsSync(termuxExec)) { process.env.LD_PRELOAD = termuxExec; } } catch {} } const originalCpus = os.cpus; os.cpus = function cpus() { try { const result = originalCpus.call(os); if (Array.isArray(result) && result.length > 0) { return result; } } catch {} return [{ model: 'unknown', speed: 0, times: { user: 0, nice: 0, sys: 0, idle: 0, irq: 0 }, }]; }; const originalNetworkInterfaces = os.networkInterfaces; os.networkInterfaces = function networkInterfaces() { try { return originalNetworkInterfaces.call(os); } catch { return { lo: [{ address: '127.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: true, cidr: '127.0.0.1/8', }], }; } }; if (!fs.existsSync('/bin/sh') && fs.existsSync(termuxShell)) { const originalExec = childProcess.exec; const originalExecSync = childProcess.execSync; childProcess.exec = function exec(command, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } options = options || {}; if (!options.shell) { options.shell = termuxShell; } return originalExec.call(childProcess, command, options, callback); }; childProcess.execSync = function execSync(command, options) { options = options || {}; if (!options.shell) { options.shell = termuxShell; } return originalExecSync.call(childProcess, command, options); }; } try { let dnsServers = ['8.8.8.8', '8.8.4.4']; try { const resolvConf = fs.readFileSync(path.join(prefix, 'etc', 'resolv.conf'), 'utf8'); const matches = resolvConf.match(/^nameserver\s+(.+)$/gm); if (matches && matches.length > 0) { dnsServers = matches.map((line) => line.replace(/^nameserver\s+/, '').trim()); } } catch {} try { dns.setServers(dnsServers); } catch {} const originalLookup = dns.lookup; const originalLookupPromise = dns.promises.lookup; dns.lookup = function lookup(hostname, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } const originalOptions = options; const opts = typeof options === 'number' ? { family: options } : (options || {}); const wantAll = opts.all === true; const family = opts.family || 0; const resolveWith = (fam, done) => { const resolver = fam === 6 ? dns.resolve6 : dns.resolve4; resolver(hostname, done); }; const tryResolve = (fam) => { resolveWith(fam, (error, addresses) => { if (!error && Array.isArray(addresses) && addresses.length > 0) { const resolvedFamily = fam === 6 ? 6 : 4; if (wantAll) { callback(null, addresses.map((address) => ({ address, family: resolvedFamily, }))); return; } callback(null, addresses[0], resolvedFamily); return; } if (family === 0 && fam === 4) { tryResolve(6); return; } originalLookup.call(dns, hostname, originalOptions, callback); }); }; tryResolve(family === 6 ? 6 : 4); }; dns.promises.lookup = async function lookup(hostname, options) { const opts = typeof options === 'number' ? { family: options } : (options || {}); const wantAll = opts.all === true; const family = opts.family || 0; const resolveWith = family === 6 ? dns.promises.resolve6 : dns.promises.resolve4; try { const addresses = await resolveWith(hostname); if (addresses.length > 0) { const resolvedFamily = family === 6 ? 6 : 4; if (wantAll) { return addresses.map((address) => ({ address, family: resolvedFamily, })); } return { address: addresses[0], family: resolvedFamily, }; } } catch {} if (family === 0) { try { const addresses = await dns.promises.resolve6(hostname); if (addresses.length > 0) { if (wantAll) { return addresses.map((address) => ({ address, family: 6 })); } return { address: addresses[0], family: 6, }; } } catch {} } return originalLookupPromise.call(dns.promises, hostname, options); }; } catch {} EOF success "Compatibility patch written to $COMPAT_PATCH_PATH" } write_node_wrappers() { local node_bin_path local node_real_path node_bin_path="$NODE_DIR/bin/node" node_real_path="$NODE_DIR/bin/node.real" if [ -f "$node_real_path" ]; then : elif [ -f "$node_bin_path" ]; then mv "$node_bin_path" "$node_real_path" else die "Node binary missing at $node_bin_path" fi info "Writing node/npm wrappers" cat >"$WRAPPER_BIN_DIR/node" <<EOF #!$PREFIX_DIR/bin/bash [ -n "\${LD_PRELOAD:-}" ] && export _CLAUDE_ORIG_LD_PRELOAD="\$LD_PRELOAD" unset LD_PRELOAD export _CLAUDE_WRAPPER_PATH="$WRAPPER_BIN_DIR/node" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" _CLAUDE_COMPAT="$COMPAT_PATCH_PATH" if [ -f "\$_CLAUDE_COMPAT" ]; then case "\${NODE_OPTIONS:-}" in *"\$_CLAUDE_COMPAT"*) ;; *) export NODE_OPTIONS="\${NODE_OPTIONS:+\$NODE_OPTIONS }-r \$_CLAUDE_COMPAT" ;; esac fi exec "$GLIBC_LDSO" --library-path "$PREFIX_DIR/glibc/lib" "$NODE_DIR/bin/node.real" "\$@" EOF cat >"$WRAPPER_BIN_DIR/npm" <<EOF #!$PREFIX_DIR/bin/bash export PATH="$WRAPPER_BIN_DIR:$NODE_DIR/bin:\$PATH" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" export NPM_CONFIG_PREFIX="$GLOBAL_PREFIX_DIR" export npm_config_prefix="$GLOBAL_PREFIX_DIR" export NPM_CONFIG_CACHE="$NPM_CACHE_DIR" export npm_config_cache="$NPM_CACHE_DIR" export NPM_CONFIG_SCRIPT_SHELL="$PREFIX_DIR/bin/sh" export npm_config_script_shell="$PREFIX_DIR/bin/sh" exec "$WRAPPER_BIN_DIR/node" "$NODE_DIR/lib/node_modules/npm/bin/npm-cli.js" "\$@" EOF cat >"$WRAPPER_BIN_DIR/npx" <<EOF #!$PREFIX_DIR/bin/bash export PATH="$WRAPPER_BIN_DIR:$NODE_DIR/bin:\$PATH" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" export NPM_CONFIG_PREFIX="$GLOBAL_PREFIX_DIR" export npm_config_prefix="$GLOBAL_PREFIX_DIR" export NPM_CONFIG_CACHE="$NPM_CACHE_DIR" export npm_config_cache="$NPM_CACHE_DIR" export NPM_CONFIG_SCRIPT_SHELL="$PREFIX_DIR/bin/sh" export npm_config_script_shell="$PREFIX_DIR/bin/sh" exec "$WRAPPER_BIN_DIR/node" "$NODE_DIR/lib/node_modules/npm/bin/npx-cli.js" "\$@" EOF chmod 755 "$WRAPPER_BIN_DIR/node" "$WRAPPER_BIN_DIR/npm" "$WRAPPER_BIN_DIR/npx" success "node/npm wrappers are ready" } install_node_runtime() { local installed_version local tmp_dir local extract_dir local fresh_dir ensure_termux_package "curl" ensure_termux_package "xz-utils" if [ -x "$WRAPPER_BIN_DIR/node" ]; then installed_version="$("$WRAPPER_BIN_DIR/node" --version 2>/dev/null | sed 's/^v//')" if [ "$installed_version" = "$NODE_VERSION" ]; then success "Node.js already installed: v$installed_version" write_compat_patch write_node_wrappers return 0 fi fi info "Downloading official Node.js ${NODE_VERSION} linux-arm64" tmp_dir="$(mktemp -d "$TMP_ROOT_DIR/claude-node.XXXXXX")" curl -fL --max-time 300 "$NODE_URL" -o "$tmp_dir/$NODE_TARBALL" success "Downloaded $NODE_TARBALL" extract_dir="$tmp_dir/extract" fresh_dir="$tmp_dir/node-fresh" mkdir -p "$extract_dir" "$fresh_dir" tar -xJf "$tmp_dir/$NODE_TARBALL" -C "$extract_dir" mv "$extract_dir"/node-v"${NODE_VERSION}"-linux-arm64/* "$fresh_dir"/ rm -rf "$NODE_DIR" mkdir -p "$(dirname "$NODE_DIR")" mv "$fresh_dir" "$NODE_DIR" write_compat_patch write_node_wrappers rm -rf "$tmp_dir" success "Node.js runtime installed in $NODE_DIR" } install_claude_package() { local package_spec package_spec="$CLAUDE_PACKAGE_NAME" if [ "$CLAUDE_PACKAGE_VERSION" != "latest" ]; then package_spec="${CLAUDE_PACKAGE_NAME}@${CLAUDE_PACKAGE_VERSION}" fi info "Installing $package_spec" PATH="$WRAPPER_BIN_DIR:$GLOBAL_BIN_DIR:$PATH" "$WRAPPER_BIN_DIR/npm" install -g "$package_spec" [ -e "$GLOBAL_BIN_DIR/claude" ] || die "npm install completed, but $GLOBAL_BIN_DIR/claude was not created" [ -x "$CLAUDE_EXE_PATH" ] || die "Claude native binary missing at $CLAUDE_EXE_PATH" success "Claude Code is installed under $GLOBAL_PREFIX_DIR" } backup_existing_launcher() { local backup_path if [ ! -e "$HOST_CLAUDE_PATH" ]; then return 0 fi if grep -Fq "$HOST_WRAPPER_MARKER" "$HOST_CLAUDE_PATH" 2>/dev/null; then success "Managed host launcher already present" return 0 fi backup_path="$BACKUP_DIR/claude.host-backup.$(date +%Y%m%d_%H%M%S)" cp "$HOST_CLAUDE_PATH" "$backup_path" success "Backed up existing launcher to $backup_path" } install_host_wrapper() { local tmp_wrapper tmp_wrapper="$(mktemp "$TMP_ROOT_DIR/claude-wrapper.XXXXXX")" cat >"$tmp_wrapper" <<EOF #!$PREFIX_DIR/bin/bash $HOST_WRAPPER_MARKER export PATH="$WRAPPER_BIN_DIR:$GLOBAL_BIN_DIR:\$PATH" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" exec "$GLIBC_RUNNER_BIN" -t "$CLAUDE_EXE_PATH" "\$@" EOF chmod 755 "$tmp_wrapper" cp "$tmp_wrapper" "$HOST_CLAUDE_PATH" chmod 755 "$HOST_CLAUDE_PATH" rm -f "$tmp_wrapper" success "Installed host launcher: $HOST_CLAUDE_PATH" } verify_install() { info "Verifying Node wrapper" "$WRAPPER_BIN_DIR/node" --version info "Verifying npm wrapper" "$WRAPPER_BIN_DIR/npm" --version info "Verifying Claude Code launcher" "$HOST_CLAUDE_PATH" --version success "Non-proot Claude Code setup completed" } main() { if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then usage exit 0 fi require_termux ensure_tmp_root ensure_state_dirs ensure_glibc_runner install_node_runtime install_claude_package backup_existing_launcher install_host_wrapper verify_install cat <<EOF Run Claude Code with: claude Current configuration: state dir: $STATE_DIR node version: $NODE_VERSION package version: $CLAUDE_PACKAGE_VERSION launcher: $HOST_CLAUDE_PATH EOF } main "$@" 2.proot方案 (会卡顿 卡就对了 卡了就等待) #!/data/data/com.termux/files/usr/bin/bash set -euo pipefail readonly SCRIPT_NAME="$(basename "$0")" readonly DISTRO_NAME="${CLAUDE_CODE_DISTRO:-debian}" readonly CLAUDE_PACKAGE_NAME="@anthropic-ai/claude-code" readonly CLAUDE_PACKAGE_VERSION="${CLAUDE_CODE_VERSION:-latest}" readonly PREFIX_DIR="${PREFIX:-/data/data/com.termux/files/usr}" readonly HOST_CLAUDE_PATH="$PREFIX_DIR/bin/claude" readonly PROOT_ROOT_DIR="$PREFIX_DIR/var/lib/proot-distro/installed-rootfs" readonly BACKUP_DIR="$HOME/.codex/tmp" readonly WRAPPER_MARKER="# claude-code-termux-wrapper" readonly C_BOLD_BLUE="\033[1;34m" readonly C_BOLD_GREEN="\033[1;32m" readonly C_BOLD_YELLOW="\033[1;33m" readonly C_BOLD_RED="\033[1;31m" readonly C_RESET="\033[0m" info() { printf '%b[INFO]%b %s\n' "$C_BOLD_BLUE" "$C_RESET" "$*" } success() { printf '%b[ OK ]%b %s\n' "$C_BOLD_GREEN" "$C_RESET" "$*" } warn() { printf '%b[WARN]%b %s\n' "$C_BOLD_YELLOW" "$C_RESET" "$*" >&2 } die() { printf '%b[ERR ]%b %s\n' "$C_BOLD_RED" "$C_RESET" "$*" >&2 exit 1 } usage() { cat <<EOF Usage: bash $SCRIPT_NAME What it does: 1. Installs proot-distro in Termux if needed. 2. Installs Debian userspace if needed. 3. Installs nodejs + npm inside Debian. 4. Installs ${CLAUDE_PACKAGE_NAME} inside Debian. 5. Replaces Termux's claude launcher with a wrapper that forwards into Debian. Environment overrides: CLAUDE_CODE_DISTRO proot distro alias, default: ${DISTRO_NAME} CLAUDE_CODE_VERSION npm package version/tag, default: ${CLAUDE_PACKAGE_VERSION} Notes: - Official Claude Code npm binaries do not support Termux's android-arm64 host. - This script uses Debian in proot as the supported Linux runtime. EOF } command_exists() { command -v "$1" >/dev/null 2>&1 } require_termux() { [ -d "$PREFIX_DIR" ] || die "This script must run in Termux." command_exists pkg || die "pkg not found. This script must run in Termux." } ensure_termux_package() { local package_name="$1" if dpkg -s "$package_name" >/dev/null 2>&1; then success "Termux package already installed: $package_name" return 0 fi info "Installing Termux package: $package_name" pkg install -y "$package_name" success "Installed Termux package: $package_name" } ensure_distro() { if [ -d "$PROOT_ROOT_DIR/$DISTRO_NAME" ]; then success "proot distro already installed: $DISTRO_NAME" return 0 fi info "Installing proot distro: $DISTRO_NAME" proot-distro install "$DISTRO_NAME" success "Installed proot distro: $DISTRO_NAME" } run_in_distro() { local command_text="$1" proot-distro login "$DISTRO_NAME" -- bash -lc "$command_text" } ensure_distro_packages() { info "Updating apt metadata inside $DISTRO_NAME" run_in_distro "env DEBIAN_FRONTEND=noninteractive apt-get update" info "Installing nodejs and npm inside $DISTRO_NAME" run_in_distro "env DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs npm" success "nodejs and npm are ready inside $DISTRO_NAME" } install_claude_in_distro() { local package_spec="$CLAUDE_PACKAGE_NAME" if [ "$CLAUDE_PACKAGE_VERSION" != "latest" ]; then package_spec="${CLAUDE_PACKAGE_NAME}@${CLAUDE_PACKAGE_VERSION}" fi info "Installing ${package_spec} inside $DISTRO_NAME" run_in_distro "npm install -g ${package_spec@Q}" success "Claude Code is installed inside $DISTRO_NAME" } backup_existing_launcher() { local backup_path mkdir -p "$BACKUP_DIR" if [ ! -e "$HOST_CLAUDE_PATH" ]; then return 0 fi if grep -Fq "$WRAPPER_MARKER" "$HOST_CLAUDE_PATH" 2>/dev/null; then success "Managed Termux launcher already present" return 0 fi backup_path="$BACKUP_DIR/claude.host-backup.$(date +%Y%m%d_%H%M%S)" cp "$HOST_CLAUDE_PATH" "$backup_path" success "Backed up existing launcher to $backup_path" } install_host_wrapper() { local tmp_wrapper tmp_wrapper="$(mktemp "${TMPDIR:-/tmp}/claude-wrapper.XXXXXX")" cat >"$tmp_wrapper" <<EOF #!/data/data/com.termux/files/usr/bin/sh $WRAPPER_MARKER work_dir=\$PWD if [ ! -d "\$work_dir" ]; then work_dir=/root fi exec proot-distro login --shared-tmp --work-dir "\$work_dir" $DISTRO_NAME -- /usr/local/bin/claude "\$@" EOF chmod 755 "$tmp_wrapper" cp "$tmp_wrapper" "$HOST_CLAUDE_PATH" chmod 755 "$HOST_CLAUDE_PATH" rm -f "$tmp_wrapper" success "Installed Termux launcher: $HOST_CLAUDE_PATH" } verify_install() { info "Verifying Claude inside $DISTRO_NAME" run_in_distro "claude --version" info "Verifying Termux launcher" "$HOST_CLAUDE_PATH" --version success "Claude Code setup completed" } main() { if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then usage exit 0 fi require_termux ensure_termux_package "proot-distro" ensure_distro ensure_distro_packages install_claude_in_distro backup_existing_launcher install_host_wrapper verify_install cat <<EOF Run Claude Code with: claude Current configuration: distro: $DISTRO_NAME host launcher: $HOST_CLAUDE_PATH EOF } main "$@" 非proot方案参考 GitHub - AidanPark/openclaw-android: Run OpenClaw on Android with a single command — no proot, no Linux · GitHub 1 个帖子 - 1 位参与者 阅读完整话题
用的中转站,wsl中使用codex cli,版本是最新版 部分配置 sandbox_mode = "workspace-write" approval_policy = "on-request" 3 个帖子 - 2 位参与者 阅读完整话题
前几天使用最新版时完全用不了claude模型,能成功思考,但思考一结束就直接报error……, 预填充相关 (点击了解更多详细信息) 消息块类型相关 (点击了解更多详细信息) 感觉antigravity的客户端确实有很严重的bug(?) 但今天把客户端从最新版换成了1.20.6,目前使用体验非常顺利 opus-4.6两次达到思考上限,retry之后也能顺利进行下去。 讲讲我的具体操作,希望能帮上佬友们: 1.先关闭自动更新 2.在控制面板卸载antigravity最新版 3.去官网下载1.20.6安装包 4.正常安装 5.正常登录 6.正常使用 目前使用的clash verge的TUN模式,节点是美国洛杉矶 大概就这些了 站内有佬提到,如果retry一直存在,可以去gemini cli试试能不能用,retry账号在cli中大概率会报403,可能是谷÷的一种风控形式,这样的话只能换号了 3 个帖子 - 2 位参与者 阅读完整话题
我是真纳闷了,这cpa我更新到最新版(出一版更一版,因为有登陆的有自己的PLus账号,怕没更新容易给号封了。。。) 现在我登陆授权的号都没问题,但是我现在用AI供应商加入中转站一直接入不进去用不了openclaw,一直是这俩错误,但是我导入到ccswith里可以用。 ⚠️ Something went wrong while processing your request. Please try again, or use /new to start a fresh session. ⚠️ API rate limit reached. Please try again later. 把配置文件和问题发给codex,问codex,她说: 为什么 CCSwith 能用,但 OpenClaw 报 429? 大概率不是“CCSwith 比 OpenClaw 更兼容”,而是这几条叠加: • CCSwith 请求更轻、并发更低 • 它可能没踩中同一个冷却窗口 • OpenClaw 这边多 agent / cron 同时吃 gpt-5.4 • 你的 CPA 又给所有 gpt-* 额外注入了超长 prompt • OpenClaw 目前 没有 fallback,所以一旦主模型冷却就直接炸给用户看 这次不是“配错了”,而是“单模型 + 多 agent/cron + CPA 全局注入超长 prompt + 无 fallback”把 gpt-5.4 打进冷却后,OpenClaw 没路可走。 ber,那你这不是神经病么。。。。有没有懂得佬,解解惑,求求了 根本不调用中转站,日志里直接就是失败: 1 个帖子 - 1 位参与者 阅读完整话题
我CC opus4.7为什么还不能切是不是CC要更新最新版吗?。我买的是MAX 20x 11 个帖子 - 7 位参与者 阅读完整话题
早上codexCli升级到最新版本,发现routerAny的codex不能用了,现在降回来,就又可以愉快的coding了 1 个帖子 - 1 位参与者 阅读完整话题
时间轴skills挺不错的,效果如图: 1、先升级到最新版:地址栏输入:chrome://settings/help 检查并更新版本。 2、在地址栏输入 chrome://flags,搜索框输入 skills,找到Enables Skills in Gemini in Chrome – Mac, Windows, Linux, ChromeOS,状态改成Enabled,然后点击右下角的 Relaunch,重启浏览器。 3、在地址栏输入 chrome://skills/browse,打开skills商店。 4、点击chrome右上角Ask Gemini 打开Gemini侧边栏,输入框输入/打开skills快捷菜单,就可以愉快的玩耍了。 感觉这个chrome skills更像prompts ,佬有高级玩法可以分享到本贴。 1 个帖子 - 1 位参与者 阅读完整话题
目前是CPA + new-api,在社区搜了很多帖子,试了几种办法,都不行,最高只能是high 1 个帖子 - 1 位参与者 阅读完整话题
听说谷歌Chrome上线Skills功能,想要尝鲜一下,这下好了,Gemini in Chrome直接没了! 尝试了社区里一些方法,还是没有调出来!!有知道解决方案的佬友吗 Gemini in Chrome现在基本每天都要用到,很方便。现在没了。 5 个帖子 - 3 位参与者 阅读完整话题
cursor 最新版,你们的 chat 会打开就闪退吗 ? 1 个帖子 - 1 位参与者 阅读完整话题
如图:我使用的是docker启动的 2 个帖子 - 2 位参与者 阅读完整话题
之前使用vscode时没有设置代理模式,导致codex一直无法使用。把vscode升级到最新版后,codex更是连登录按钮都没有了。 我一直以为是VPN的原因,想到要去购买静态住宅ip,但是想了想,我gpt官网是能够登录并且正常对话的,所以问题可能是出在vscode上。 vscode上设置代理模式: 使用快捷键 ctrl + , ,打开 设置 。 在搜索框中输入 proxy ,选择 代理服务器 ,点击 在 setting.json 中编辑 在setting.json文件中添加: "http.proxy": "http://your_proxy_server:port", "https.proxy": "http://your_proxy_server:port", "http.proxyStrictSSL": false 如果你本地下载了clash,并且订阅了,则your_proxy_server为 127.0.0.1 ,port一般为 7890 1 个帖子 - 1 位参与者 阅读完整话题
如图,古法注册的账号,用了半小时了,看不到任何请求和额度变化,配置检查了确实是连接到CPA的。有大佬解惑吗 5 个帖子 - 4 位参与者 阅读完整话题
为啥我的 X 不会自动翻译,每次都要点击一下?开了自动翻译、最新版 𝕏 7 个帖子 - 4 位参与者 阅读完整话题
在昨天将 Enpass Mac 更新到最新版之后,UI 确实好看了很多, 但是疯狂的闪退啊,有没有碰到同样情况的,基本不可用啊 1 个帖子 - 1 位参与者 阅读完整话题
先贴链接了: https://github.com/claw-codes/wx4py 刚刚更新了最新版 v0.2.0 ,可以做群聊机器人了