Skip to content

Commit 9ecbbd4

Browse files
feat: 内置虾盘云 + 设备指纹绑定 + Release 流水线
- 新增 portable/lib/{fingerprint,xiapan-client,bootstrap-xiapan}.mjs: 跨平台设备指纹(Win USB/disk + Mac UUID + Linux machine-id + seed 兜底) 生成 sk-uc-{fingerprint} 形式的虾盘云 apiKey,启动时 merge 到 openclaw.json - Config.html 顶部新增「已绑定虾盘云」横幅:指纹来源 + Key + 余额 + 充值/解绑 - config-server 增加 /api/xiapan/{status,bind,unbind} 三个端点 - Electron app 在 whenReady 调 bootstrap,新增 sync-lib.js 让 build 前自动同步 - 锁 OpenClaw 版本到 2026.4.29(OPENCLAW_VERSION 单一来源) - 删除死代码 portable/充值.html - 新增 .github/workflows/release.yml:tag 触发,出 portable zip + Electron exe/dmg - README 增加内置虾盘云说明 + 直接下载发行版指引
1 parent efeec64 commit 9ecbbd4

22 files changed

Lines changed: 1749 additions & 709 deletions

.github/workflows/release.yml

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: 'Tag to publish (e.g. v2.1.0). Leave empty to use the most recent tag.'
11+
required: false
12+
default: ''
13+
14+
permissions:
15+
contents: write
16+
17+
jobs:
18+
portable-windows:
19+
name: Portable Windows zip
20+
runs-on: windows-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: Read OpenClaw version
25+
id: openclaw_version
26+
shell: bash
27+
run: |
28+
version=$(tr -d '[:space:]' < OPENCLAW_VERSION)
29+
echo "version=$version" >> "$GITHUB_OUTPUT"
30+
31+
- uses: actions/setup-node@v4
32+
with:
33+
node-version: '22'
34+
35+
- name: Run portable setup (Windows)
36+
shell: cmd
37+
run: |
38+
cd portable
39+
call setup.bat
40+
41+
- name: Stage portable folder
42+
shell: bash
43+
run: |
44+
mkdir -p dist
45+
tag_name="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
46+
stage_dir="dist/u-claw-portable-windows-${tag_name}"
47+
mkdir -p "$stage_dir"
48+
cp -R portable/. "$stage_dir/"
49+
# Drop dev-only large files we don't ship
50+
rm -rf "$stage_dir/data/logs" 2>/dev/null || true
51+
52+
- name: Zip portable
53+
shell: pwsh
54+
run: |
55+
$tag = if ($env:GITHUB_REF_NAME) { $env:GITHUB_REF_NAME } else { '${{ github.event.inputs.tag }}' }
56+
$stage = "dist/u-claw-portable-windows-$tag"
57+
$out = "dist/u-claw-portable-windows-$tag.zip"
58+
Compress-Archive -Path "$stage/*" -DestinationPath $out -CompressionLevel Optimal
59+
60+
- uses: actions/upload-artifact@v4
61+
with:
62+
name: portable-windows
63+
path: dist/u-claw-portable-windows-*.zip
64+
65+
portable-mac:
66+
name: Portable macOS zip
67+
runs-on: macos-14
68+
steps:
69+
- uses: actions/checkout@v4
70+
71+
- uses: actions/setup-node@v4
72+
with:
73+
node-version: '22'
74+
75+
- name: Run portable setup (mac)
76+
run: |
77+
cd portable
78+
bash setup.sh
79+
80+
- name: Stage portable folder
81+
run: |
82+
mkdir -p dist
83+
tag_name="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
84+
stage_dir="dist/u-claw-portable-mac-${tag_name}"
85+
mkdir -p "$stage_dir"
86+
cp -R portable/. "$stage_dir/"
87+
rm -rf "$stage_dir/data/logs" 2>/dev/null || true
88+
89+
- name: Zip portable
90+
run: |
91+
tag_name="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
92+
cd dist
93+
zip -qry "u-claw-portable-mac-${tag_name}.zip" "u-claw-portable-mac-${tag_name}"
94+
95+
- uses: actions/upload-artifact@v4
96+
with:
97+
name: portable-mac
98+
path: dist/u-claw-portable-mac-*.zip
99+
100+
desktop-windows:
101+
name: Electron Windows installer
102+
runs-on: windows-latest
103+
steps:
104+
- uses: actions/checkout@v4
105+
106+
- uses: actions/setup-node@v4
107+
with:
108+
node-version: '22'
109+
110+
- name: Install dependencies
111+
shell: cmd
112+
run: |
113+
cd u-claw-app
114+
npm install --registry=https://registry.npmmirror.com
115+
116+
- name: Build Windows installer
117+
shell: cmd
118+
run: |
119+
cd u-claw-app
120+
npm run build:win
121+
env:
122+
# Skip code signing — we ship unsigned. README documents the SmartScreen workaround.
123+
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
124+
125+
- uses: actions/upload-artifact@v4
126+
with:
127+
name: desktop-windows
128+
path: |
129+
u-claw-app/release/*.exe
130+
u-claw-app/release/*.exe.blockmap
131+
132+
desktop-mac:
133+
name: Electron macOS DMG
134+
runs-on: macos-14
135+
steps:
136+
- uses: actions/checkout@v4
137+
138+
- uses: actions/setup-node@v4
139+
with:
140+
node-version: '22'
141+
142+
- name: Install dependencies
143+
run: |
144+
cd u-claw-app
145+
npm install --registry=https://registry.npmmirror.com
146+
147+
- name: Build macOS DMG
148+
run: |
149+
cd u-claw-app
150+
npm run build:mac-arm64
151+
env:
152+
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
153+
154+
- uses: actions/upload-artifact@v4
155+
with:
156+
name: desktop-mac
157+
path: |
158+
u-claw-app/release/*.dmg
159+
u-claw-app/release/*.dmg.blockmap
160+
161+
publish:
162+
name: Publish GitHub Release
163+
needs: [portable-windows, portable-mac, desktop-windows, desktop-mac]
164+
runs-on: ubuntu-latest
165+
steps:
166+
- uses: actions/checkout@v4
167+
168+
- uses: actions/download-artifact@v4
169+
with:
170+
path: artifacts
171+
172+
- name: Resolve tag
173+
id: tag
174+
run: |
175+
if [ -n "${{ github.event.inputs.tag }}" ]; then
176+
tag="${{ github.event.inputs.tag }}"
177+
else
178+
tag="${GITHUB_REF_NAME}"
179+
fi
180+
echo "tag=$tag" >> "$GITHUB_OUTPUT"
181+
182+
- name: Read OpenClaw version
183+
id: openclaw_version
184+
run: |
185+
version=$(tr -d '[:space:]' < OPENCLAW_VERSION)
186+
echo "version=$version" >> "$GITHUB_OUTPUT"
187+
188+
- name: Create or update release
189+
uses: softprops/action-gh-release@v2
190+
with:
191+
tag_name: ${{ steps.tag.outputs.tag }}
192+
name: U-Claw ${{ steps.tag.outputs.tag }}
193+
body: |
194+
## U-Claw ${{ steps.tag.outputs.tag }}
195+
196+
- 内置虾盘云:首次启动自动绑定本机/U盘指纹,生成 `sk-...` apiKey
197+
- OpenClaw runtime: `${{ steps.openclaw_version.outputs.version }}`
198+
- 充值入口:https://u-claw.org/cloud.html
199+
200+
> Windows 安装包未做代码签名,首次运行需在 SmartScreen 选择"仍要运行"。
201+
> macOS DMG 未做公证,首次启动需 `xattr -rd com.apple.quarantine /Applications/U-Claw.app` 或右键打开。
202+
files: |
203+
artifacts/portable-windows/*
204+
artifacts/portable-mac/*
205+
artifacts/desktop-windows/*
206+
artifacts/desktop-mac/*
207+
fail_on_unmatched_files: false
208+
env:
209+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

OPENCLAW_VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2026.4.29

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ U-Claw(虾盘)是一个**制作教程 + 全套源代码**,教你把 [OpenC
2222

2323
> 📖 **[完整教程](https://u-claw.org/tutorial.html)** — 从零开始的手工安装指南、模型配置、聊天平台接入,小白也能看懂。
2424
25+
### 🔗 内置虾盘云:开箱即用
26+
27+
每个 U-Claw 实例首次启动会**自动**根据当前 U 盘 / 硬盘的指纹生成一个 `sk-...` 形式的虾盘云 apiKey,并写入 `data/.openclaw/openclaw.json`。打开 Config.html 就能看到这张「已绑定虾盘云」横幅(指纹来源、Key、余额)。
28+
29+
- **不送 token**:余额初始为 0,需自行充值([u-claw.org/cloud.html](https://u-claw.org/cloud.html)
30+
- **指纹规则**
31+
- 从 U 盘根目录启动 → 绑定该 U 盘的硬件指纹(USB Serial + PNPDeviceID)
32+
- 从硬盘启动(电脑安装版 / Electron App)→ 绑定主板 + 系统盘指纹
33+
- Mac/Linux 走 Hardware UUID / `/etc/machine-id` + 启动盘 UUID
34+
- **换机 / 换盘**:换 U 盘或换电脑后,新的指纹会生成新的 Key;旧 Key 的余额仍归属原指纹(在 Config.html 点「解绑」可触发重新绑定)
35+
- **隐私**:指纹只用于本地生成 Key,不上传,无登录
36+
2537
### 一键安装(推荐)
2638

2739
不需要 U 盘,一行命令直接装到电脑:
@@ -108,6 +120,19 @@ npm run build:mac-arm64 # 打包 → release/*.dmg
108120
npm run build:win # 打包 → release/*.exe
109121
```
110122

123+
### 直接下载发行版
124+
125+
[GitHub Releases](https://github.com/dongsheng123132/u-claw/releases) 提供四种打包好的产物:
126+
127+
- `u-claw-portable-windows-vX.Y.Z.zip` — Windows 便携版(解压即用)
128+
- `u-claw-portable-mac-vX.Y.Z.zip` — Mac 便携版
129+
- `U-Claw Setup vX.Y.Z.exe` — Windows 桌面安装包
130+
- `U-Claw-vX.Y.Z-arm64.dmg` — Mac 桌面安装包
131+
132+
> ⚠️ 安装包未签名:
133+
> - **Windows**:双击 `.exe` 时 SmartScreen 会拦,点「更多信息」→「仍要运行」
134+
> - **Mac**:首次启动如被 Gatekeeper 拦,执行 `xattr -rd com.apple.quarantine /Applications/U-Claw.app` 或在 Finder 里右键→打开
135+
111136
### 支持的 AI 模型
112137

113138
**国产模型(无需翻墙):**

install/install.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,14 @@ if [ -d "$CORE_DIR/node_modules/openclaw" ]; then
176176
echo -e " ${GREEN}${NC} OpenClaw 已安装,跳过"
177177
else
178178
if [ ! -f "$CORE_DIR/package.json" ]; then
179-
cat > "$CORE_DIR/package.json" << 'PKGJSON'
179+
OPENCLAW_VERSION="2026.4.29"
180+
cat > "$CORE_DIR/package.json" << PKGJSON
180181
{
181182
"name": "u-claw-core",
182183
"version": "1.0.0",
183184
"private": true,
184185
"dependencies": {
185-
"openclaw": "latest"
186+
"openclaw": "$OPENCLAW_VERSION"
186187
}
187188
}
188189
PKGJSON

portable/Config.html

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,26 @@
151151
<h1><span class="lobster">🦞</span> U-Claw Pro</h1>
152152
<p class="subtitle">便携版 — 选择模型,填入 API Key,一键启动</p>
153153

154+
<!-- Xiapan Cloud bound banner: shown when bootstrap has injected uclaw-cloud -->
155+
<div class="xp-banner" id="xpBanner" style="display:none; background:linear-gradient(135deg,#2a1f1f,#1f2a1f); border:1px solid #ff6b35; border-radius:10px; padding:16px 18px; margin-bottom:18px;">
156+
<div style="display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;">
157+
<div style="flex:1; min-width:240px;">
158+
<div style="font-size:0.95em; color:#ff6b35; font-weight:600;">🔗 已绑定虾盘云 · 开箱即用</div>
159+
<div style="font-size:0.82em; color:#bbb; margin-top:4px;">
160+
指纹来源: <span id="xpSource"></span>
161+
· Key: <code id="xpKeyShort" style="background:#222; padding:2px 6px; border-radius:4px;"></code>
162+
· 余额: <span id="xpBalance"></span>
163+
</div>
164+
<div id="xpHint" style="font-size:0.75em; color:#888; margin-top:4px;">余额为 0 时无法调用 AI,请先充值</div>
165+
</div>
166+
<div style="display:flex; gap:8px;">
167+
<button class="btn" id="xpRecharge" style="background:#ff6b35; color:#fff; padding:8px 16px; font-size:0.85em;">前往充值 →</button>
168+
<button class="btn" id="xpRefresh" style="background:#333; color:#ccc; padding:8px 12px; font-size:0.85em;">刷新</button>
169+
<button class="btn" id="xpRebind" style="background:#222; color:#888; padding:8px 12px; font-size:0.8em;" title="清除绑定后重启 U-Claw 即可重新生成 Key">解绑</button>
170+
</div>
171+
</div>
172+
</div>
173+
154174
<!-- Steps -->
155175
<div class="steps">
156176
<div class="step active" data-step="1"><span class="num">1</span>选模型</div>
@@ -388,6 +408,50 @@ <h4>data/ — 配置和聊天记录</h4>
388408
<div class="toast" id="toast"></div>
389409

390410
<script>
411+
// --- Xiapan Cloud banner ---
412+
async function loadXiapanStatus() {
413+
const banner = document.getElementById('xpBanner');
414+
try {
415+
const res = await fetch('/api/xiapan/status');
416+
if (!res.ok) return;
417+
const data = await res.json();
418+
if (!data || !data.apiKey) return;
419+
420+
document.getElementById('xpSource').textContent = ({
421+
usb: 'U 盘', disk: '硬盘', mac: 'Mac', linux: 'Linux', seed: '本机种子', test: '测试',
422+
})[data.source] || data.source;
423+
document.getElementById('xpKeyShort').textContent = data.apiKey.slice(0, 14) + '…';
424+
const bal = data.balance || {};
425+
if (bal.ok) {
426+
const usd = bal.remainingUsd != null ? bal.remainingUsd.toFixed(2) : '0.00';
427+
const tokens = (bal.remainingTokens || 0).toLocaleString();
428+
document.getElementById('xpBalance').textContent = `$${usd} (${tokens} tokens)`;
429+
document.getElementById('xpHint').textContent = bal.remainingUsd > 0
430+
? '可直接使用 deepseek-chat / qwen-plus / qwen-turbo'
431+
: '余额为 0,点击右侧前往充值';
432+
} else if (bal.reason && bal.reason.includes('401')) {
433+
document.getElementById('xpBalance').textContent = '未注册';
434+
document.getElementById('xpHint').textContent = '首次使用:点「前往充值」即可在虾盘云页面注册并充值,秒到账';
435+
} else {
436+
document.getElementById('xpBalance').textContent = '查询失败';
437+
document.getElementById('xpHint').textContent = '请检查网络或 api.u-claw.org 服务状态';
438+
}
439+
440+
document.getElementById('xpRecharge').onclick = () => window.open(data.rechargeUrl, '_blank');
441+
document.getElementById('xpRefresh').onclick = () => loadXiapanStatus();
442+
document.getElementById('xpRebind').onclick = async () => {
443+
if (!confirm('解绑后下次启动 U-Claw 会重新生成 Key(基于当前设备指纹)。\n现有 Key 的余额仍归属当前指纹,更换 U 盘 / 电脑后才需要解绑。\n\n确认解绑?')) return;
444+
await fetch('/api/xiapan/unbind', { method: 'POST' });
445+
showToast('已解绑,请重启 U-Claw');
446+
};
447+
448+
banner.style.display = 'block';
449+
} catch (err) {
450+
// network error or endpoint missing — leave banner hidden
451+
}
452+
}
453+
loadXiapanStatus();
454+
391455
// --- State ---
392456
let selectedProvider = null;
393457
let selectedBase = '';

portable/Mac-Start.command

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ if [ ! -d "$CORE_DIR/node_modules" ]; then
106106
echo ""
107107
fi
108108

109+
# ---- 7b. Bind device fingerprint and inject Xiapan Cloud apiKey ----
110+
echo -e " ${CYAN}Binding device fingerprint to Xiapan Cloud...${NC}"
111+
UCLAW_APP_ROOT="$UCLAW_DIR" "$NODE_BIN" "$UCLAW_DIR/lib/bootstrap-xiapan.mjs" "$CONFIG_FILE" || true
112+
echo ""
113+
109114
# ---- 8. Find available port ----
110115
PORT=18789
111116
while lsof -i :$PORT >/dev/null 2>&1; do

portable/Windows-Start.bat

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ if not exist "%CORE_DIR%\node_modules" (
7272
echo.
7373
)
7474

75+
REM Bind device fingerprint and inject Xiapan Cloud apiKey into openclaw.json
76+
echo Binding device fingerprint to Xiapan Cloud...
77+
set "UCLAW_APP_ROOT=%UCLAW_DIR%"
78+
"%NODE_BIN%" "%UCLAW_DIR%lib\bootstrap-xiapan.mjs" "%STATE_DIR%\openclaw.json"
79+
echo.
80+
7581
REM Auto-install WeChat plugin if available
7682
set "WECHAT_PLUGIN_SRC=%APP_DIR%\extensions\openclaw-weixin"
7783
set "WECHAT_PLUGIN_DST=%USERPROFILE%\.openclaw\extensions\openclaw-weixin"

0 commit comments

Comments
 (0)