Compare commits

..

10 Commits

Author SHA1 Message Date
hfshfg
9a23aec097 docs: redesign README landing page
Some checks failed
Track OpenClaw upstream / Check upstream & auto-bump (push) Has been cancelled
2026-07-27 23:45:12 +08:00
hfshfg
77a3546459 chore(release): 发布 v2.1.17 — 修复 DeepSeek 已下线模型名
api.deepseek.com 停用 deepseek-chat,配置页和安装脚本仍写死旧名,导致选
DeepSeek 的客户每条消息都 400 失败且界面无报错。详见 0be55b9。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 22:46:11 +08:00
hfshfg
0be55b9064 fix(models): DeepSeek 写死已下线的 deepseek-chat,客户配完必坏
api.deepseek.com 已停用 deepseek-chat / deepseek-coder / deepseek-reasoner,
现在只接受 deepseek-v4-flash 和 deepseek-v4-pro,用旧名调用直接返回:

  400 The supported API model names are deepseek-v4-pro or
      deepseek-v4-flash, but you passed deepseek-chat.

Config.html 把 card.dataset.model 直接写进 openclaw.json 的 models[].id 和
agents.defaults.model.primary,所以客户只要在配置页点「DeepSeek」卡片,配出来
的就是必然失败的配置——网关照常 listening、webchat 照常连上,只在日志里刷
embedded_run_agent_end/isError=True,界面上表现为「发消息没反应」,极难自诊。

客户机 pc-5376 实测:连续 2 小时、20+ 次对话全部 400 失败。

改动(deepseek-chat -> deepseek-v4-flash):
- portable/Config.html                     data-model,落盘值
- portable/config-server/public/index.html data-model,落盘值(同一清单第 2 份拷贝)
- install/install.ps1                      交互式选项 1
- install/install.sh                       交互式选项 1 + 未知选项兜底
- u-claw-app/resources/Config.html         已废弃的 Electron 归档,一并改防止复活
- portable/Mac-Menu.command                提示文字
- portable/skills-cn/deepseek-helper/      技能文档模型表(会被 AI 读取并转述给用户)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 20:48:35 +08:00
u-claw-bot
735e4de854 chore(upstream): 跟随 OpenClaw 2026.7.1-2,发布 v2.1.16
自动跟踪上游:OpenClaw npm latest 升到 2026.7.1-2,
自动 bump 壳版本到 2.1.16 并打 tag 触发发版。
2026-07-19 04:17:40 +00:00
u-claw-bot
50a4e45ea4 chore(upstream): 跟随 OpenClaw 2026.7.1-1,发布 v2.1.15
自动跟踪上游:OpenClaw npm latest 升到 2026.7.1-1,
自动 bump 壳版本到 2.1.15 并打 tag 触发发版。
2026-07-18 03:49:16 +00:00
u-claw-bot
7c23358142 chore(upstream): 跟随 OpenClaw 2026.7.1,发布 v2.1.14
自动跟踪上游:OpenClaw npm latest 升到 2026.7.1,
自动 bump 壳版本到 2.1.14 并打 tag 触发发版。
2026-07-14 03:52:03 +00:00
hfshfg
02bf4ddf95 docs(readme): 顶部加 U-King 装机管家导流 + 代理合作加 U-King 分销条目
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 15:58:45 +08:00
u-claw-bot
b3fc827b60 chore(upstream): 跟随 OpenClaw 2026.6.11,发布 v2.1.13
自动跟踪上游:OpenClaw npm latest 升到 2026.6.11,
自动 bump 壳版本到 2.1.13 并打 tag 触发发版。
2026-07-01 05:15:56 +00:00
u-claw-bot
06113d8429 chore(upstream): 跟随 OpenClaw 2026.6.10,发布 v2.1.12
自动跟踪上游:OpenClaw npm latest 升到 2026.6.10,
自动 bump 壳版本到 2.1.12 并打 tag 触发发版。
2026-06-24 04:58:30 +00:00
hfshfg
6ab87c6b67 fix(portable): 微信扫码重定向/Telegram botToken/Windows 启动端口 (v2.1.11)
- 微信扫码卡死: config-server 跟随 IDC scaned_but_redirect 把后续轮询切到
  redirect_host,刷新二维码时重置 pollBaseUrl(扫码后不再卡住等不到 confirmed)。新增测试。
- Telegram 渠道改用 botToken(顶层 telegram 只认 botToken,旧 token 别名被静默忽略 → 连不上)。
- Windows-Start: 先起 config-server 再探测 gateway 端口,从 runtime.json 读实际
  configServerPort 并按该端口开 Config Center / 传给 wait-gateway(18788 被占也能开)。
- wait-gateway.bat: 用 ping 代替 timeout /t(避开 PATH 上 GNU coreutils timeout 冲突),接受 CONFIG_PORT 参数。
- Windows-Menu: IF 块内 echo 的 () 转义为 ^(^),修 v2.1.10 闪退回归。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 00:41:20 +08:00
18 changed files with 283 additions and 64 deletions

View File

@@ -1 +1 @@
2026.6.9
2026.7.1-2

View File

@@ -1,12 +1,47 @@
# 🦞 U-Claw虾盘
<p align="center">
<img src="assets/readme/hero.svg" alt="U-Claw随身携带的 AI 工作空间" width="100%" />
</p>
> **虾盘 — 全球首个 U 盘里运行的 AI 助手 | The world's first AI assistant that runs from a USB drive**
> **制作「插上就能用」的 AI 助手 U 盘 — 教程与源代码**
> **Build a plug-and-play AI assistant USB drive — Tutorial & Source Code**
<h1 align="center">U-Claw虾盘</h1>
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
<p align="center"><strong>把 AI 工作空间装进 U 盘:插上任意电脑,配置、记忆和工具都跟着走。</strong></p>
[中文](#中文) | [English](#english) | [📖 完整教程](https://u-claw.org/tutorial.html)
<p align="center">
<a href="https://github.com/dongsheng123132/u-claw/releases">下载便携版</a> ·
<a href="https://u-claw.org/tutorial.html">完整教程</a> ·
<a href="#快速开始制作便携版-u-盘">从源码制作</a> ·
<a href="#english">English</a>
</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-1f7a8c?style=flat-square" alt="MIT License" /></a>
<img src="https://img.shields.io/badge/Portable-USB%20first-123343?style=flat-square" alt="USB first" />
<img src="https://img.shields.io/badge/Runtime-OpenClaw-48d1c1?style=flat-square" alt="OpenClaw runtime" />
</p>
> [!IMPORTANT]
> 这不是 U 盘制作工具。这个仓库就是 U 盘的文件骨架:运行一次 `setup.sh` 补齐运行时,再把整个 `portable/` 拷到盘里即可。
## 三步开始
1. 从 [Releases](https://github.com/dongsheng123132/u-claw/releases) 下载 Windows 便携版,解压到 U 盘后双击 `Windows-Start.bat`
2. 或克隆仓库,在 `portable/` 运行 `bash setup.sh`,下载 Node.js 与 OpenClaw。
3. 首次启动在本地配置模型 Key配置只保存在 U 盘的 `data/.openclaw/openclaw.json`
| 你得到什么 | 为什么重要 |
| --- | --- |
| 随身 AI 工作空间 | 换电脑时带走配置、记忆与工具,不在主机残留用户数据。 |
| 本地优先 | 不绑定设备、不打指纹、不上传本地配置。 |
| 多种使用方式 | 便携 U 盘、在线一键安装、可启动 Linux U 盘各自独立。 |
> [!TIP]
> ### 👑 同作者新品U-King · AI 装机管家
> 一键装好 **Claude Code / Codex / OpenClaw / Hermes** 四大 AI 神器,驱动自动配好——一个 Key 直用 Claude、GPT、DeepSeek、Kimi 等 24+ 全球模型,免翻墙。绿色版仅几 MB双击即用还带 AI 作图 / 视频 / 本地大模型 / 多终端工作台。
>
> **免费下载:[www.u-king.org](https://www.u-king.org)**(国内镜像 [cloud.u-claw.org/uking](https://cloud.u-claw.org/uking/)
>
> *U-Claw 让 AI 住进 U 盘U-King 帮你把全套 AI 编程神器装进电脑。*
> *EN: U-King — one-click installer for Claude Code / Codex / OpenClaw, with one API key for 24+ global models → [u-king.org](https://www.u-king.org)*
---
@@ -263,6 +298,7 @@ npm install && npm run build
- **抖店 / 直播带货**:提供最高佣金比例,产品已在多个直播间验证转化
- **代理分销**:买断或按单分润均可谈,支持定制版本
- **技术合作**:有开发能力者欢迎深度合作
- **👑 U-King 装机管家分销(新)**[U-King](https://www.u-king.org) 软件本身免费送客户,客户按用量给 AI 模型 API 充值,你拿**持续分润**——不压货、零售后我们负责赚的是长期流水。适合装机店、AI 培训、社群主理人
有意向请微信联系(备注「代理合作」优先处理)。
@@ -530,6 +566,7 @@ U-Claw 3.0 delivers excellent user experience with very low return rates. We han
- **Live commerce / TikTok shop**: Top commission rates, proven conversion in live streams
- **Reseller / distribution**: Revenue share or wholesale, custom branded versions available
- **Technical partnership**: Deep collaboration welcome for developers
- **👑 U-King distribution (new)**: give away [U-King](https://www.u-king.org) (free AI setup manager) — earn **recurring revenue share** on your customers' API top-ups. No inventory, we handle support
Interested? WeChat hecare888 (mention "partnership" for priority response).

32
assets/readme/hero.svg Normal file
View File

@@ -0,0 +1,32 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 560" role="img" aria-labelledby="title desc">
<title id="title">U-Claw portable AI workspace</title>
<desc id="desc">A USB drive carries a local AI workspace across Windows, macOS, and Linux.</desc>
<rect width="1280" height="560" fill="#09121e"/>
<path d="M0 430C196 362 286 473 491 400s300-37 486-87 207-36 303-11v258H0Z" fill="#0e2632"/>
<circle cx="1047" cy="126" r="176" fill="#163d45" opacity=".62"/>
<circle cx="1047" cy="126" r="132" fill="#1d6970" opacity=".48"/>
<g fill="none" stroke="#48d1c1" stroke-width="2" opacity=".65">
<path d="M730 92h174v74h120v104"/>
<path d="M778 387h115v-69h151v-94"/>
<path d="M235 401h114v-77h96"/>
</g>
<g transform="translate(472 132)">
<rect x="0" y="0" width="286" height="260" rx="18" fill="#d8f2e9"/>
<rect x="28" y="24" width="230" height="156" rx="10" fill="#123343"/>
<path d="M113 64v58m30-58v58m30-58v58" stroke="#48d1c1" stroke-width="9" stroke-linecap="round"/>
<path d="M76 130h137" stroke="#48d1c1" stroke-width="9" stroke-linecap="round"/>
<rect x="93" y="203" width="100" height="20" rx="10" fill="#0a1b2b"/>
<path d="M44 260v38h198v-38" fill="#b9dfd5"/>
</g>
<g fill="#b8f4e8">
<text x="84" y="151" font-family="Arial, sans-serif" font-size="62" font-weight="700">U-CLAW</text>
<text x="88" y="202" font-family="Arial, sans-serif" font-size="25" letter-spacing="3">AI THAT TRAVELS WITH YOU</text>
</g>
<g font-family="Arial, sans-serif" font-size="22" fill="#d8f2e9">
<text x="90" y="313">Portable workspace</text>
<text x="90" y="350">Local data · Your model · Your USB drive</text>
</g>
<g transform="translate(923 367)" fill="#d8f2e9" font-family="Arial, sans-serif" font-size="18">
<text x="0" y="0">Windows</text><text x="116" y="0">macOS</text><text x="218" y="0">Linux</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -355,9 +355,11 @@ metadata: { "openclaw": { "emoji": "robot" } }
| Model | Use case | Context |
|-------|----------|---------|
| deepseek-chat | Daily chat | 32K |
| deepseek-coder | Code generation | 16K |
| deepseek-reasoner | Complex reasoning | 64K |
| deepseek-v4-flash | Daily chat, fast and cheap | 128K |
| deepseek-v4-pro | Complex reasoning, code | 128K |
> Note: the legacy names `deepseek-chat` / `deepseek-coder` / `deepseek-reasoner` are
> no longer accepted by api.deepseek.com and return HTTP 400.
- OpenAI-compatible API, base_url: https://api.deepseek.com
- Direct access in China, API Key: https://platform.deepseek.com
@@ -494,7 +496,7 @@ if ($hasConfig) {
if ([string]::IsNullOrEmpty($choice)) { $choice = "1" }
$modelConfigs = @{
"1" = @{ model="deepseek-chat"; baseUrl="https://api.deepseek.com/v1"; provider="custom"; label="DeepSeek API Key"; hint="Get key: https://platform.deepseek.com/api_keys"; needKey=$true }
"1" = @{ model="deepseek-v4-flash"; baseUrl="https://api.deepseek.com/v1"; provider="custom"; label="DeepSeek API Key"; hint="Get key: https://platform.deepseek.com/api_keys"; needKey=$true }
"2" = @{ model="moonshot-v1-auto"; baseUrl="https://api.moonshot.cn/v1"; provider="custom"; label="Moonshot API Key"; hint="Get key: https://platform.moonshot.cn/console/api-keys"; needKey=$true }
"3" = @{ model="qwen-plus"; baseUrl="https://dashscope.aliyuncs.com/compatible-mode/v1"; provider="custom"; label="Qwen API Key"; hint="Get key: https://dashscope.console.aliyun.com/apiKey (free quota available)"; needKey=$true }
"4" = @{ model="glm-4-plus"; baseUrl="https://open.bigmodel.cn/api/paas/v4"; provider="custom"; label="Zhipu API Key"; hint="Get key: https://open.bigmodel.cn/usercenter/apikeys"; needKey=$true }

View File

@@ -495,9 +495,11 @@ metadata: { "openclaw": { "emoji": "🤖" } }
| 模型 | 适用场景 | 上下文长度 |
|------|---------|-----------|
| deepseek-chat | 日常对话、文案写作、知识问答 | 32K |
| deepseek-coder | 代码生成、代码审查、技术文档 | 16K |
| deepseek-reasoner | 复杂推理、数学、逻辑分析 | 64K |
| deepseek-v4-flash | 日常对话、文案写作、知识问答,快且便宜 | 128K |
| deepseek-v4-pro | 复杂推理、数学、代码 | 128K |
> 注意:旧名 `deepseek-chat` / `deepseek-coder` / `deepseek-reasoner` 已被
> api.deepseek.com 拒绝,调用会直接返回 HTTP 400。
## 关键提示
@@ -796,7 +798,7 @@ else
# 模型配置映射
case $MODEL_CHOICE in
1)
MODEL_NAME="deepseek-chat"
MODEL_NAME="deepseek-v4-flash"
BASE_URL="https://api.deepseek.com/v1"
PROVIDER="custom"
KEY_LABEL="DeepSeek API Key"
@@ -877,7 +879,7 @@ else
;;
*)
echo -e " ${YELLOW}未知选项,使用默认 DeepSeek${NC}"
MODEL_NAME="deepseek-chat"
MODEL_NAME="deepseek-v4-flash"
BASE_URL="https://api.deepseek.com/v1"
PROVIDER="custom"
KEY_LABEL="DeepSeek API Key"

View File

@@ -170,10 +170,10 @@ input:focus { border-color: #ff6b35; }
<p>一个 Key 用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙</p>
<a class="buy-link" href="https://u-claw.org/cloud.html" target="_blank" data-action-label="注册 / 充值 / 获取 API Key">→ 注册 / 充值 / 获取 API Key</a>
</div>
<div class="model-card" data-provider="deepseek" data-base="https://api.deepseek.com/v1" data-model="deepseek-chat">
<div class="model-card" data-provider="deepseek" data-base="https://api.deepseek.com/v1" data-model="deepseek-v4-flash">
<span class="check"></span>
<h4>DeepSeek <span class="tag cn">国内</span><span class="tag cheap">便宜</span></h4>
<p>deepseek-chat / deepseek-v4超低价格</p>
<p>deepseek-v4-flash / deepseek-v4-pro,超低价格</p>
<a class="buy-link" href="https://platform.deepseek.com/" target="_blank">→ 获取 API Key</a>
</div>
<div class="model-card" data-provider="minimax" data-base="https://api.minimax.chat/v1" data-model="MiniMax-M2">

View File

@@ -107,7 +107,7 @@ do_config() {
echo ""
echo -e " DeepSeek → 选 Custom Provider"
echo -e " URL: https://api.deepseek.com/v1"
echo -e " 模型: deepseek-chat"
echo -e " 模型: deepseek-v4-flash"
echo -e " Kimi → 选 Moonshot AI"
echo -e " 通义千问 → 选 Qwen"
echo -e " 豆包 → 选 Volcano Engine"

View File

@@ -1 +1 @@
2026.6.9
2026.7.1-2

View File

@@ -477,12 +477,12 @@ echo Fetching latest version...
for /f "tokens=*" %%v in ('"%NODE_BIN%" -e "const https=require('https');https.get('https://registry.npmmirror.com/openclaw/latest',r=>{let d='';r.on('data',c=>d+=c);r.on('end',()=>{try{console.log(JSON.parse(d).version)}catch(e){console.log('error')}})})" 2^>nul') do set LATEST_VER=%%v
if "!LATEST_VER!"=="" (
echo Could not fetch latest version (network issue?)
echo Could not fetch latest version ^(network issue?^)
pause
goto :menu
)
if "!LATEST_VER!"=="error" (
echo Could not fetch latest version (network issue?)
echo Could not fetch latest version ^(network issue?^)
pause
goto :menu
)
@@ -550,7 +550,7 @@ if !BK_COUNT! gtr 3 (
echo Cleaned !DEL_NUM! old backups.
)
) else (
echo Backups: !BK_COUNT! (no cleanup needed)
echo Backups: !BK_COUNT! ^(no cleanup needed^)
)
REM Clean old logs (>7 days)
@@ -598,7 +598,7 @@ if "%plgchoice%"=="b" (
echo.
echo Common plugins:
echo @icesword760/openclaw-wechat - WeChat
echo @nicepkg/openclaw-plugin-qq - QQ (community)
echo @nicepkg/openclaw-plugin-qq - QQ ^(community^)
echo.
set /p plgname=" Plugin name (empty to cancel): "
if not "!plgname!"=="" (

View File

@@ -107,7 +107,8 @@ for /f "usebackq tokens=1,* delims==" %%a in (`""%NODE_BIN%" "%UCLAW_DIR%lib\res
)
if defined NO_PROXY (
set "no_proxy=%NO_PROXY%"
echo Direct-connect (NO_PROXY): %NO_PROXY%
REM Note: no unescaped parens in echo inside this IF block - cmd treats ) as block-end.
echo Direct-connect via NO_PROXY: %NO_PROXY%
)
REM Async update check (non-blocking, 5s timeout, silent failure)
@@ -134,7 +135,30 @@ if exist "%WECHAT_PLUGIN_SRC%\openclaw.plugin.json" (
)
)
REM Find available port
REM Start Config Server in background
echo Starting Config Center on port 18788...
set "CONFIG_SERVER=%UCLAW_DIR%config-server"
set "RUNTIME_JSON=%STATE_DIR%\runtime.json"
del "%RUNTIME_JSON%" >nul 2>&1
start /B "" "%NODE_BIN%" "%CONFIG_SERVER%\server.js" >nul 2>&1
REM Wait for Config Server with polling instead of a fixed delay.
REM It writes runtime.json with the actual fallback port when ready.
set /a CFG_TRIES=0
:wait_config
if exist "%RUNTIME_JSON%" goto :config_ready
set /a CFG_TRIES+=1
if %CFG_TRIES% geq 20 goto :config_ready
ping -n 1 -w 300 127.0.0.1 >nul 2>&1
goto :wait_config
:config_ready
set "CONFIG_PORT=18788"
if exist "%RUNTIME_JSON%" (
for /f "usebackq tokens=*" %%p in (`powershell -NoProfile -Command "try { (Get-Content -Raw '%RUNTIME_JSON%' | ConvertFrom-Json).configServerPort } catch {}" 2^>nul`) do set "CONFIG_PORT=%%p"
)
echo Config Center port: %CONFIG_PORT%
REM Find available gateway port after Config Center has bound its port.
set PORT=18789
:check_port
netstat -an | findstr ":%PORT% " | findstr "LISTENING" >nul 2>&1
@@ -152,24 +176,6 @@ if %errorlevel%==0 (
echo Starting OpenClaw on port %PORT%...
echo.
REM Start Config Server in background
echo Starting Config Center on port 18788...
set "CONFIG_SERVER=%UCLAW_DIR%config-server"
start /B "" "%NODE_BIN%" "%CONFIG_SERVER%\server.js" >nul 2>&1
REM Wait for Config Server with polling instead of a fixed delay.
REM It is usually ready in under one second. Poll about every 0.3 seconds,
REM up to about 6 seconds, then continue anyway.
set /a CFG_TRIES=0
:wait_config
netstat -an | findstr ":18788 " | findstr "LISTENING" >nul 2>&1
if %errorlevel%==0 goto :config_ready
set /a CFG_TRIES+=1
if %CFG_TRIES% geq 20 goto :config_ready
ping -n 1 -w 300 127.0.0.1 >nul 2>&1
goto :wait_config
:config_ready
REM Do not open Dashboard before the gateway is ready.
REM Slow USB drives may need tens of seconds to stage bundled deps.
REM Open the local startup page now, and always open Config Center too.
@@ -182,11 +188,11 @@ set "LOADING_URL=file:///%LOADING_PATH:\=/%?port=%PORT%&token=uclaw"
start "" "%LOADING_URL%"
echo Opening Config Center...
start "" http://127.0.0.1:18788/
start "" http://127.0.0.1:%CONFIG_PORT%/
REM Fallback watcher: if the startup page cannot poll from file URLs,
REM keep polling and reopen Config Center after the gateway is ready.
start /B "" cmd /c ""%UCLAW_DIR%lib\wait-gateway.bat" %PORT%"
start /B "" cmd /c ""%UCLAW_DIR%lib\wait-gateway.bat" %PORT% %CONFIG_PORT%"
REM Prewarm gateway in the background after it becomes ready.
start /B "" "%NODE_BIN%" "%UCLAW_DIR%lib\prewarm.mjs" %PORT% uclaw >nul 2>&1

View File

@@ -199,10 +199,10 @@ input:focus { border-color: #ff6b35; }
<p>moonshot-v1-auto智能选模型</p>
<a class="buy-link" href="https://platform.moonshot.cn/" target="_blank">→ 获取 API Key</a>
</div>
<div class="model-card" data-provider="deepseek" data-base="https://api.deepseek.com/v1" data-model="deepseek-chat">
<div class="model-card" data-provider="deepseek" data-base="https://api.deepseek.com/v1" data-model="deepseek-v4-flash">
<span class="check"></span>
<h4>DeepSeek <span class="tag cn">国内</span><span class="tag cheap">便宜</span></h4>
<p>deepseek-chat,超低价格</p>
<p>deepseek-v4-flash,超低价格</p>
<a class="buy-link" href="https://platform.deepseek.com/" target="_blank">→ 获取 API Key</a>
</div>
<div class="model-card" data-provider="zai" data-base="" data-model="glm-5">
@@ -678,7 +678,9 @@ async function saveChannelsAndOpen() {
var channels = {};
var tgToken = document.getElementById('ch-telegram-token').value.trim();
if (tgToken) channels.telegram = { enabled: true, token: tgToken, dmPolicy: 'pairing' };
// OpenClaw 顶层 telegram 渠道只认 botToken旧 token 别名仅在 accounts.<id> 里有效)。
// 之前写成 token 会被静默忽略 → Telegram 接不上。
if (tgToken) channels.telegram = { enabled: true, botToken: tgToken, dmPolicy: 'pairing' };
var qqId = document.getElementById('ch-qqbot-appid').value.trim();
var qqSecret = document.getElementById('ch-qqbot-secret').value.trim();

View File

@@ -246,7 +246,13 @@ async function handleWeChatStatus(sessionKey) {
return { status: 'expired', message: 'Session expired' };
}
const result = await pollWeChatQrStatus(login.apiBaseUrl, login.qrcode);
// 状态轮询用 pollBaseUrlIDC 重定向后会指向新主机);二维码获取/刷新始终用原始
// apiBaseUrl与官方插件一致refresh 回到固定主机,只有 status 轮询跟随重定向)。
const result = await pollWeChatQrStatus(login.pollBaseUrl || login.apiBaseUrl, login.qrcode);
// 微信登录状态流转日志(跳过高频的 wait便于排查"扫码卡死"类问题)。
if (result.status && result.status !== 'wait') {
console.log(`[wechat] status=${result.status}` + (result.redirect_host ? ` redirect_host=${result.redirect_host}` : ''));
}
if (result.status === 'expired') {
// Try to refresh QR code
@@ -261,6 +267,8 @@ async function handleWeChatStatus(sessionKey) {
login.qrcode = refreshed.qrcode;
login.qrcodeUrl = newQr;
login.startedAt = Date.now();
// 新二维码来自原始主机,重置轮询主机,避免拿新码去轮询旧的重定向主机。
login.pollBaseUrl = null;
return { status: 'refreshed', qrcodeUrl: newQr };
}
@@ -302,6 +310,18 @@ async function handleWeChatStatus(sessionKey) {
};
}
// IDC 重定向用户扫码后ilink 服务端可能要求把后续轮询切换到另一个数据中心主机
// (status=scaned_but_redirect + redirect_host)。必须跟着切,否则一直轮询旧主机,
// 扫码后永远等不到 confirmed——表现为「扫了码却卡死不前进」。
// 同款逻辑见官方插件 openclaw-weixin/src/auth/login-qr.ts 的 scaned_but_redirect 分支。
if (result.status === 'scaned_but_redirect') {
if (result.redirect_host) {
login.pollBaseUrl = 'https://' + result.redirect_host;
}
// 对前端按「已扫码」处理:显示提示并继续轮询,下一轮已指向新主机。
return { status: 'scaned' };
}
return { status: result.status };
}

View File

@@ -4,11 +4,13 @@ REM Slow USB drives can need tens of seconds before the gateway listens.
REM
REM Windows-Start opens Config Center immediately, so the ready path only
REM exits quietly. On timeout, reopen Config Center as a recovery hint.
REM Usage (called in background by Windows-Start.bat): wait-gateway.bat PORT
REM Usage (called in background by Windows-Start.bat): wait-gateway.bat PORT CONFIG_PORT
REM Polls every 2 seconds, up to about 5 minutes.
set "PORT=%~1"
if "%PORT%"=="" set "PORT=18789"
set "CONFIG_PORT=%~2"
if "%CONFIG_PORT%"=="" set "CONFIG_PORT=18788"
set /a TRIES=0
:wait_loop
@@ -16,12 +18,15 @@ netstat -an | findstr ":%PORT% " | findstr "LISTENING" >nul 2>&1
if %errorlevel%==0 goto :ready
set /a TRIES+=1
if %TRIES% geq 150 goto :timeout
timeout /t 2 /nobreak >nul
REM Use ping (not "timeout /t") for the ~2s delay: if a GNU coreutils "timeout"
REM is on PATH (Git/MSYS bin), it rejects "/t" and this poll becomes a busy-loop.
REM ping for the delay is PATH-robust and matches Windows-Start.bat's wait loop.
ping -n 3 127.0.0.1 >nul 2>&1
goto :wait_loop
:ready
exit /b 0
:timeout
start "" http://127.0.0.1:18788/
start "" http://127.0.0.1:%CONFIG_PORT%/
exit /b 1

View File

@@ -10,7 +10,7 @@ metadata: { "openclaw": { "emoji": "🤖" } }
## 功能概述
- **模型选择指南**: deepseek-chat vs deepseek-coder 的使用场景对比
- **模型选择指南**: deepseek-v4-flash vs deepseek-v4-pro 的使用场景对比
- **API 调用示例**: 提供 Python、curl、Node.js 等语言的调用代码
- **定价计算**: 根据 token 用量估算费用(输入 ¥1/百万tokens输出 ¥2/百万tokens
- **Prompt 优化**: 针对 DeepSeek 模型特性优化提示词
@@ -20,9 +20,12 @@ metadata: { "openclaw": { "emoji": "🤖" } }
| 模型 | 适用场景 | 上下文长度 |
|------|---------|-----------|
| deepseek-chat | 日常对话、文案写作、知识问答 | 32K |
| deepseek-coder | 代码生成、代码审查、技术文档 | 16K |
| deepseek-reasoner | 复杂推理、数学、逻辑分析 | 64K |
| deepseek-v4-flash | 日常对话、文案写作、知识问答,快且便宜 | 128K |
| deepseek-v4-pro | 复杂推理、数学、代码生成与审查 | 128K |
> ⚠️ 旧名 `deepseek-chat` / `deepseek-coder` / `deepseek-reasoner` 已下线,
> api.deepseek.com 现在只接受 `deepseek-v4-flash` 和 `deepseek-v4-pro`
> 用旧名调用会直接返回 HTTP 400。
## 使用示例
@@ -33,7 +36,7 @@ metadata: { "openclaw": { "emoji": "🤖" } }
### 模型选择
```
我要做一个客服机器人,应该用 deepseek-chat 还是 deepseek-coder
我要做一个客服机器人,应该用 deepseek-v4-flash 还是 deepseek-v4-pro
```
### 费用估算
@@ -49,7 +52,7 @@ metadata: { "openclaw": { "emoji": "🤖" } }
## 适用场景
- 首次接入 DeepSeek API 的开发者
- 需要在 deepseek-chat 和 deepseek-coder 之间做选择
- 需要在 deepseek-v4-flash 和 deepseek-v4-pro 之间做选择
- 想要优化 API 调用成本
- 排查 API 调用问题
- 需要快速生成 API 调用代码片段

View File

@@ -0,0 +1,68 @@
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { join } from 'node:path';
import test from 'node:test';
import assert from 'node:assert/strict';
const repoRoot = fileURLToPath(new URL('..', import.meta.url));
const server = readFileSync(join(repoRoot, 'portable', 'config-server', 'server.js'), 'utf8');
const configUi = readFileSync(join(repoRoot, 'portable', 'config-server', 'public', 'index.html'), 'utf8');
// The ilink QR API (StatusResponse in openclaw-weixin/src/auth/login-qr.ts) can return
// status "scaned_but_redirect" with a redirect_host: after the user scans, polling must
// move to a new IDC host or "confirmed" never arrives and the QR screen hangs forever.
// The config-server must mirror the plugin's redirect handling.
test('config-server follows the WeChat scaned_but_redirect IDC redirect', () => {
// Status polling uses a redirect-aware host, not the fixed apiBaseUrl directly.
assert.match(
server,
/pollWeChatQrStatus\(\s*login\.pollBaseUrl\s*\|\|\s*login\.apiBaseUrl/,
'status polling must use login.pollBaseUrl (falls back to apiBaseUrl)',
);
// On scaned_but_redirect, switch the poll host to redirect_host.
assert.match(
server,
/scaned_but_redirect[\s\S]{0,200}login\.pollBaseUrl\s*=\s*['"]https:\/\/['"]\s*\+\s*result\.redirect_host/,
'must set login.pollBaseUrl to https://<redirect_host> on scaned_but_redirect',
);
// The redirect case is reported to the client as "scaned" so it keeps polling.
assert.match(
server,
/scaned_but_redirect[\s\S]{0,260}return\s*\{\s*status:\s*['"]scaned['"]\s*\}/,
'scaned_but_redirect should surface as status "scaned" to the client',
);
});
test('config-server writes the Telegram bot token under the field OpenClaw reads (botToken)', () => {
// OpenClaw's top-level telegram channel schema only reads `botToken` (the legacy
// `token` alias is honored only inside accounts.<id>). Writing flat `token` silently
// disables Telegram, so the Config Center must write `botToken`.
assert.match(
configUi,
/channels\.telegram\s*=\s*\{[^}]*botToken:\s*tgToken/,
'telegram channel must be saved with botToken',
);
assert.doesNotMatch(
configUi,
/channels\.telegram\s*=\s*\{[^}]*\btoken:\s*tgToken/,
'telegram channel must not use the flat `token` field (ignored by OpenClaw)',
);
});
test('config-server resets the poll host when the QR is refreshed', () => {
// A refreshed QR comes from the original host, so the redirected poll host must reset,
// otherwise the new QR would be polled against a stale redirect host.
assert.match(
server,
/status:\s*'refreshed'[\s\S]{0,400}/,
'refresh branch should exist',
);
assert.match(
server,
/login\.pollBaseUrl\s*=\s*null;[\s\S]{0,200}status:\s*'refreshed'/,
'QR refresh must reset login.pollBaseUrl before returning refreshed',
);
});

View File

@@ -50,7 +50,7 @@ test('Windows startup keeps Config Center available even after model setup', ()
assert.match(
script,
/Opening Config Center[\s\S]*start "" http:\/\/127\.0\.0\.1:18788\//,
/Opening Config Center[\s\S]*start "" http:\/\/127\.0\.0\.1:%CONFIG_PORT%\//,
'Windows-Start.bat should always open Config Center for model/channel changes',
);
assert.doesNotMatch(
@@ -65,7 +65,7 @@ test('Windows gateway fallback does not force-open Dashboard', () => {
assert.match(
script,
/:timeout[\s\S]*start "" http:\/\/127\.0\.0\.1:18788\//,
/:timeout[\s\S]*start "" http:\/\/127\.0\.0\.1:%CONFIG_PORT%\//,
'wait-gateway.bat should return users to Config Center on timeout',
);
assert.doesNotMatch(
@@ -147,6 +147,48 @@ test('OpenClaw doctor launcher is read-only (no destructive repair flags)', () =
assert.doesNotMatch(bat, /doctor[^\n]*--force/);
});
// cmd.exe treats ')' as the end of an IF/FOR ( ... ) block, so an unescaped paren in
// an `echo` *inside* a block aborts parsing ("was unexpected at this time") and the
// window flash-closes. This shipped once in v2.1.10 (echo Direct-connect (NO_PROXY)).
// Track block depth structurally and flag any unescaped ( or ) in echoes inside a block.
function unescapedParenEchoesInsideBlocks(bat) {
const offenders = [];
let depth = 0;
for (const raw of bat.split(/\r?\n/)) {
const line = raw.trim();
if (depth > 0 && /^echo\b/i.test(line)) {
// cmd eats an unescaped ')' that sits at the END of an echo (cosmetic: the ')'
// just disappears). The flash-exit only happens when a ')' is followed by more
// text on the line (e.g. "(NO_PROXY): value" → ')' closes the block, ": value"
// then errors). So: drop escaped ^), drop trailing ')'/whitespace, and flag any
// ')' that survives (meaning it had text after it).
let s = line.replace(/\^\)/g, '').replace(/[)\s]+$/, '');
if (s.includes(')')) offenders.push(raw.trim());
}
// structural depth: ') else (' keeps depth; leading ')' closes; if/for line ending in '(' opens
if (/^\)\s*else\b.*\($/i.test(line)) { /* same depth */ }
else if (/^\)/.test(line)) depth = Math.max(0, depth - 1);
if (/^\($/.test(line) || /\b(if|for)\b.*[^^]\(\s*$/i.test(line)) depth += 1;
}
return offenders;
}
test('Windows launchers have no unescaped parens in echoes inside IF/FOR blocks (v2.1.10 flash-exit regression)', () => {
for (const name of [
'Windows-Start.bat',
'Windows-IntranetFix.bat',
'Windows-LocalModel.bat',
'OpenClaw-Doctor.bat',
'Windows-Diagnose.bat',
'Windows-Menu.bat',
'Windows-Install.bat',
]) {
const bat = readRepoFile('portable', name);
const offenders = unescapedParenEchoesInsideBlocks(bat);
assert.deepEqual(offenders, [], `${name} has unescaped parens in block echo(es): ${offenders.join(' | ')}`);
}
});
test('PowerShell installer generated start.bat disables OpenClaw bonjour discovery', () => {
const script = readRepoFile('install', 'install.ps1');

View File

@@ -1,6 +1,6 @@
{
"name": "u-claw",
"version": "2.1.10",
"version": "2.1.17",
"description": "U-Claw - AI 助手桌面版,插上 U 盘就能用",
"main": "src/main.js",
"author": "U-Claw <hello@u-claw.org> (https://u-claw.org)",

View File

@@ -170,10 +170,10 @@ input:focus { border-color: #ff6b35; }
<p>一个 Key 用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙</p>
<a class="buy-link" href="https://u-claw.org/cloud.html" target="_blank">→ 注册并获取 API Key</a>
</div>
<div class="model-card" data-provider="deepseek" data-base="https://api.deepseek.com/v1" data-model="deepseek-chat">
<div class="model-card" data-provider="deepseek" data-base="https://api.deepseek.com/v1" data-model="deepseek-v4-flash">
<span class="check"></span>
<h4>DeepSeek <span class="tag cn">国内</span><span class="tag cheap">便宜</span></h4>
<p>deepseek-chat / deepseek-v4超低价格</p>
<p>deepseek-v4-flash / deepseek-v4-pro,超低价格</p>
<a class="buy-link" href="https://platform.deepseek.com/" target="_blank">→ 获取 API Key</a>
</div>
<div class="model-card" data-provider="minimax" data-base="https://api.minimax.chat/v1" data-model="MiniMax-M2">