diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 8868107..2925f1f 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,7 +4,7 @@ contact_links: url: https://u-claw.org/tutorial.html about: 从零开始的安装教程,含模型配置、平台接入 - name: 🔍 查看 FAQ - url: https://github.com/dongsheng123132/u-claw#faq + url: https://gitea.fanghe.it.com/zhenghy/u-claw#faq about: 常见问题解答,先看这里 - name: 💬 联系作者(微信) url: https://u-claw.org/guide.html#remote-support diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 34ef575..f14753f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,7 +11,7 @@ - [ ] ✨ 新功能 - [ ] 📝 文档/README - [ ] 🔧 脚本/构建(portable, install, bootable, u-claw-app) -- [ ] 🎨 技能 (skills-cn) +- [ ] 🎨 技能 (skills/) - [ ] ♻️ 重构(不改变行为) - [ ] 🧪 测试 @@ -40,7 +40,7 @@ - [ ] u-claw-app/ (Electron 桌面) - [ ] bootable/ (Linux 可启动 U 盘) - [ ] install/ (一键安装脚本) -- [ ] skills-cn/ (中国本地化技能) +- [ ] skills/ (技能内容与 manifest) - [ ] 仅文档 ## 自检 / Checklist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 675713b..f83612e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,6 +31,7 @@ jobs: mkdir -p "$stage_dir" cp -R portable/. "$stage_dir/" cp OPENCLAW_VERSION "$stage_dir/OPENCLAW_VERSION" + cp NODE_VERSION "$stage_dir/NODE_VERSION" rm -rf "$stage_dir/data/logs" 2>/dev/null || true - name: Pre-install Node.js (Windows) and OpenClaw deps @@ -39,9 +40,9 @@ jobs: # Absolute paths so `cd "$core_dir"` later doesn't break `du`/`find` stage_dir="$(pwd)/dist/u-claw-portable-windows-${tag_name}" openclaw_version=$(tr -d '[:space:]' < OPENCLAW_VERSION) - node_version="v22.22.1" - mirror_node="https://npmmirror.com/mirrors/node" - mirror_npm="https://registry.npmmirror.com" + node_version=$(tr -d "[:space:]" < NODE_VERSION) + mirror_node="https://nodejs.org/dist" + mirror_npm="https://registry.npmjs.org" app_dir="$stage_dir/app" runtime_dir="$app_dir/runtime" @@ -49,8 +50,8 @@ jobs: mkdir -p "$runtime_dir" "$core_dir" # 1) Download Node for Windows x64 only. - # Mac users: Mac-Start.command runs setup.sh on first launch which - # downloads node-mac-arm64 from npmmirror.com (~30MB, ~10s in China). + # Mac users: START HERE - Mac.command runs setup.sh on first launch which + # downloads node-mac-arm64 from nodejs.org (~30MB). # Stanley pattern: ship one platform per zip, keep size reasonable. win_node="$runtime_dir/node-win-x64" mkdir -p "$win_node" @@ -121,15 +122,16 @@ jobs: --no-fund || echo "WARN: $cn_pkg install failed, skipping (便携版仍可用其它渠道)" done - # 6) Copy China-optimized skills if present - skills_cn="$stage_dir/skills-cn" + # 6) Install skills from the manifest. + # skills/ is the single source of truth (see skills/README.md). Ship it + # plus the installer onto the USB so the drive can re-install or switch + # locale offline, then populate OpenClaw's skills dir from it. skills_target="$core_dir/node_modules/openclaw/skills" - if [ -d "$skills_cn" ] && [ -d "$skills_target" ]; then - for skill_dir in "$skills_cn"/*/; do - skill_name=$(basename "$skill_dir") - [ ! -d "$skills_target/$skill_name" ] && cp -R "$skill_dir" "$skills_target/$skill_name" - done - fi + mkdir -p "$stage_dir/lib" "$skills_target" + cp -R skills "$stage_dir/skills" + cp lib/install-skills.mjs "$stage_dir/lib/install-skills.mjs" + node "$stage_dir/lib/install-skills.mjs" --target "$skills_target" --locale en + echo "Skills on the drive: $(ls -1 "$skills_target" | wc -l)" # 6b) Install WeChat (Weixin) plugin into app/extensions/openclaw-weixin # 官方 npm 包 @tencent-weixin/openclaw-weixin 自带 dist/index.js(发布时已编译,无需 build)。 @@ -191,7 +193,11 @@ jobs: tag_name="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}" cd dist zip -qry "u-claw-portable-windows-${tag_name}.zip" "u-claw-portable-windows-${tag_name}" + # Publish a checksum next to every asset so installers can verify what + # they downloaded instead of trusting "the file is bigger than 1MB". + sha256sum "u-claw-portable-windows-${tag_name}.zip" > "u-claw-portable-windows-${tag_name}.zip.sha256" ls -lh "u-claw-portable-windows-${tag_name}.zip" + cat "u-claw-portable-windows-${tag_name}.zip.sha256" - name: Size guard (lesson from 5916ff5 — GitHub 2GB asset cap) run: | @@ -211,7 +217,9 @@ jobs: - uses: actions/upload-artifact@v4 with: name: portable-windows-full - path: dist/u-claw-portable-windows-*.zip + path: | + dist/u-claw-portable-windows-*.zip + dist/u-claw-portable-windows-*.zip.sha256 publish: name: Publish GitHub Release @@ -255,8 +263,8 @@ jobs: ### 下载 - - **Windows 便携完整版(U 盘版)**:`u-claw-portable-windows-*.zip`(约 150-200 MB,已预装 Node.js + OpenClaw,**解压即用,零网络依赖**)。解压到 U 盘后双击 `Windows-Start.bat` 启动。 - - **macOS 便携版**:源码在 `portable/` 目录,`bash setup.sh` 自动下载 Node + OpenClaw(国内镜像约 1 分钟),双击 `Mac-Start.command` 启动。 + - **Windows 便携完整版(U 盘版)**:`u-claw-portable-windows-*.zip`(约 150-200 MB,已预装 Node.js + OpenClaw,**解压即用,零网络依赖**)。解压到 U 盘后双击 `START HERE - Windows.bat` 启动。 + - **macOS 便携版**:源码在 `portable/` 目录,`bash setup.sh` 自动下载 Node + OpenClaw(约 1 分钟),双击 `START HERE - Mac.command` 启动。 > **U 盘格式建议**:请用 **NTFS** 格式化 U 盘(NOT exFAT/FAT32)。Node.js 在 exFAT 上 IO 极慢且不支持符号链接,可能导致启动失败。 > Windows 下右键 U 盘 → 格式化 → 文件系统选择 NTFS。 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..c8cce97 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,24 @@ +name: Tests + +# The launcher/manifest tests were previously local-only — nothing ran them in CI, +# so the guards they encode (pure-ASCII .bat, LF-only .command, no China-routed +# download sources, installer parity) could regress unnoticed on a merge. +on: + push: + branches: ['**'] + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '22.22.1' + registry-url: 'https://registry.npmjs.org' + + - name: Run tests + run: node --test tests/ diff --git a/.github/workflows/track-upstream.yml b/.github/workflows/track-upstream.yml index e3e62de..c46561c 100644 --- a/.github/workflows/track-upstream.yml +++ b/.github/workflows/track-upstream.yml @@ -60,13 +60,7 @@ jobs: latest="${force#v}" echo "强制指定上游版本: $latest" else - latest="$(npm view openclaw version --registry=https://registry.npmmirror.com 2>/dev/null | tr -d '[:space:]')" - # npmmirror 偶尔缓存陈旧,官方源兜底取较大值 - official="$(npm view openclaw version 2>/dev/null | tr -d '[:space:]')" - if [ -n "$official" ] && [ "$official" != "$latest" ]; then - # 取版本号较大的那个(npmmirror 缓存滞后时用官方源) - latest="$(printf '%s\n%s\n' "$latest" "$official" | sort -V | tail -1)" - fi + latest="$(npm view openclaw version --registry=https://registry.npmjs.org 2>/dev/null | tr -d '[:space:]')" echo "npm latest openclaw: $latest" fi if [ -z "$latest" ]; then diff --git a/CLAUDE.md b/CLAUDE.md index 980d792..25e0063 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,14 +29,14 @@ Distribution forms: ```bash # Portable version — build dev copy -cd portable && bash setup.sh # Downloads Node.js v22 + OpenClaw + WeChat/QQ plugin to app/ -bash Mac-Start.command # Launch (Mac ARM64). Windows: Windows-Start.bat +cd portable/advanced && bash setup.sh # Downloads Node.js v22 + OpenClaw + plugins into ../app/ +cd .. && bash "START HERE - Mac.command" # Launch (Mac). Windows: double-click "START HERE - Windows.bat" # Copy to USB drive cp -R portable/ /Volumes/YOUR_USB/U-Claw/ # Electron desktop app -cd u-claw-app && bash setup.sh # One-click: Node.js + Electron + deps (China mirrors) +cd u-claw-app && bash setup.sh # One-click: Node.js + Electron + deps npm run dev # Dev mode npm run build:mac-arm64 # Build Mac ARM64 DMG npm run build:win # Build Windows NSIS + portable @@ -44,7 +44,7 @@ npm run build:win # Build Windows NSIS + portable # Bootable Linux USB (run on Windows PowerShell as Admin) cd bootable .\1-prepare-usb.ps1 # Write Ventoy to USB (formats drive!) -.\2-download-iso.ps1 # Download Ubuntu ISO (~5.8GB, China mirrors) +.\2-download-iso.ps1 # Download Ubuntu ISO (~5.8GB) .\3-create-persistence.ps1 # Create 20GB ext4 persistence image .\4-copy-to-usb.ps1 # Copy ISO + persistence + scripts to USB ``` @@ -56,11 +56,14 @@ node --test tests/ # Run all tests (node:test, no test framework de node --test tests/windows-launchers.test.mjs # Run one test file ``` -Tests assert on the **text/behavior of the launcher scripts** (`.bat`/`.command`) — e.g. that -`Windows-Start.bat` escapes `^(...^)` parens inside IF blocks and disables OpenClaw bonjour -discovery. They read repo files as strings; they do **not** spawn OpenClaw. There is no root -`package.json` — tests are not run by the release CI (`.github/workflows/release.yml` only -builds and publishes). Run them locally before pushing launcher changes. +Tests assert on the **text/behavior of the launchers and shared `.mjs` helpers** — e.g. that the +Start launchers stay thin shells over `lib/start.mjs`, that `.bat` files are pure ASCII with CRLF, +that no China-routed download source comes back, that the two installers resolve skills the same +way, and that every message key exists in every catalogue. They read repo files as strings; they +do **not** spawn OpenClaw. There is no root +`package.json`. **As of 2026-08-17 tests do run in CI** — `.github/workflows/tests.yml` runs +`node --test tests/` on every push and PR. Before that they were local-only, so the guards they +encode could regress unnoticed. **CI workflows** (`.github/workflows/`): `release.yml` builds Win/Mac portable + desktop and publishes a GitHub Release on tag push. `track-upstream.yml` runs daily (cron) — checks @@ -83,16 +86,24 @@ portable/ THE USB content (= repo + setup.sh downloads) {Mac,Windows}-Install — copy USB → computer (~/.uclaw/ or %USERPROFILE%) {Mac,Windows}-Diagnose — health check / collect logs for bug reports {Mac-OpenClaw-CLI,OpenClaw-CLI.bat} — drop into raw `openclaw` CLI - *.html (Welcome, Config, U-Claw, SkillHub) — local UI pages + *.html (Welcome, U-Claw, SkillHub) — local UI pages + Config.html — redirect shim only; the settings UI itself is + config-server/public/index.html (single implementation since 2026-08-17). + The old standalone copy called the API on a root-relative path, which + cannot work from file:// — Save failed silently for anyone who opened it. config-server/server.js — local HTTP server (port 18788-18798) backing Config.html: writes openclaw.json, WeChat QR login, update-status API lib/ — Node helpers (see "lib/ helpers" below) default-config.json — seed config copied to data/.openclaw/ on first run app/core/ (OpenClaw) + app/runtime/ (Node.js) — downloaded by setup.sh data/.openclaw/openclaw.json — user config (on USB, portable) - skills-cn/ — 17 个中国本地化技能(小红书/微博/B站/抖音/知乎/ - 微信公众号/Word/Excel/PPT/天气/搜索/翻译/DeepSeek/ - 图片压缩/PDF工具/二维码/网页转Markdown) +skills/ Single source of truth for skill content + distribution (2026-08-17). + manifest.json — the only thing installers read + en//SKILL.md — content + Replaces the old three-way split (portable/skills-cn/ on disk, + heredocs in install.sh, here-strings in install.ps1). See skills/README.md. + Installed by lib/install-skills.mjs; release.yml copies skills/ + the + installer onto the drive so it can re-install offline. u-claw-app/ [DEPRECATED 2026-06-19, archived — not built/published] Electron desktop app (main.js ~400 lines). Kept for archive only; see u-claw-app/DEPRECATED.md. @@ -102,24 +113,31 @@ bootable/ Linux 可启动 U 盘模块(完全独立,不依赖其他 4 步 PowerShell 脚本 (Windows 上制作) Ventoy 1.0.99 + Ubuntu 24.04 LTS + casper-rw 持久化 linux-setup/ — setup-openclaw.sh 安装到 /opt/u-claw/ - 独立仓库镜像: github.com/dongsheng123132/u-claw-linux + 独立仓库镜像: gitea.fanghe.it.com/zhenghy/u-claw-linux install/ 一键在线安装模块(curl | bash / irm | iex) install.sh (Mac/Linux) + install.ps1 (Windows) - 7 步流程: 系统检测 → Node.js → OpenClaw → QQ插件 → 技能 → 模型配置 → 启动脚本 + 7 步流程: 系统检测 → Node.js → OpenClaw → QQ插件 → 技能(读 skills/manifest.json) → 模型配置 → 启动脚本 安装到 ~/.uclaw/,与 Mac-Install.command 结果相同 ``` -> **Note**: 官网 (u-claw.org) 已拆分到独立私有仓库 [u-claw.org](https://github.com/dongsheng123132/u-claw.org),本仓库不再包含 website/ 和 vercel.json。 -> **虾航**: AI人导航站 (nav.u-claw.org) 在独立私有仓库 [xiahang](https://github.com/dongsheng123132/xiahang)。 +> **This is a fork.** Upstream is `github.com/dongsheng123132/u-claw`; we host at +> `gitea.fanghe.it.com/zhenghy/u-claw` and do **not** send changes back — the overseas +> build removes the China-market defaults that are the point of the upstream project. +> See `origin.json` for every URL this build fetches at runtime, and the migration +> notes in the workspace root. +> +> **The website is upstream's and we do not have it.** They split it out on 2026-04-14 +> (commit `65f830e`) into a private repo of their own. `guide.html` lives there, so the +> website work in the overseas plan is blocked until we either get access or build our own. Both portable and desktop versions auto-find a free port in range 18789–18799 and start the OpenClaw gateway. On first run, they detect whether a model is configured — if not, they open Config.html; otherwise, they open the dashboard. ## Key Technical Details - **Node.js discovery**: Portable looks at `app/runtime/node-mac-arm64/bin/node`; Electron looks at `resources/runtime/node-{platform}-{arch}` then falls back to system `node` -- **China mirrors**: All downloads use `npmmirror.com` — Node.js binaries from `npmmirror.com/mirrors/node`, npm packages from `registry.npmmirror.com` +- **Download sources (overseas build, 2026-08-17)**: Node.js binaries from `nodejs.org/dist`, npm packages from `registry.npmjs.org`, GitHub assets direct. No China-routed mirrors or GitHub proxies remain in scripts, launchers or CI — `tests/no-china-sources.test.mjs` fails the build if any come back. - **`OPENCLAW_VERSION` file**: single source of truth for the bundled OpenClaw runtime version (e.g. `2026.6.8`). CI reads it to pin the npm install; it's copied into `portable/` so USB users / `check-update.mjs` can compare installed vs latest. Bump this file to upgrade. - **Environment variables**: `OPENCLAW_HOME`, `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH` control where OpenClaw reads config - **macOS quarantine**: Mac scripts run `xattr -rd com.apple.quarantine` to remove Gatekeeper blocks @@ -140,7 +158,9 @@ Pure-Node, zero-dependency `.mjs` modules (use `fetch` + `node:zlib` only). All | `portable-cache.mjs` | **启动加速核心**:把"重 IO、可重建"的缓存从 U 盘搬到本机硬盘。算出本机缓存根(win `%LOCALAPPDATA%\U-Claw\` / mac `~/Library/Caches/U-Claw` / linux `$XDG_CACHE_HOME`,UUID 隔离让换盘符仍复用),输出 `NODE_COMPILE_CACHE` 路径,并把 `data/.openclaw/browser` 做成 junction(win)/symlink(mac) 指向本机盘——浏览器 user-data 的海量随机小写不再砸 U 盘。CLI 打印 `KEY=VALUE` 供启动脚本 source。静默失败:取不到就缓存留 U 盘照常启动。 | | `prewarm.mjs` | gateway 首轮预热:端口就绪后后台静默 GET `/ready`→`/status`→`/models`(带 `x-openclaw-token`),把 config/model 子系统在 runtime 内存里热起来,用户首次点发送不再等。零依赖、短超时、后台 detach。 | | `loading.html` | 启动首屏(splash):双击启动后立刻打开,给即时反馈消除"黑窗假死"。本页每秒 fetch `/ready`,gateway 真就绪后自动 `location.replace` 跳 Dashboard——天然规避"gateway 没起就开 Dashboard 拒连"(issue #46/#48)。端口经 `?port=` 传入。 | -| `wait-gateway.bat` | Windows 兜底:现由 `loading.html` 首屏轮询并自动跳转;本脚本退居兜底——万一首屏 `file://` fetch 被浏览器拦,仍轮询端口、就绪后开 Dashboard。 | +| `start.mjs` | **启动主逻辑(2026-08-17 起)**:运行时检测、数据目录、缓存加速、默认配置、依赖安装、NO_PROXY、微信插件、config-server 启动与端口发现、gateway 端口扫描、首屏与控制台打开、预热、兜底轮询、退出清理。`.bat`/`.command` 退化为 ~30 行的启动壳。这样两平台不会再漂,且所有面向用户的文案可翻译。 | +| `i18n.mjs` + `messages/{en,zh-CN}.json` | 启动器与本地页面的词条。语言优先级:显式覆盖 > 盘内配置 `uclaw.locale` > 系统 locale > en —— **语言跟盘走,不跟机器走**。key 用语义命名,缺失自动回落英文。 | +| ~~`wait-gateway.bat`~~ | 已移除(2026-08-17)。兜底轮询并入 `start.mjs` 的 `watchGatewayReady()`,现在 macOS 也有了 —— 此前只有 Windows 有。 | | `maintain.sh` | Maintenance/diagnostics script. | ### 启动加速(吸收自 v2 u-clawx 4.0 的工程经验,2026-06-17) @@ -159,7 +179,7 @@ Pure-Node, zero-dependency `.mjs` modules (use `fetch` + `node:zlib` only). All ### 模型配置 ("选模型填 Key") -Config.html 列出国内外大模型供用户挑选。首选卡片是 **虾盘云** (Xiapan Cloud 中转站,`api.u-claw.org/v1`) +设置页(`config-server/public/index.html`,旧入口 `Config.html` 会重定向过来)列出模型供用户挑选。首选卡片是 **虾盘云** (Xiapan Cloud 中转站,`api.u-claw.org/v1`) ——一个 Key 调用 DeepSeek / Claude / GPT / 通义 等全部模型,但和其它 provider 一样**需要用户自己去 `https://u-claw.org/cloud.html` 注册拿 Key**,不再自动开户。其余 provider (DeepSeek/通义/Kimi/智谱/ 豆包/MiniMax/OpenAI/Claude/Groq/硅基流动/自定义) 填各家官方 Key 即可。配置只写本地 @@ -187,14 +207,14 @@ Release artifacts go to GitHub Releases, not the repo. - Mac Apple Silicon (ARM64): ✅ Working - Mac Intel (x64): ✅ Working(portable 需先运行 setup.sh 下载 node-mac-x64) - Windows x64: 🚧 In development -- Linux x64 (Bootable USB): ✅ `bootable/` 目录 + 独立仓库 [u-claw-linux](https://github.com/dongsheng123132/u-claw-linux) +- Linux x64 (Bootable USB): ✅ `bootable/` 目录 + 独立仓库 [u-claw-linux](https://gitea.fanghe.it.com/zhenghy/u-claw-linux) ## Bootable Linux Key Details - **制作环境**: Windows 10/11 + PowerShell (Admin),4 步脚本 - **U 盘要求**: 32GB+ USB 3.0 - **技术栈**: Ventoy 1.0.99 引导 → Ubuntu 24.04 ISO → casper-rw 持久化 → OpenClaw 安装到 /opt/u-claw/ -- **国内镜像**: ISO 下载走清华/阿里/中科大,Node.js 和 npm 走 npmmirror.com +- **下载源**: ISO 走 releases.ubuntu.com,Node.js 走 nodejs.org,npm 走 registry.npmjs.org - **Linux 环境变量**: `OPENCLAW_HOME=/opt/u-claw/data/.openclaw` - **bootable/ 完全独立**: 不引用 portable/、u-claw-app/ 的任何文件,修改互不影响 - **同步**: bootable/ 内容与 u-claw-linux 仓库保持一致,改一边要记得同步另一边 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6ef795b..473e76c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ ```bash # 1. Clone -git clone https://github.com/dongsheng123132/u-claw.git +git clone https://gitea.fanghe.it.com/zhenghy/u-claw.git cd u-claw # 2. 选一个形态调试。最快的是 portable/ @@ -86,7 +86,7 @@ bash Mac-Start.command # macOS 启动 fix(portable): node-extract path missing intermediate dir fix(install.sh): npm wrapper不能用 node 直接执行 docs: 补充 Windows 11 ARM64 支持说明 -feat(skills-cn): 增加 douyin-script 技能 +feat(skills): 增加 linkedin-post 技能 ``` 不接受:"update"、"fix"、"修改若干文件" 这种。 @@ -129,7 +129,7 @@ git push origin fix/install-sh-npm-path - 4 步 PowerShell 脚本必须**按顺序**跑 - ISO 下载走清华/阿里/中科大镜像,不要直接用 ubuntu.com -- `bootable/` 与独立仓库 `dongsheng123132/u-claw-linux` 内容保持同步,改一边记得同步另一边 +- `bootable/` 与独立仓库 `zhenghy/u-claw-linux` 内容保持同步,改一边记得同步另一边 ### `install/` @@ -138,7 +138,7 @@ git push origin fix/install-sh-npm-path - 安装目录固定为 `~/.uclaw/`(Mac/Linux)或 `%USERPROFILE%\.uclaw\`(Windows) - 启动脚本要找空闲端口(18789-18799),不要写死 -### `skills-cn/` +### `skills/` - 技能格式是 `/SKILL.md`,frontmatter 里有 `name`、`description`、`metadata` - 技能内容用中文写,给中国用户看 diff --git a/NODE_VERSION b/NODE_VERSION new file mode 100644 index 0000000..5ecee25 --- /dev/null +++ b/NODE_VERSION @@ -0,0 +1 @@ +v22.22.1 diff --git a/README.md b/README.md index 126f384..7d3334e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@

- U-Claw:随身携带的 AI 工作空间 + U-Claw — your AI workspace on a USB drive

-

U-Claw(虾盘)

+

U-Claw

-

把 AI 工作空间装进 U 盘:插上任意电脑,配置、记忆和工具都跟着走。

+

An AI workspace on a USB drive. Plug it into any computer — your settings, memory and tools come with it.

- 下载便携版 · - 完整教程 · - 从源码制作 · - English + Download · + Guide · + Build from source · + 中文

@@ -20,556 +20,132 @@

> [!IMPORTANT] -> 这不是 U 盘制作工具。这个仓库就是 U 盘的文件骨架:运行一次 `setup.sh` 补齐运行时,再把整个 `portable/` 拷到盘里即可。 +> This repository is not a tool that builds a USB drive — it **is** the drive's contents. Run `setup.sh` once to fetch the runtime, then copy `portable/` onto the drive. -## 三步开始 +## Why a USB drive -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`。 +Three reasons, and they are the whole pitch: -| 你得到什么 | 为什么重要 | -| --- | --- | -| 随身 AI 工作空间 | 换电脑时带走配置、记忆与工具,不在主机残留用户数据。 | -| 本地优先 | 不绑定设备、不打指纹、不上传本地配置。 | -| 多种使用方式 | 便携 U 盘、在线一键安装、可启动 Linux U 盘各自独立。 | +1. **Your work computer will not let you install software.** Finance, government contracting and most regulated industries lock this down. A USB drive needs no installer and no admin rights. +2. **Your setup travels with you.** Model keys, chat history and project memory live in `data/` on the drive, not on whichever machine you borrowed. +3. **Nothing is left behind on the host.** Pull the drive out and walk away. (One caveat, stated plainly: U-Claw writes a rebuildable cache to the host's local disk to keep startup fast on slow drives. There is a one-click clean-up under `advanced/`.) -> [!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)* +## Get started ---- +1. Download the portable build from [Releases](https://gitea.fanghe.it.com/zhenghy/u-claw/releases), unzip it onto a USB drive, and double-click `START HERE - Windows.bat` (or `START HERE - Mac.command`). +2. Settings opens by itself. Paste an API key — U-Claw identifies the provider and checks the key before letting you continue. +3. Start talking. - +**No key yet?** [Google Gemini](https://aistudio.google.com/apikey) is the quickest: sign in with a Google account, no card, free tier. [OpenRouter](https://openrouter.ai/keys) is a good second choice if you want one key across many models. -## 中文 - -### 这是什么 - -U-Claw(虾盘)是一个**制作教程 + 全套源代码**,教你把 [OpenClaw](https://github.com/openclaw/openclaw)(开源 AI 助手框架)做成 U 盘——插上任意电脑,双击就能用 AI。为什么叫虾盘?U-Claw = USB + Claw(虾钳),U 盘 + AI = 虾盘。 - -代码库本身就是 U 盘的文件骨架,运行 `setup.sh` 补齐大依赖后,整个 `portable/` 目录直接拷贝到 U 盘即可。 - -> 📖 **[完整教程](https://u-claw.org/tutorial.html)** — 从零开始的手工安装指南、模型配置、聊天平台接入,小白也能看懂。 - -### 🧩 模型随便选:国内外大模型都能用 - -U-Claw 是纯开源工具,**不绑定设备、不打指纹、不上传任何数据**。首次启动会自动打开 Config 页面,选一个模型、填入自己的 API Key 即可一键启动: - -- **虾盘云(首选 · 中转站)**:一个 Key 调用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙。注册并充值:[u-claw.org/cloud.html](https://u-claw.org/cloud.html) -- **各家官方 Key 也行**:DeepSeek、通义千问、Kimi、智谱 GLM、豆包、MiniMax(国内)/ OpenAI、Claude、Groq(国外)/ 硅基流动、任意 OpenAI 兼容地址(自定义) -- **配置只存在本地** `data/.openclaw/openclaw.json`,拔盘不留痕 - -### 一键安装(推荐) - -不需要 U 盘,一行命令直接装到电脑: - -```bash -# Mac / Linux -curl -fsSL https://u-claw.org/install.sh | bash - -# Windows (PowerShell 管理员) -irm https://u-claw.org/install.ps1 | iex -``` - -自动完成: Node.js 下载 → OpenClaw 安装 → 10 个中国技能 → 模型配置 → 启动脚本生成。全程国内镜像,无需翻墙。 - -详见 [`install/README.md`](install/README.md)。 - -### 快速开始:制作便携版 U 盘 - -```bash -# 1. 克隆代码 -git clone https://github.com/dongsheng123132/u-claw.git - -# 2. 补齐大依赖(Node.js + OpenClaw,国内镜像,约 1 分钟) -cd u-claw/portable && bash setup.sh - -# 3. 拷贝到 U 盘 -cp -R portable/ /Volumes/你的U盘/U-Claw/ # Mac -# 或 Windows 资源管理器直接拖过去 -``` - -**完成!** 插上 U 盘,双击启动脚本就能用。 - -### U 盘功能一览 - -| 功能 | Mac | Windows | -|------|-----|---------| -| **免安装运行** | `Mac-Start.command` | `Windows-Start.bat` | -| **功能菜单** | `Mac-Menu.command` | `Windows-Menu.bat` | -| **安装到电脑** | `Mac-Install.command` | `Windows-Install.bat` | -| **首次配置** | `Config.html` | `Config.html` | - -### U 盘文件结构 - -``` -U-Claw/ ← 整个拷到 U 盘 -├── Mac-Start.command Mac 免安装运行 -├── Mac-Menu.command Mac 功能菜单 -├── Mac-Install.command 安装到 Mac -├── Windows-Start.bat Windows 免安装运行 -├── Windows-Menu.bat Windows 功能菜单 -├── Windows-Install.bat 安装到 Windows -├── Config.html 首次配置页面 -├── setup.sh 补齐依赖(开发者用) -├── app/ ← 大依赖(setup.sh 下载,不进 git) -│ ├── core/ OpenClaw + QQ 插件 -│ └── runtime/ -│ ├── node-mac-arm64/ Mac Apple Silicon -│ ├── node-mac-x64/ Mac Intel -│ └── node-win-x64/ Windows 64-bit -└── data/ ← 用户数据(不进 git) - ├── .openclaw/ 配置文件 - ├── memory/ AI 记忆 - └── backups/ 备份 -``` - -### Linux 可启动版 - -连操作系统都没有?没关系。可启动版可以让任意电脑从 U 盘直接启动 Ubuntu + AI: - -- 本仓库内:[`bootable/`](bootable/) 目录(与其他模块完全独立,互不影响) -- 独立仓库:[u-claw-linux](https://github.com/dongsheng123132/u-claw-linux)(内容一致,方便单独克隆) - -基于 Ventoy + Ubuntu 24.04 LTS + 持久化存储,在 Windows 上运行 4 步 PowerShell 脚本即可制作。详见 [`bootable/README.md`](bootable/README.md)。 - -> **关于桌面安装版(Electron)**:`u-claw-app/` 的 Electron 桌面版(`.exe` 安装版 / 绿色版 / `.dmg`)**已于 2026-06-19 停止发布并归档**,原因见 [`u-claw-app/DEPRECATED.md`](u-claw-app/DEPRECATED.md)。U-Claw 现在只发布「便携 U 盘版」——这才是产品的本质:插上 U 盘、解压即用。 - -### 直接下载发行版 - -[GitHub Releases](https://github.com/dongsheng123132/u-claw/releases) 提供便携 U 盘版: - -- `u-claw-portable-windows-vX.Y.Z.zip` — Windows 便携完整版(已预装 Node + OpenClaw,**解压到 U 盘双击 `Windows-Start.bat` 即用**) -- **Mac**:源码在 [`portable/`](portable/) 目录,`bash setup.sh` 自动下载 Node + OpenClaw(国内镜像约 1 分钟),双击 `Mac-Start.command` 启动 - -> ⚠️ **U 盘请用 NTFS 格式**(不要 exFAT/FAT32):Node.js 在 exFAT 上 IO 极慢且不支持符号链接,可能导致启动失败。 - -### 支持的 AI 模型 - -**国产模型(无需翻墙):** - -| 模型 | 推荐场景 | -|------|----------| -| DeepSeek | 编程首选,极便宜 | -| Kimi K2.5 | 长文档,256K 上下文 | -| 通义千问 Qwen | 免费额度大 | -| 智谱 GLM | 学术场景 | -| MiniMax | 语音多模态 | -| 豆包 Doubao | 火山引擎 | - -**国际模型:** Claude · GPT · Gemini(需翻墙或中转) - -### 支持的聊天平台 - -| 平台 | 状态 | 说明 | -|------|------|------| -| QQ | ✅ 已预装 | 输入 AppID + Secret 即可 | -| 飞书 | ✅ 内置 | 企业首选 | -| Telegram | ✅ 内置 | 海外推荐 | -| WhatsApp | ✅ 内置 | Baileys 协议 | -| Discord | ✅ 内置 | — | -| 微信 | ✅ 社区插件 | iPad 协议 | - -### 国内镜像 - -所有脚本默认走国内镜像,无需翻墙: - -| 资源 | 镜像 | -|------|------| -| npm 包 | `registry.npmmirror.com` | -| Node.js | `npmmirror.com/mirrors/node` | -| Electron | `npmmirror.com/mirrors/electron` | - -### 开发 & 贡献 - -```bash -git clone https://github.com/dongsheng123132/u-claw.git -cd u-claw/portable && bash setup.sh -bash Mac-Start.command # Mac 测试 -``` - -**平台支持:** - -| 平台 | 状态 | 说明 | -|------|------|------| -| Mac Apple Silicon (M1-M4) | ✅ | 便携版 | -| Mac Intel (x64) | ✅ | 便携版 | -| Windows x64 | 🚧 开发中 | 便携版 | -| Linux x64(可启动 U 盘) | ✅ | [`bootable/`](bootable/) 目录 | - -欢迎 PR!特别需要:Windows 脚本完善、教程翻译。 - -### 🦞 寻找技术伙伴 - -U-Claw 是一个快速成长的开源项目,目前已有不少商业合作机会。 - -我们正在寻找: -- **技术伙伴** — 全栈 / Node.js / Electron / 脚本自动化 -- **资源合作** — 渠道、内容、社区运营 - -如果你对 AI 工具的落地和商业化感兴趣,欢迎联系: - -- 微信: hecare888 -- Telegram: [@dsds8848](https://t.me/dsds8848) -- Twitter/X: [@Bitplus888](https://x.com/Bitplus888) -- Email: [hefangsheng@gmail.com](mailto:hefangsheng@gmail.com) -- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) -- 官网: [u-claw.org](https://u-claw.org) - -### FAQ - -**Q: 需要翻墙吗?** -不需要。安装和运行全程使用国内镜像,国产模型 API 直连。 - -**Q: U 盘需要多大?** -4GB+(完整约 2.3GB)。 - -**Q: 能分发吗?** -MIT 协议,随便复制分发。 - -**Q: Mac 提示"未验证的开发者"?** -右键脚本 → 打开。 - -**Q: setup.bat / setup.sh 执行失败,提示模块找不到?** -通常是 npm install 过程中网络中断导致 `node_modules` 不完整。解决步骤: -1. 删除不完整的依赖:`rmdir /s /q portable\app\core\node_modules`(Windows)或 `rm -rf portable/app/core/node_modules`(Mac) -2. 切换淘宝镜像重新安装:`cd portable/app/core && npm install --registry=https://registry.npmmirror.com` - -**Q: 系统已有 Node.js v24,安装失败?** -Node.js v24 是最新开发版,部分依赖尚不兼容。需要 **v20 或 v22 LTS**。删除已下载的 runtime 目录后重新运行 setup,它会自动下载内置的 Node v22: -```bash -# Windows -rmdir /s /q portable\app\runtime\node-win-x64 -setup.bat - -# Mac -rm -rf portable/app/runtime/node-mac-arm64 -bash setup.sh -``` - -**Q: Mac 上提示 `.toSorted is not a function`?** -系统旧版 Node.js 被检测到并跳过了内置版本下载,但旧版 Node 不支持 `.toSorted()`(需要 v20+)。删除 runtime 目录让脚本重新下载内置 Node v22: -```bash -rm -rf portable/app/runtime/node-mac-arm64 -bash setup.sh -``` - -**Q: 如何同时配置多个 AI 模型并切换?** -支持同时配置多个 provider!打开 `Config.html` → 在 Providers 区域点击「添加」,逐个填入各模型的 API Key 和地址(如 DeepSeek、Kimi、通义等)→ 保存后,在聊天界面左上角下拉菜单随时切换。配置持久保存在 U 盘上。 - -**Q: U 盘安装后无法创建文件 / 写入失败?** -两种可能:① U 盘侧面有物理写保护开关,拨到解锁位置;② U 盘格式不兼容,建议格式化为 **exFAT**(Mac/Windows/Linux 三端均支持读写)。 - -**Q: 从 Ubuntu 向 U 盘复制时符号链接丢失?** -`node_modules/.bin/` 下有大量符号链接,FAT32/exFAT 在直接 `cp -R` 时会跳过。用 `rsync -aL` 可将符号链接展开为真实文件: -```bash -rsync -aL --progress portable/ /media/YOUR_USB/U-Claw/ -``` - -**Q: QQbot 报错 `Unknown channel: qqbot`?** -Bundle 里的 `@sliverp/qqbot` 是未编译的 TypeScript 源码,需要先编译: -```bash -cd portable/app/core/node_modules/@sliverp/qqbot -npm install && npm run build -``` -正式 Release 包已修复此问题,建议从 [Releases](https://github.com/dongsheng123132/u-claw/releases) 下载最新版。 - -### 联系 & 合作 - -微信二维码 — 贺去病 ai 工作室 - -- 微信: hecare888(或扫右侧二维码) -- Telegram: [@dsds8848](https://t.me/dsds8848) -- Twitter/X: [@Bitplus888](https://x.com/Bitplus888) -- Email: [hefangsheng@gmail.com](mailto:hefangsheng@gmail.com) -- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) -- 官网: [u-claw.org](https://u-claw.org) - -**🤝 招募代理 / 带货合作** - -虾盘 3.0 体验极佳,退货率极低,售后由我们负责——你只管卖货: - -- **抖店 / 直播带货**:提供最高佣金比例,产品已在多个直播间验证转化 -- **代理分销**:买断或按单分润均可谈,支持定制版本 -- **技术合作**:有开发能力者欢迎深度合作 -- **👑 U-King 装机管家分销(新)**:[U-King](https://www.u-king.org) 软件本身免费送客户,客户按用量给 AI 模型 API 充值,你拿**持续分润**——不压货、零售后(我们负责),赚的是长期流水。适合装机店、AI 培训、社群主理人 - -有意向请微信联系(备注「代理合作」优先处理)。 - ---- - - - -## English - -### What is this - -U-Claw (aka "虾盘" / "Xia Pan" in Chinese, meaning "Claw Drive") is a **tutorial + complete source code** for building an [OpenClaw](https://github.com/openclaw/openclaw) (open-source AI assistant framework) USB drive — plug it into any computer, double-click, and start using AI. - -The codebase itself is the USB file skeleton. Run `setup.sh` to download large dependencies, then copy the entire `portable/` directory to a USB drive. - -> 📖 **[Full Tutorial](https://u-claw.org/tutorial.html)** — Step-by-step manual installation, model setup, chat platform integration. - -### One-Line Install (Recommended) - -No USB needed — install directly to your computer: - -```bash -# Mac / Linux -curl -fsSL https://u-claw.org/install.sh | bash - -# Windows (PowerShell as Admin) -irm https://u-claw.org/install.ps1 | iex -``` - -Automatically downloads Node.js, installs OpenClaw, configures 10 Chinese-optimized skills, and sets up your AI model. All downloads use China mirrors. - -See [`install/README.md`](install/README.md) for details. - -### Quick Start: Build a Portable USB - -```bash -# 1. Clone -git clone https://github.com/dongsheng123132/u-claw.git - -# 2. Download dependencies (Node.js + OpenClaw, ~1 min) -cd u-claw/portable && bash setup.sh - -# 3. Copy to USB drive -cp -R portable/ /Volumes/YOUR_USB/U-Claw/ # Mac -# Or drag & drop on Windows -``` - -**Done!** Plug in the USB, double-click the start script, and you're running AI. - -### USB Features - -| Feature | Mac | Windows | -|---------|-----|---------| -| **Run (no install)** | `Mac-Start.command` | `Windows-Start.bat` | -| **Menu** | `Mac-Menu.command` | `Windows-Menu.bat` | -| **Install to PC** | `Mac-Install.command` | `Windows-Install.bat` | -| **First-time config** | `Config.html` | `Config.html` | - -### File Structure - -``` -U-Claw/ ← Copy entire folder to USB -├── Mac-Start.command Mac launcher -├── Mac-Menu.command Mac menu -├── Mac-Install.command Install to Mac -├── Windows-Start.bat Windows launcher -├── Windows-Menu.bat Windows menu -├── Windows-Install.bat Install to Windows -├── Config.html First-time config page -├── setup.sh Download dependencies (dev use) -├── app/ ← Large deps (downloaded by setup.sh, not in git) -│ ├── core/ OpenClaw + QQ plugin -│ └── runtime/ -│ ├── node-mac-arm64/ Mac Apple Silicon -│ ├── node-mac-x64/ Mac Intel -│ └── node-win-x64/ Windows 64-bit -└── data/ ← User data (not in git) - ├── .openclaw/ Config file - ├── memory/ AI memory - └── backups/ Backups -``` - -### Linux Bootable USB - -No operating system? No problem. Boot any computer from USB into Ubuntu + AI: - -- In this repo: [`bootable/`](bootable/) directory (fully independent from other modules) -- Standalone repo: [u-claw-linux](https://github.com/dongsheng123132/u-claw-linux) (same content, easier to clone separately) - -Based on Ventoy + Ubuntu 24.04 LTS + persistence. 4-step PowerShell scripts on Windows. See [`bootable/README.md`](bootable/README.md) for details. - -> **About the Electron desktop app**: `u-claw-app/` (the `.exe` installer / portable / `.dmg` builds) was **deprecated and is no longer published as of 2026-06-19** — see [`u-claw-app/DEPRECATED.md`](u-claw-app/DEPRECATED.md). U-Claw now ships only the portable USB build, which is the product's essence: plug in the USB and run. - -### Supported AI Models - -**Chinese models (no VPN needed):** +## Models | Model | Best for | -|-------|----------| -| DeepSeek | Coding, extremely cheap | -| Kimi K2.5 | Long documents, 256K context | -| Qwen | Large free tier | -| GLM (Zhipu) | Academic use | -| MiniMax | Voice & multimodal | -| Doubao | Volcengine ecosystem | +|---|---| +| **Claude** | Best all-rounder | +| **GPT** | Most widely used | +| **Gemini** | Free tier, easiest signup | +| **SEA-LION** | Malay, Tamil and Singlish — built by AI Singapore | +| **Local model** | Offline. Nothing leaves the machine. | -**International models:** Claude · GPT · Gemini (VPN or relay required in China) +Others, including DeepSeek, Kimi, Qwen and GLM, are available under *Advanced* in Settings. -### Supported Chat Platforms +> **A note on SEA-LION**: the hosted API is free but currently rate-limited to 10 requests per minute per user, and there is no published paid tier. That is fine for chatting and tight for agent workloads, so it is offered as a specialist choice rather than a default. + +## Chat platforms | Platform | Status | Notes | -|----------|--------|-------| -| QQ | ✅ Pre-installed | Enter AppID + Secret | -| Feishu (Lark) | ✅ Built-in | Enterprise favorite | -| Telegram | ✅ Built-in | International | -| WhatsApp | ✅ Built-in | Baileys protocol | +|---|---|---| +| Telegram | ✅ Built-in | — | +| WhatsApp | ⚠️ Built-in | Uses the Baileys protocol, which is unofficial. There is a real risk of your account being banned — see the warning in Settings before connecting a number you care about. | | Discord | ✅ Built-in | — | -| WeChat | ✅ Community plugin | iPad protocol | +| Slack | ✅ Built-in | — | +| WeChat · QQ · Feishu · DingTalk | Available | Mainly useful for users in China — see [README.zh-CN.md](README.zh-CN.md) | -### China Mirrors - -All scripts use China mirrors by default — no VPN needed: - -| Resource | Mirror | -|----------|--------| -| npm packages | `registry.npmmirror.com` | -| Node.js | `npmmirror.com/mirrors/node` | -| Electron | `npmmirror.com/mirrors/electron` | - -### Development & Contributing +## Build it yourself ```bash -git clone https://github.com/dongsheng123132/u-claw.git -cd u-claw/portable && bash setup.sh -bash Mac-Start.command # Test on Mac +git clone https://gitea.fanghe.it.com/zhenghy/u-claw.git +cd u-claw/portable/advanced && bash setup.sh # fetches Node.js + OpenClaw, about a minute + +cp -R portable/ /Volumes/YOUR_USB/U-Claw/ # Mac +# On Windows, drag the folder onto the drive ``` -**Platform Support:** +## What is on the drive -| Platform | Status | Notes | -|----------|--------|-------| -| Mac Apple Silicon (M1-M4) | ✅ | Portable + Desktop | -| Mac Intel (x64) | ✅ | Portable + Desktop | -| Windows x64 | 🚧 In progress | Portable + Desktop | -| Linux x64 (Bootable USB) | ✅ | [`bootable/`](bootable/) directory | +| | Mac | Windows | +|---|---|---| +| **Run it** | `START HERE - Mac.command` | `START HERE - Windows.bat` | +| **All the other tools** | `Mac-Menu.command` | `Windows-Menu.bat` | +| **Copy onto this computer** | `Mac-Install.command` | `Windows-Install.bat` | +| **Settings** | opens on first run | opens on first run | -PRs welcome! Especially: Windows scripts, documentation. +``` +U-Claw/ +├── START HERE - Windows.bat ← double-click this +├── START HERE - Mac.command ← or this +├── Read me first.html Three-step walkthrough +├── advanced/ Diagnostics, CLI, install-to-PC, build scripts +├── skills/ Skill content + manifest.json +├── lib/ Launcher, i18n, helpers +├── app/ Runtime (fetched by setup.sh, not in git) +│ ├── core/ OpenClaw +│ └── runtime/node-{mac-arm64,mac-x64,win-x64}/ +└── data/ Your data (not in git) + ├── .openclaw/ Config + ├── memory/ What the AI remembers + └── backups/ +``` -### 🔧 Professional Services / 专业服务 +## Linux bootable USB -Need help? We offer remote support and custom development: +No operating system on the machine at all? Boot it from the drive into Ubuntu with U-Claw already installed. See [`bootable/`](bootable/), built on Ventoy + Ubuntu 24.04 LTS with persistence. -| Service | Description | Price | -|---------|-------------|-------| -| **Remote Installation** | We remotely install OpenClaw + skills + model config for you | Free | -| **Troubleshooting** | Startup failures, port conflicts, network issues | From ¥50 | -| **Model Tuning** | API key setup, model switching, prompt optimization | From ¥50 | -| **Custom Development** | Custom skills, enterprise private deployment, QQ/WeChat/Feishu bot integration | From ¥200 | -| **USB Green Edition** | Pre-built portable USB with your custom skills & models | From ¥100 | +> The Electron desktop app (`u-claw-app/`) was **deprecated on 2026-06-19** and is no longer published — see [`u-claw-app/DEPRECATED.md`](u-claw-app/DEPRECATED.md). The portable USB build is the product. -**One-click remote support** — run one command, we connect and fix it: +## Is this safe? + +- **Your API key is written to the drive only.** It is never sent anywhere except to the model provider you chose. +- **No telemetry.** No device fingerprinting, no usage reporting, no account required. This build has none of that code in it. +- **Your conversations stay in `data/` on the drive.** +- **What does leave the machine**: your messages go to whichever model provider you configured, exactly as they would in that provider's own app. If that is not acceptable for your data, use the local model option instead. + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md). Tests run on every push: ```bash -# Mac / Linux -curl -fsSL https://u-claw.org/remote.sh | bash - -# Windows (Admin PowerShell) -irm https://u-claw.org/remote.ps1 | iex +node --test tests/ ``` -WeChat: **hecare888** (备注「U-Claw 远程」优先处理) +They check the things that break quietly: launchers staying thin, `.bat` files staying pure ASCII, no China-routed download sources creeping back, both installers agreeing on the skill list, and every UI string existing in every language. -👉 [View full service details / 查看完整服务详情](https://u-claw.org/guide.html#remote-support) +## FAQ -### 🦞 Looking for Partners +**Do I need to install anything?** +No. That is the point. -U-Claw is a fast-growing open-source project with real commercial opportunities. +**Does it work on both Mac and Windows?** +Yes, from the same drive. Windows builds ship with the runtime included; on Mac the first launch fetches it (about a minute). -We're looking for: -- **Technical partners** — Full-stack / Node.js / Electron / scripting -- **Resource partners** — Distribution, content, community +**Where do my settings live?** +`data/.openclaw/openclaw.json` on the drive. Copy the drive, copy your setup. -If you're interested in AI tooling and commercialization, let's talk: +**Can I use it without an internet connection?** +Yes, with a local model. Everything else needs to reach your model provider. -- Telegram: [@dsds8848](https://t.me/dsds8848) -- Twitter/X: [@Bitplus888](https://x.com/Bitplus888) -- Email: [hefangsheng@gmail.com](mailto:hefangsheng@gmail.com) -- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) -- WeChat: hecare888 -- Website: [u-claw.org](https://u-claw.org) +**Which file system should the drive use?** +exFAT. macOS can only read NTFS, not write to it, which would break the whole "your settings travel with you" idea. -### FAQ +## Contact -**Q: Do I need a VPN?** -No. All downloads use China mirrors. Chinese AI model APIs work directly. - -**Q: How big should the USB drive be?** -4GB+ (~2.3GB full). - -**Q: Can I redistribute?** -MIT license — copy and share freely. - -**Q: Mac says "unverified developer"?** -Right-click the script → Open. - -**Q: setup.bat / setup.sh fails with "module not found"?** -Usually caused by a network interruption during `npm install`, leaving `node_modules` incomplete. Fix: -1. Delete incomplete dependencies: `rmdir /s /q portable\app\core\node_modules` (Windows) or `rm -rf portable/app/core/node_modules` (Mac) -2. Reinstall using China mirror: `cd portable/app/core && npm install --registry=https://registry.npmmirror.com` - -**Q: Already have Node.js v24 and installation fails?** -Node.js v24 is a dev release — some dependencies aren't compatible yet. You need **v20 or v22 LTS**. Delete the runtime folder to force a fresh download of the bundled Node v22: -```bash -# Windows -rmdir /s /q portable\app\runtime\node-win-x64 -setup.bat - -# Mac -rm -rf portable/app/runtime/node-mac-arm64 -bash setup.sh -``` - -**Q: Mac shows `.toSorted is not a function`?** -Your system Node.js was detected and the bundled version was skipped, but the system version is too old (needs v20+). Delete the runtime folder to re-download the bundled Node v22: -```bash -rm -rf portable/app/runtime/node-mac-arm64 -bash setup.sh -``` - -**Q: How do I use multiple AI models / providers?** -Multiple providers are supported! Open `Config.html` → click "Add" in the Providers section → enter API Key and endpoint for each model (DeepSeek, Kimi, Qwen, etc.) → save. Switch between models via the dropdown in the chat interface. Config is saved persistently on the USB drive. - -**Q: USB drive shows "cannot create file" / write errors?** -Two possibilities: ① The USB drive has a physical write-protect switch on the side — slide it to unlock; ② Format incompatibility — format the drive as **exFAT** (supported on Mac/Windows/Linux). - -**Q: Symlinks missing when copying from Ubuntu to USB?** -`node_modules/.bin/` contains many symlinks that get skipped during direct `cp -R`. Use `rsync -aL` to expand symlinks into real files: -```bash -rsync -aL --progress portable/ /media/YOUR_USB/U-Claw/ -``` - -**Q: QQbot error: `Unknown channel: qqbot`?** -The bundled `@sliverp/qqbot` is uncompiled TypeScript source. Compile it manually: -```bash -cd portable/app/core/node_modules/@sliverp/qqbot -npm install && npm run build -``` -This is fixed in the latest [Release](https://github.com/dongsheng123132/u-claw/releases) — downloading the pre-built release is recommended. - -### Contact & Partnership - -WeChat QR — He Qubing AI Studio - -- WeChat: hecare888 (or scan QR on the right) -- Telegram: [@dsds8848](https://t.me/dsds8848) -- Twitter/X: [@Bitplus888](https://x.com/Bitplus888) -- Email: [hefangsheng@gmail.com](mailto:hefangsheng@gmail.com) -- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) -- Website: [u-claw.org](https://u-claw.org) - -**🤝 Reseller / Affiliate Program** - -U-Claw 3.0 delivers excellent user experience with very low return rates. We handle all after-sales support — you focus on selling: - -- **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). +- Email — help@u-claw.org +- Issues — [GitHub](https://gitea.fanghe.it.com/zhenghy/u-claw/issues) +- Site — [u-claw.org](https://u-claw.org) --- -**Made with 🦞 by [贺去病 ai 工作室](https://github.com/dongsheng123132)** +

English · 中文

+ +

MIT License

diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..354811e --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,312 @@ +

+ U-Claw:随身携带的 AI 工作空间 +

+ +

U-Claw(虾盘)

+ +

把 AI 工作空间装进 U 盘:插上任意电脑,配置、记忆和工具都跟着走。

+ +

+ 下载便携版 · + 完整教程 · + 从源码制作 · + English +

+ +

+ MIT License + USB first + OpenClaw runtime +

+ +> [!IMPORTANT] +> 这不是 U 盘制作工具。这个仓库就是 U 盘的文件骨架:运行一次 `setup.sh` 补齐运行时,再把整个 `portable/` 拷到盘里即可。 + +## 三步开始 + +1. 从 [Releases](https://gitea.fanghe.it.com/zhenghy/u-claw/releases) 下载 Windows 便携版,解压到 U 盘后双击 `START HERE - Windows.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)* + +--- + + + +## 中文 + +### 这是什么 + +U-Claw(虾盘)是一个**制作教程 + 全套源代码**,教你把 [OpenClaw](https://github.com/openclaw/openclaw)(开源 AI 助手框架)做成 U 盘——插上任意电脑,双击就能用 AI。为什么叫虾盘?U-Claw = USB + Claw(虾钳),U 盘 + AI = 虾盘。 + +代码库本身就是 U 盘的文件骨架,运行 `setup.sh` 补齐大依赖后,整个 `portable/` 目录直接拷贝到 U 盘即可。 + +> 📖 **[完整教程](https://u-claw.org/tutorial.html)** — 从零开始的手工安装指南、模型配置、聊天平台接入,小白也能看懂。 + +### 🧩 模型随便选:国内外大模型都能用 + +U-Claw 是纯开源工具,**不绑定设备、不打指纹、不上传任何数据**。首次启动会自动打开 Config 页面,选一个模型、填入自己的 API Key 即可一键启动: + +- **虾盘云(首选 · 中转站)**:一个 Key 调用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙。注册并充值:[u-claw.org/cloud.html](https://u-claw.org/cloud.html) +- **各家官方 Key 也行**:DeepSeek、通义千问、Kimi、智谱 GLM、豆包、MiniMax(国内)/ OpenAI、Claude、Groq(国外)/ 硅基流动、任意 OpenAI 兼容地址(自定义) +- **配置只存在本地** `data/.openclaw/openclaw.json`,拔盘不留痕 + +### 一键安装(推荐) + +不需要 U 盘,一行命令直接装到电脑: + +```bash +# Mac / Linux +curl -fsSL https://u-claw.org/install.sh | bash + +# Windows (PowerShell 管理员) +irm https://u-claw.org/install.ps1 | iex +``` + +自动完成: Node.js 下载 → OpenClaw 安装 → 10 个中国技能 → 模型配置 → 启动脚本生成。全程国内镜像,无需翻墙。 + +详见 [`install/README.md`](install/README.md)。 + +### 快速开始:制作便携版 U 盘 + +```bash +# 1. 克隆代码 +git clone https://gitea.fanghe.it.com/zhenghy/u-claw.git + +# 2. 补齐大依赖(Node.js + OpenClaw,国内镜像,约 1 分钟) +cd u-claw/portable/advanced && bash setup.sh + +# 3. 拷贝到 U 盘 +cp -R portable/ /Volumes/你的U盘/U-Claw/ # Mac +# 或 Windows 资源管理器直接拖过去 +``` + +**完成!** 插上 U 盘,双击启动脚本就能用。 + +### U 盘功能一览 + +| 功能 | Mac | Windows | +|------|-----|---------| +| **免安装运行** | `START HERE - Mac.command` | `START HERE - Windows.bat` | +| **功能菜单** | `Mac-Menu.command` | `Windows-Menu.bat` | +| **安装到电脑** | `Mac-Install.command` | `Windows-Install.bat` | +| **首次配置** | `Config.html` | `Config.html` | + +### U 盘文件结构 + +``` +U-Claw/ ← 整个拷到 U 盘 +├── START HERE - Mac.command Mac 免安装运行 +├── Mac-Menu.command Mac 功能菜单 +├── Mac-Install.command 安装到 Mac +├── START HERE - Windows.bat Windows 免安装运行 +├── Windows-Menu.bat Windows 功能菜单 +├── Windows-Install.bat 安装到 Windows +├── Config.html 首次配置页面 +├── setup.sh 补齐依赖(开发者用) +├── app/ ← 大依赖(setup.sh 下载,不进 git) +│ ├── core/ OpenClaw + QQ 插件 +│ └── runtime/ +│ ├── node-mac-arm64/ Mac Apple Silicon +│ ├── node-mac-x64/ Mac Intel +│ └── node-win-x64/ Windows 64-bit +└── data/ ← 用户数据(不进 git) + ├── .openclaw/ 配置文件 + ├── memory/ AI 记忆 + └── backups/ 备份 +``` + +### Linux 可启动版 + +连操作系统都没有?没关系。可启动版可以让任意电脑从 U 盘直接启动 Ubuntu + AI: + +- 本仓库内:[`bootable/`](bootable/) 目录(与其他模块完全独立,互不影响) +- 独立仓库:[u-claw-linux](https://gitea.fanghe.it.com/zhenghy/u-claw-linux)(内容一致,方便单独克隆) + +基于 Ventoy + Ubuntu 24.04 LTS + 持久化存储,在 Windows 上运行 4 步 PowerShell 脚本即可制作。详见 [`bootable/README.md`](bootable/README.md)。 + +> **关于桌面安装版(Electron)**:`u-claw-app/` 的 Electron 桌面版(`.exe` 安装版 / 绿色版 / `.dmg`)**已于 2026-06-19 停止发布并归档**,原因见 [`u-claw-app/DEPRECATED.md`](u-claw-app/DEPRECATED.md)。U-Claw 现在只发布「便携 U 盘版」——这才是产品的本质:插上 U 盘、解压即用。 + +### 直接下载发行版 + +[GitHub Releases](https://gitea.fanghe.it.com/zhenghy/u-claw/releases) 提供便携 U 盘版: + +- `u-claw-portable-windows-vX.Y.Z.zip` — Windows 便携完整版(已预装 Node + OpenClaw,**解压到 U 盘双击 `START HERE - Windows.bat` 即用**) +- **Mac**:源码在 [`portable/`](portable/) 目录,`bash setup.sh` 自动下载 Node + OpenClaw(国内镜像约 1 分钟),双击 `START HERE - Mac.command` 启动 + +> ⚠️ **U 盘请用 NTFS 格式**(不要 exFAT/FAT32):Node.js 在 exFAT 上 IO 极慢且不支持符号链接,可能导致启动失败。 + +### 支持的 AI 模型 + +**国产模型(无需翻墙):** + +| 模型 | 推荐场景 | +|------|----------| +| DeepSeek | 编程首选,极便宜 | +| Kimi K2.5 | 长文档,256K 上下文 | +| 通义千问 Qwen | 免费额度大 | +| 智谱 GLM | 学术场景 | +| MiniMax | 语音多模态 | +| 豆包 Doubao | 火山引擎 | + +**国际模型:** Claude · GPT · Gemini(需翻墙或中转) + +### 支持的聊天平台 + +| 平台 | 状态 | 说明 | +|------|------|------| +| QQ | ✅ 已预装 | 输入 AppID + Secret 即可 | +| 飞书 | ✅ 内置 | 企业首选 | +| Telegram | ✅ 内置 | 海外推荐 | +| WhatsApp | ✅ 内置 | Baileys 协议 | +| Discord | ✅ 内置 | — | +| 微信 | ✅ 社区插件 | iPad 协议 | + +### 国内镜像 + +所有脚本默认走国内镜像,无需翻墙: + +| 资源 | 镜像 | +|------|------| +| npm 包 | `registry.npmmirror.com` | +| Node.js | `npmmirror.com/mirrors/node` | +| Electron | `npmmirror.com/mirrors/electron` | + +### 开发 & 贡献 + +```bash +git clone https://gitea.fanghe.it.com/zhenghy/u-claw.git +cd u-claw/portable/advanced && bash setup.sh +bash "START HERE - Mac.command" # Mac 测试 +``` + +**平台支持:** + +| 平台 | 状态 | 说明 | +|------|------|------| +| Mac Apple Silicon (M1-M4) | ✅ | 便携版 | +| Mac Intel (x64) | ✅ | 便携版 | +| Windows x64 | 🚧 开发中 | 便携版 | +| Linux x64(可启动 U 盘) | ✅ | [`bootable/`](bootable/) 目录 | + +欢迎 PR!特别需要:Windows 脚本完善、教程翻译。 + +### 🦞 寻找技术伙伴 + +U-Claw 是一个快速成长的开源项目,目前已有不少商业合作机会。 + +我们正在寻找: +- **技术伙伴** — 全栈 / Node.js / Electron / 脚本自动化 +- **资源合作** — 渠道、内容、社区运营 + +如果你对 AI 工具的落地和商业化感兴趣,欢迎联系: + +- 微信: hecare888 +- Telegram: [@dsds8848](https://t.me/dsds8848) +- Twitter/X: [@Bitplus888](https://x.com/Bitplus888) +- Email: [hefangsheng@gmail.com](mailto:hefangsheng@gmail.com) +- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) +- 官网: [u-claw.org](https://u-claw.org) + +### FAQ + +**Q: 需要翻墙吗?** +不需要。安装和运行全程使用国内镜像,国产模型 API 直连。 + +**Q: U 盘需要多大?** +4GB+(完整约 2.3GB)。 + +**Q: 能分发吗?** +MIT 协议,随便复制分发。 + +**Q: Mac 提示"未验证的开发者"?** +右键脚本 → 打开。 + +**Q: setup.bat / setup.sh 执行失败,提示模块找不到?** +通常是 npm install 过程中网络中断导致 `node_modules` 不完整。解决步骤: +1. 删除不完整的依赖:`rmdir /s /q portable\app\core\node_modules`(Windows)或 `rm -rf portable/app/core/node_modules`(Mac) +2. 切换淘宝镜像重新安装:`cd portable/app/core && npm install --registry=https://registry.npmmirror.com` + +**Q: 系统已有 Node.js v24,安装失败?** +Node.js v24 是最新开发版,部分依赖尚不兼容。需要 **v20 或 v22 LTS**。删除已下载的 runtime 目录后重新运行 setup,它会自动下载内置的 Node v22: +```bash +# Windows +rmdir /s /q portable\app\runtime\node-win-x64 +setup.bat + +# Mac +rm -rf portable/app/runtime/node-mac-arm64 +bash setup.sh +``` + +**Q: Mac 上提示 `.toSorted is not a function`?** +系统旧版 Node.js 被检测到并跳过了内置版本下载,但旧版 Node 不支持 `.toSorted()`(需要 v20+)。删除 runtime 目录让脚本重新下载内置 Node v22: +```bash +rm -rf portable/app/runtime/node-mac-arm64 +bash setup.sh +``` + +**Q: 如何同时配置多个 AI 模型并切换?** +支持同时配置多个 provider!打开 `Config.html` → 在 Providers 区域点击「添加」,逐个填入各模型的 API Key 和地址(如 DeepSeek、Kimi、通义等)→ 保存后,在聊天界面左上角下拉菜单随时切换。配置持久保存在 U 盘上。 + +**Q: U 盘安装后无法创建文件 / 写入失败?** +两种可能:① U 盘侧面有物理写保护开关,拨到解锁位置;② U 盘格式不兼容,建议格式化为 **exFAT**(Mac/Windows/Linux 三端均支持读写)。 + +**Q: 从 Ubuntu 向 U 盘复制时符号链接丢失?** +`node_modules/.bin/` 下有大量符号链接,FAT32/exFAT 在直接 `cp -R` 时会跳过。用 `rsync -aL` 可将符号链接展开为真实文件: +```bash +rsync -aL --progress portable/ /media/YOUR_USB/U-Claw/ +``` + +**Q: QQbot 报错 `Unknown channel: qqbot`?** +Bundle 里的 `@sliverp/qqbot` 是未编译的 TypeScript 源码,需要先编译: +```bash +cd portable/app/core/node_modules/@sliverp/qqbot +npm install && npm run build +``` +正式 Release 包已修复此问题,建议从 [Releases](https://gitea.fanghe.it.com/zhenghy/u-claw/releases) 下载最新版。 + +### 联系 & 合作 + +微信二维码 — 贺去病 ai 工作室 + +- 微信: hecare888(或扫右侧二维码) +- Telegram: [@dsds8848](https://t.me/dsds8848) +- Twitter/X: [@Bitplus888](https://x.com/Bitplus888) +- Email: [hefangsheng@gmail.com](mailto:hefangsheng@gmail.com) +- GitHub: [@dongsheng123132](https://github.com/dongsheng123132) +- 官网: [u-claw.org](https://u-claw.org) + +**🤝 招募代理 / 带货合作** + +虾盘 3.0 体验极佳,退货率极低,售后由我们负责——你只管卖货: + +- **抖店 / 直播带货**:提供最高佣金比例,产品已在多个直播间验证转化 +- **代理分销**:买断或按单分润均可谈,支持定制版本 +- **技术合作**:有开发能力者欢迎深度合作 +- **👑 U-King 装机管家分销(新)**:[U-King](https://www.u-king.org) 软件本身免费送客户,客户按用量给 AI 模型 API 充值,你拿**持续分润**——不压货、零售后(我们负责),赚的是长期流水。适合装机店、AI 培训、社群主理人 + +有意向请微信联系(备注「代理合作」优先处理)。 + +--- + + + + +--- + +

English · 中文

diff --git a/SECURITY.md b/SECURITY.md index 45fa515..9dba632 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,7 +9,7 @@ 如果你发现了 U-Claw 的安全问题,请通过以下任一渠道私下联系: - 邮件:`hefangsheng@u-claw.org`(建议附 PoC、影响范围、复现步骤) -- GitHub 私密漏洞报告:在 [u-claw 仓库](https://github.com/dongsheng123132/u-claw) 的 Security 标签页 → "Report a vulnerability" +- GitHub 私密漏洞报告:在 [u-claw 仓库](https://gitea.fanghe.it.com/zhenghy/u-claw) 的 Security 标签页 → "Report a vulnerability" 我们会在 **3 个工作日内** 确认收到,并在 **14 天内** 给出初步评估。请允许我们在公开披露前修复问题。 diff --git a/bootable/2-download-iso.ps1 b/bootable/2-download-iso.ps1 index c456962..6b0d42a 100644 --- a/bootable/2-download-iso.ps1 +++ b/bootable/2-download-iso.ps1 @@ -17,11 +17,8 @@ $SHA256Expected = "3a4c9877b483ab46d7c3fbe165a0db275e1ae3cfe56a5657e5a47c2f99a99 $CacheDir = Join-Path $PSScriptRoot ".download-cache" $ISOPath = Join-Path $CacheDir $ISOName -# Mirror list (China mirrors first) +# Mirror list (official source first) $Mirrors = @( - "https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/24.04.4/$ISOName", - "https://mirrors.aliyun.com/ubuntu-releases/24.04.4/$ISOName", - "https://mirrors.ustc.edu.cn/ubuntu-releases/24.04.4/$ISOName", "https://releases.ubuntu.com/24.04.4/$ISOName" ) diff --git a/bootable/IMPROVEMENTS_SUMMARY.md b/bootable/IMPROVEMENTS_SUMMARY.md index b9ca6e4..f992310 100644 --- a/bootable/IMPROVEMENTS_SUMMARY.md +++ b/bootable/IMPROVEMENTS_SUMMARY.md @@ -206,7 +206,7 @@ bash /opt/u-claw/test-installation.sh ## 贡献与反馈 欢迎通过以下渠道提供反馈: -- GitHub Issues: https://github.com/dongsheng123132/u-claw/issues +- GitHub Issues: https://gitea.fanghe.it.com/zhenghy/u-claw/issues - 微信: hecare888 - 邮件: [项目维护者] diff --git a/bootable/README.md b/bootable/README.md index 531e0ba..86affe4 100644 --- a/bootable/README.md +++ b/bootable/README.md @@ -11,7 +11,7 @@ - 不依赖仓库内 `portable/`、`u-claw-app/`、`website/` 中的任何文件 - 所有脚本内部硬编码了 URL 和路径,完全自包含 - 出问题只影响 `bootable/` 自身,不会波及其他模块 -- 同时维护了一份**独立仓库**:[u-claw-linux](https://github.com/dongsheng123132/u-claw-linux),内容一致 +- 同时维护了一份**独立仓库**:[u-claw-linux](https://gitea.fanghe.it.com/zhenghy/u-claw-linux),内容一致 ## 这是什么 diff --git a/bootable/TROUBLESHOOTING.md b/bootable/TROUBLESHOOTING.md index d9cb00c..e1a200b 100644 --- a/bootable/TROUBLESHOOTING.md +++ b/bootable/TROUBLESHOOTING.md @@ -203,7 +203,7 @@ du -sh /opt/u-claw/* - 重新运行所有4个PowerShell脚本 3. **寻求帮助**: - - GitHub Issues: https://github.com/dongsheng123132/u-claw/issues + - GitHub Issues: https://gitea.fanghe.it.com/zhenghy/u-claw/issues - 微信: hecare888 ## 性能优化建议 diff --git a/bootable/linux-setup/setup-openclaw.sh b/bootable/linux-setup/setup-openclaw.sh index 1212ad6..e9d6269 100644 --- a/bootable/linux-setup/setup-openclaw.sh +++ b/bootable/linux-setup/setup-openclaw.sh @@ -7,10 +7,10 @@ set -euo pipefail # ── All constants defined here (independent of any other project files) ── -NODE_VERSION="v22.16.0" -NODE_MIRROR="https://npmmirror.com/mirrors/node" +NODE_VERSION="v22.22.1" +NODE_MIRROR="https://nodejs.org/dist" NODE_OFFICIAL="https://nodejs.org/dist" -NPM_MIRROR="https://registry.npmmirror.com" +NPM_MIRROR="https://registry.npmjs.org" INSTALL_DIR="/opt/u-claw" NODE_ARCHIVE="node-${NODE_VERSION}-linux-x64.tar.xz" diff --git a/bootable/linux-setup/test-installation.sh b/bootable/linux-setup/test-installation.sh index 39377cd..85da277 100755 --- a/bootable/linux-setup/test-installation.sh +++ b/bootable/linux-setup/test-installation.sh @@ -59,8 +59,8 @@ if [ -x "$NODE_BIN" ]; then NODE_VERSION=$("$NODE_BIN" --version 2>/dev/null || echo "") echo -e "✓ Node.js版本: ${GREEN}$NODE_VERSION${NC}" - if [ "$NODE_VERSION" != "v22.14.0" ]; then - warn "Node.js版本" "Expected v22.14.0, found $NODE_VERSION" + if [ "$NODE_VERSION" != "v22.22.1" ]; then + warn "Node.js版本" "Expected v22.22.1, found $NODE_VERSION" fi else echo -e "${RED}✗ Node.js未找到或不可执行${NC}" @@ -191,7 +191,7 @@ if [ $ERRORS -gt 0 ]; then if [ ! -d "$INSTALL_DIR/core/node_modules/openclaw" ]; then echo " 重新安装OpenClaw..." cd "$INSTALL_DIR/core" - sudo npm install --registry=https://registry.npmmirror.com openclaw@latest 2>/dev/null || true + sudo npm install --registry=https://registry.npmjs.org openclaw@latest 2>/dev/null || true fi echo "" diff --git a/install/README.md b/install/README.md index 4b429e8..6fe944a 100644 --- a/install/README.md +++ b/install/README.md @@ -99,7 +99,7 @@ powershell -ExecutionPolicy Bypass -File install\install.ps1 ## 技术细节 - **Node.js**: 只装到 `~/.uclaw/runtime/`,不动系统 Node;系统已有 v20+ 则复用 -- **镜像**: Mac/Linux 全走 `npmmirror.com`(Node 二进制 + npm 包);Windows bundle 下载依次尝试 ghfast.top → ghproxy.net → gh.idayer.com → 直连,国内无需翻墙 +- **下载源**: Node 二进制走 `nodejs.org`,npm 包走 `registry.npmjs.org`;Windows bundle 直连 GitHub Releases - **Windows 编码**: `chcp 65001` + UTF8 输出确保中文显示 - **管道模式**: `curl | bash` 时自动跳过交互,使用默认配置 - **卸载**: `rm -rf ~/.uclaw` (Mac/Linux) 或删除 `%USERPROFILE%\.uclaw` (Windows) diff --git a/install/install.ps1 b/install/install.ps1 index c8fd851..aaf1e29 100644 --- a/install/install.ps1 +++ b/install/install.ps1 @@ -22,9 +22,16 @@ $RUNTIME_DIR = "$UCLAW_DIR\runtime" $CORE_DIR = "$UCLAW_DIR\core" $DATA_DIR = "$UCLAW_DIR\data" $CONFIG_PATH = "$DATA_DIR\.openclaw\openclaw.json" -$NODE_VERSION = "v22.16.0" -$MIRROR = "https://registry.npmmirror.com" -$NODE_MIRROR = "https://npmmirror.com/mirrors/node" +$NODE_VERSION = "v22.22.1" +$MIRROR = "https://registry.npmjs.org" +$NODE_MIRROR = "https://nodejs.org/dist" +$OPENCLAW_VERSION = "2026.7.1-2" + +# Skills: content lives in skills/, described by skills/manifest.json. +# UCLAW_REF pins which revision irm|iex pulls skill content from. +$UCLAW_LOCALE = if ($env:UCLAW_LOCALE) { $env:UCLAW_LOCALE } else { "en" } +$UCLAW_REF = if ($env:UCLAW_REF) { $env:UCLAW_REF } else { "main" } +$SKILL_INSTALLER_URL = "https://gitea.fanghe.it.com/zhenghy/u-claw/raw/branch/$UCLAW_REF/lib/install-skills.mjs" # ---- Color helpers ---- function Write-Green($msg) { Write-Host $msg -ForegroundColor Green } @@ -170,11 +177,8 @@ if (Test-Path "$CORE_DIR\node_modules\openclaw") { Write-Green " [OK] OpenClaw already installed, skip" } else { Write-Cyan " Downloading pre-bundled package (no npm install needed)..." - $BUNDLE_GITHUB_URL = "https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip" + $BUNDLE_GITHUB_URL = "https://gitea.fanghe.it.com/zhenghy/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip" $BUNDLE_MIRRORS = @( - "https://ghfast.top/https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip", - "https://ghproxy.net/https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip", - "https://gh.idayer.com/https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip", $BUNDLE_GITHUB_URL ) $bundleZip = "$env:TEMP\openclaw-bundle.zip" @@ -205,8 +209,6 @@ if (Test-Path "$CORE_DIR\node_modules\openclaw") { if (-not $downloaded) { Write-Host " Trying curl fallback..." -ForegroundColor DarkGray $curlMirrors = @( - "https://ghfast.top/https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip", - "https://ghproxy.net/https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip", $BUNDLE_GITHUB_URL ) foreach ($curlUrl in $curlMirrors) { @@ -226,6 +228,32 @@ if (Test-Path "$CORE_DIR\node_modules\openclaw") { exit 1 } + # Integrity check. Until this landed the installer only checked that the + # download was larger than 1MB, then extracted and ran it -- the same + # "fetch and execute, unverified" shape we warn about elsewhere. + # The publisher writes .sha256 next to the bundle; see release.yml. + $expectedHash = $null + try { + $hashBody = (Invoke-WebRequest -Uri "$BUNDLE_GITHUB_URL.sha256" -UseBasicParsing -TimeoutSec 30).Content + $expectedHash = ($hashBody -split '\s+')[0].Trim().ToLower() + } catch { + $expectedHash = $null + } + + if ($expectedHash) { + $actualHash = (Get-FileHash -Path $bundleZip -Algorithm SHA256).Hash.ToLower() + if ($actualHash -ne $expectedHash) { + Remove-Item -Force $bundleZip -ErrorAction SilentlyContinue + Write-Red " [FAIL] The downloaded file does not match its published checksum." + Write-Yellow " It was damaged in transit, or it is not the file we published." + Write-Yellow " Nothing was installed. Try again on a different network." + exit 1 + } + Write-Green " [OK] Checksum verified" + } else { + Write-Yellow " [!] No published checksum found - integrity was not verified." + } + Write-Host " Extracting..." -ForegroundColor Cyan $tempExtract = "$env:TEMP\openclaw-bundle-extract" if (Test-Path $tempExtract) { Remove-Item -Recurse -Force $tempExtract } @@ -254,213 +282,36 @@ if (Test-Path "$CORE_DIR\node_modules\@sliverp\qqbot") { Write-Host "" # ============================================================ -# Step 4: China-optimized skills (10 skills) +# Step 4: Install skills from the manifest # ============================================================ -Write-Host " [3/6] Install China skills (10) ..." -ForegroundColor White +# Skill content lives in skills/ and is described by skills/manifest.json. +# This script carries none of it, which is what keeps the shell and PowerShell +# installers identical (tests/skills-manifest.test.mjs enforces that) and keeps +# non-ASCII bytes out of the launchers. +Write-Host " [3/6] Installing skills ..." -ForegroundColor White $SKILLS_TARGET = "$CORE_DIR\node_modules\openclaw\skills" if (-not (Test-Path $SKILLS_TARGET)) { New-Item -ItemType Directory -Force -Path $SKILLS_TARGET | Out-Null } -$skillCount = 0 - -$skills = @{ - "bilibili-helper" = @' ---- -name: bilibili-helper -description: "Bilibili content helper - video title, tags, cover design, category selection" -metadata: { "openclaw": { "emoji": "TV" } } ---- - -# Bilibili Content Helper - -Optimize video titles, descriptions, tags and covers for better recommendations on Bilibili. - -## Title formulas - -1. Question: "Why XX? You'll understand after watching" -2. Tutorial: "XX Tutorial | Step by step from scratch" -3. Review: "Spent XX yuan on XX, is it worth it?" -4. Challenge: "Challenge XX days using only XX" -5. Ranking: "Top 10 XX of the year" -'@ - - "china-search" = @' ---- -name: china-search -description: "China search engines - Baidu, Sogou, Bing China search" -metadata: { "openclaw": { "emoji": "search" } } ---- - -# China Search Engine Helper - -Search via Baidu, Sogou, Bing China using curl. - -## Commands - -```bash -curl -s -L "https://www.baidu.com/s?wd=keyword" -H "User-Agent: Mozilla/5.0" -curl -s -L "https://weixin.sogou.com/weixin?query=keyword" -H "User-Agent: Mozilla/5.0" -curl -s -L "https://cn.bing.com/search?q=keyword" -H "User-Agent: Mozilla/5.0" -``` -'@ - - "china-translate" = @' ---- -name: china-translate -description: "CN-EN translation - tech docs, UI localization, cultural adaptation" -metadata: { "openclaw": { "emoji": "globe" } } ---- - -# CN-EN Translation Helper - -Professional Chinese-English bidirectional translation for tech docs and product localization. - -## Common terms - -| English | Chinese | -|---------|---------| -| Deploy | Bu Shu | -| Repository | Cang Ku | -| Container | Rong Qi | -| Middleware | Zhong Jian Jian | -| Token | Token / Ling Pai | -| Prompt | Ti Shi Ci | -'@ - - "china-weather" = @' ---- -name: china-weather -description: "China city weather query - supports Chinese city names, wttr.in API" -metadata: { "openclaw": { "emoji": "sun" } } ---- - -# China Weather Query - -```bash -curl -s "wttr.in/Shenzhen?lang=zh" -curl -s "wttr.in/Beijing?format=j1" -``` -'@ - - "deepseek-helper" = @' ---- -name: deepseek-helper -description: "DeepSeek API helper - model selection, API guide, pricing info" -metadata: { "openclaw": { "emoji": "robot" } } ---- - -# DeepSeek API Helper - -## Models - -| Model | Use case | Context | -|-------|----------|---------| -| 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 -'@ - - "douyin-script" = @' ---- -name: douyin-script -description: "Douyin/Kuaishou short video script - hook, structure, hashtag strategy" -metadata: { "openclaw": { "emoji": "video" } } ---- - -# Douyin/Kuaishou Script Helper - -## First 3-second Hook formulas - -1. Counter-intuitive: "What you've been doing is actually wrong" -2. Number shock: "Only 100 yuan but better than 1000 yuan" -3. Suspense: "Guess what this is for?" -4. Emotional: "Workers fell silent after watching..." -5. Result first: "The final result is amazing!" - -## Hashtags: large + medium + small topics, 5-8 total -## Best time: 7-9am, 12-2pm, 6-10pm -'@ - - "wechat-article" = @' ---- -name: wechat-article -description: "WeChat article writing - structure, formatting, conversion optimization" -metadata: { "openclaw": { "emoji": "green" } } ---- - -# WeChat Article Writing Helper - -## Formatting rules - -- Body font 15-16px, line height 1.75-2x -- Body color #3f3f3f, accent #007AFF -- 3-5 lines per paragraph, 1 image per 300 chars -- Title under 30 chars, first 15 chars must catch attention -'@ - - "weibo-poster" = @' ---- -name: weibo-poster -description: "Weibo content creation - 140-char optimization, trending topics, images" -metadata: { "openclaw": { "emoji": "red" } } ---- - -# Weibo Content Helper - -## 140-char tips: Write then trim, one point per post, end with golden quote -## Images: 1 for highlight / 3 for comparison / 6 for narrative / 9 for grid -## Timing: Weekday lunch + after work, Weekend morning + evening -'@ - - "xiaohongshu-writer" = @' ---- -name: xiaohongshu-writer -description: "Xiaohongshu note writer - title optimization, emoji strategy, hashtags" -metadata: { "openclaw": { "emoji": "book" } } ---- - -# Xiaohongshu Note Writer - -## Title formulas - -1. Numbers: "5 ways / 10 types / under 100 yuan" -2. Contrast: "3K salary vs 30K salary" -3. Review: "Personally tested, really works!" -4. Collection: "XX Collection | All in one post" - -## Tips: Max 3 lines per paragraph, 1-2 emoji per paragraph, 3-8 hashtags -'@ - - "zhihu-writer" = @' ---- -name: zhihu-writer -description: "Zhihu answer/article writing - structure, professional tone, citations" -metadata: { "openclaw": { "emoji": "pen" } } ---- - -# Zhihu Writing Helper - -## Answer structure: Conclusion first -> Point-by-point -> Summary -## Style: Confident not arrogant, professional but accessible -## Quality: 500-3000 chars, original, reply to comments, focus on 2-3 topics -'@ -} - -foreach ($skillName in $skills.Keys) { - $skillDir = "$SKILLS_TARGET\$skillName" - if (-not (Test-Path $skillDir)) { - New-Item -ItemType Directory -Force -Path $skillDir | Out-Null - [IO.File]::WriteAllText("$skillDir\SKILL.md", $skills[$skillName], (New-Object System.Text.UTF8Encoding $false)) - $skillCount++ +$skillInstaller = Join-Path $PSScriptRoot "..\lib\install-skills.mjs" +$skillTemp = $null +if (-not (Test-Path $skillInstaller)) { + # irm | iex has no checkout: fetch the installer, then let it fetch content. + $skillTemp = Join-Path $env:TEMP "uclaw-install-skills.mjs" + try { + Invoke-WebRequest -Uri $SKILL_INSTALLER_URL -OutFile $skillTemp -UseBasicParsing -TimeoutSec 60 + $skillInstaller = $skillTemp + } catch { + Write-Host " [!] Could not download the skill installer - skipping skills." -ForegroundColor Yellow + Write-Host " You can add them later from the Skill Hub." -ForegroundColor DarkGray + $skillInstaller = $null } } -Write-Green " [OK] China skills installed (+$skillCount)" +if ($skillInstaller) { + & $INSTALL_NODE $skillInstaller --target $SKILLS_TARGET --locale $UCLAW_LOCALE --ref $UCLAW_REF + if ($skillTemp) { Remove-Item -Force $skillTemp -ErrorAction SilentlyContinue } +} Write-Host "" # ============================================================ diff --git a/install/install.sh b/install/install.sh old mode 100755 new mode 100644 index 5d31e1e..a7edcae --- a/install/install.sh +++ b/install/install.sh @@ -25,9 +25,17 @@ RUNTIME_DIR="$UCLAW_DIR/runtime" CORE_DIR="$UCLAW_DIR/core" DATA_DIR="$UCLAW_DIR/data" CONFIG_PATH="$DATA_DIR/.openclaw/openclaw.json" -NODE_VERSION="v22.16.0" -MIRROR="https://registry.npmmirror.com" -NODE_MIRROR="https://npmmirror.com/mirrors/node" +NODE_VERSION="v22.22.1" +MIRROR="https://registry.npmjs.org" +NODE_MIRROR="https://nodejs.org/dist" +OPENCLAW_VERSION="2026.7.1-2" + +# Skills: content lives in skills/, described by skills/manifest.json. +# UCLAW_REF pins which revision curl|bash pulls skill content from. +UCLAW_LOCALE="${UCLAW_LOCALE:-en}" +UCLAW_REF="${UCLAW_REF:-main}" +SKILL_INSTALLER_URL="https://gitea.fanghe.it.com/zhenghy/u-claw/raw/branch/$UCLAW_REF/lib/install-skills.mjs" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd || echo "")" # ============================================================ # Step 1: Banner + 系统检测 @@ -37,8 +45,8 @@ echo "" echo -e "${CYAN}${BOLD}" cat << 'BANNER' ╔══════════════════════════════════════════╗ - ║ 🦞 U-Claw 一键安装 ║ - ║ 让 AI 助手一行命令装好 ║ + ║ U-Claw installer ║ + ║ One command. One AI assistant. ║ ╚══════════════════════════════════════════╝ BANNER echo -e "${NC}" @@ -51,46 +59,46 @@ if [ "$OS" = "Darwin" ]; then if [ "$ARCH" = "arm64" ]; then PLATFORM="darwin-arm64" NODE_DIR="node-mac-arm64" - echo -e " 系统: ${GREEN}macOS Apple Silicon (M 系列) ✓${NC}" + echo -e " System: ${GREEN}macOS Apple Silicon ✓${NC}" else PLATFORM="darwin-x64" NODE_DIR="node-mac-x64" - echo -e " 系统: ${GREEN}macOS Intel ✓${NC}" + echo -e " System: ${GREEN}macOS Intel ✓${NC}" fi elif [ "$OS" = "Linux" ]; then if [ "$ARCH" = "x86_64" ]; then PLATFORM="linux-x64" NODE_DIR="node-linux-x64" - echo -e " 系统: ${GREEN}Linux x64 ✓${NC}" + echo -e " System: ${GREEN}Linux x64 ✓${NC}" elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then PLATFORM="linux-arm64" NODE_DIR="node-linux-arm64" - echo -e " 系统: ${GREEN}Linux ARM64 ✓${NC}" + echo -e " System: ${GREEN}Linux ARM64 ✓${NC}" else - echo -e " ${RED}不支持的架构: $ARCH${NC}" + echo -e " ${RED}U-Claw does not have a build for this processor ($ARCH).${NC}" exit 1 fi else - echo -e " ${RED}不支持的系统: $OS${NC}" - echo -e " ${YELLOW}Windows 请使用 PowerShell: irm https://u-claw.org/install.ps1 | iex${NC}" + echo -e " ${RED}U-Claw does not have a build for this operating system ($OS).${NC}" + echo -e " ${YELLOW}On Windows, run this in PowerShell instead: irm https://u-claw.org/install.ps1 | iex${NC}" exit 1 fi -echo -e " 安装目录: ${CYAN}$UCLAW_DIR${NC}" +echo -e " Installing to: ${CYAN}$UCLAW_DIR${NC}" echo "" # 检查已有安装 if [ -d "$UCLAW_DIR/core/node_modules/openclaw" ]; then - echo -e " ${YELLOW}检测到已有安装: $UCLAW_DIR${NC}" + echo -e " ${YELLOW}U-Claw is already installed at $UCLAW_DIR${NC}" if [ -t 0 ]; then - read -p " 覆盖安装?(y/n) [y]: " -n 1 OVERWRITE + read -p " Reinstall over it? (y/n) [y]: " -n 1 OVERWRITE echo "" if [ "$OVERWRITE" = "n" ] || [ "$OVERWRITE" = "N" ]; then - echo -e " ${DIM}已取消${NC}" + echo -e " ${DIM}Cancelled.${NC}" exit 0 fi else - echo -e " ${CYAN}管道模式,自动覆盖安装${NC}" + echo -e " ${CYAN}Running non-interactively — reinstalling.${NC}" fi echo "" fi @@ -101,7 +109,7 @@ mkdir -p "$RUNTIME_DIR" "$CORE_DIR" "$DATA_DIR/.openclaw" "$DATA_DIR/memory" "$D # ============================================================ # Step 2: Node.js v22 安装 # ============================================================ -echo -e " ${BOLD}[1/7] 安装 Node.js $NODE_VERSION ...${NC}" +echo -e " ${BOLD}[1/7] Installing Node.js $NODE_VERSION${NC}" NODE_INSTALL_DIR="$RUNTIME_DIR/$NODE_DIR" INSTALL_NODE="" @@ -113,7 +121,7 @@ if command -v node >/dev/null 2>&1; then SYS_VER=$(node --version) MAJOR=$(echo "$SYS_VER" | sed 's/v//' | cut -d. -f1) if [ "$MAJOR" -ge 20 ] 2>/dev/null; then - echo -e " ${GREEN}✓${NC} 系统已有 Node.js $SYS_VER,复用" + echo -e " ${GREEN}✓${NC} Using the Node.js already on this machine ($SYS_VER)" INSTALL_NODE="$(which node)" INSTALL_NPM="$(which npm)" USE_SYSTEM_NODE=true @@ -122,11 +130,11 @@ fi if [ "$USE_SYSTEM_NODE" = "false" ]; then if [ -f "$NODE_INSTALL_DIR/bin/node" ]; then - echo -e " ${GREEN}✓${NC} Node.js 已存在,跳过下载" + echo -e " ${GREEN}✓${NC} Node.js already downloaded" INSTALL_NODE="$NODE_INSTALL_DIR/bin/node" INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm-cli.js" else - echo -e " ${CYAN}↓${NC} 从国内镜像下载 Node.js $NODE_VERSION ($PLATFORM)..." + echo -e " ${CYAN}↓${NC} Downloading Node.js $NODE_VERSION ($PLATFORM)" TARBALL="node-${NODE_VERSION}-${PLATFORM}.tar.gz" URL="${NODE_MIRROR}/${NODE_VERSION}/${TARBALL}" @@ -136,7 +144,7 @@ if [ "$USE_SYSTEM_NODE" = "false" ]; then elif command -v wget >/dev/null 2>&1; then wget -q --show-progress "$URL" -O "/tmp/$TARBALL" else - echo -e " ${RED}✗ 未找到 curl 或 wget,请先安装${NC}" + echo -e " ${RED}✗ Neither curl nor wget is available.${NC}\n Install one of them, then run this again." exit 1 fi @@ -145,11 +153,11 @@ if [ "$USE_SYSTEM_NODE" = "false" ]; then chmod +x "$NODE_INSTALL_DIR/bin/node" if [ -f "$NODE_INSTALL_DIR/bin/node" ]; then - echo -e " ${GREEN}✓${NC} Node.js 安装完成" + echo -e " ${GREEN}✓${NC} Node.js installed" INSTALL_NODE="$NODE_INSTALL_DIR/bin/node" INSTALL_NPM="$NODE_INSTALL_DIR/lib/node_modules/npm/bin/npm-cli.js" else - echo -e " ${RED}✗ Node.js 下载失败${NC}" + echo -e " ${RED}✗ The Node.js download did not finish.${NC}\n Usually a dropped connection. Check your network and run this again." exit 1 fi fi @@ -165,18 +173,25 @@ run_npm() { fi } +run_node() { + if [ "$USE_SYSTEM_NODE" = "true" ]; then + node "$@" + else + "$INSTALL_NODE" "$@" + fi +} + echo "" # ============================================================ # Step 3: OpenClaw 安装 # ============================================================ -echo -e " ${BOLD}[2/7] 安装 OpenClaw ...${NC}" +echo -e " ${BOLD}[2/7] Installing OpenClaw${NC}" if [ -d "$CORE_DIR/node_modules/openclaw" ]; then - echo -e " ${GREEN}✓${NC} OpenClaw 已安装,跳过" + echo -e " ${GREEN}✓${NC} OpenClaw already installed" else if [ ! -f "$CORE_DIR/package.json" ]; then - OPENCLAW_VERSION="2026.4.29" cat > "$CORE_DIR/package.json" << PKGJSON { "name": "u-claw-core", @@ -189,14 +204,14 @@ else PKGJSON fi - echo -e " ${CYAN}↓${NC} 从国内镜像安装..." + echo -e " ${CYAN}↓${NC} Downloading from the npm registry" NPM_LOG=$(mktemp /tmp/uclaw-npm.XXXXXX.log) if run_npm install --prefix "$CORE_DIR" --registry="$MIRROR" >"$NPM_LOG" 2>&1; then tail -5 "$NPM_LOG" rm -f "$NPM_LOG" - echo -e " ${GREEN}✓${NC} OpenClaw 安装完成" + echo -e " ${GREEN}✓${NC} OpenClaw installed" else - echo -e " ${RED}✗ OpenClaw 安装失败,完整日志见 $NPM_LOG${NC}" + echo -e " ${RED}✗ OpenClaw could not be installed. Full log: $NPM_LOG${NC}" tail -20 "$NPM_LOG" exit 1 fi @@ -207,684 +222,131 @@ echo "" # ============================================================ # Step 4: QQ 插件(非致命) # ============================================================ -echo -e " ${BOLD}[3/7] 安装 QQ 插件 ...${NC}" +echo -e " ${BOLD}[3/7] Installing the QQ plugin${NC}" if [ -d "$CORE_DIR/node_modules/@sliverp/qqbot" ]; then - echo -e " ${GREEN}✓${NC} QQ 插件已安装,跳过" + echo -e " ${GREEN}✓${NC} QQ plugin already installed" else - echo -e " ${CYAN}↓${NC} 安装 QQ 插件..." + echo -e " ${CYAN}↓${NC} Installing the QQ plugin" run_npm install @sliverp/qqbot@latest --prefix "$CORE_DIR" --registry="$MIRROR" 2>/dev/null || { - echo -e " ${YELLOW}⚠${NC} QQ 插件安装失败(不影响主功能)" + echo -e " ${YELLOW}⚠${NC} QQ plugin failed to install. Everything else still works." } if [ -d "$CORE_DIR/node_modules/@sliverp/qqbot" ]; then - echo -e " ${GREEN}✓${NC} QQ 插件安装完成" + echo -e " ${GREEN}✓${NC} QQ plugin installed" fi fi echo "" # ============================================================ -# Step 5: 写入 10 个中国技能 +# Step 5: Install skills from the manifest # ============================================================ -echo -e " ${BOLD}[4/7] 安装中国本地化技能 (10个) ...${NC}" +# Skill content lives in skills/ and is described by skills/manifest.json. +# This script carries none of it, which is what keeps the shell and PowerShell +# installers identical (tests/skills-manifest.test.mjs enforces that). +echo -e " ${BOLD}[4/7] Installing skills ...${NC}" SKILLS_TARGET="$CORE_DIR/node_modules/openclaw/skills" -if [ ! -d "$SKILLS_TARGET" ]; then - mkdir -p "$SKILLS_TARGET" +mkdir -p "$SKILLS_TARGET" + +SKILL_INSTALLER="$SCRIPT_DIR/../lib/install-skills.mjs" +if [ -f "$SKILL_INSTALLER" ]; then + run_node "$SKILL_INSTALLER" --target "$SKILLS_TARGET" --locale "$UCLAW_LOCALE" +else + # curl | bash has no checkout: fetch the installer, then let it fetch content. + SKILL_TMP=$(mktemp "${TMPDIR:-/tmp}/uclaw-skills.XXXXXX.mjs") + if curl -fsSL "$SKILL_INSTALLER_URL" -o "$SKILL_TMP"; then + run_node "$SKILL_TMP" --target "$SKILLS_TARGET" --locale "$UCLAW_LOCALE" --ref "$UCLAW_REF" + rm -f "$SKILL_TMP" + else + rm -f "$SKILL_TMP" + echo -e " ${RED}✗${NC} Could not download the skill installer — skipping skills." + echo -e " You can add them later from the Skill Hub." + fi fi - -SKILL_COUNT=0 - -# ---- bilibili-helper ---- -if [ ! -d "$SKILLS_TARGET/bilibili-helper" ]; then -mkdir -p "$SKILLS_TARGET/bilibili-helper" -cat > "$SKILLS_TARGET/bilibili-helper/SKILL.md" << 'SKILLEOF' ---- -name: bilibili-helper -description: "B站内容助手 - 视频标题描述优化、标签策略、封面设计建议、分区选择、评论互动" -metadata: { "openclaw": { "emoji": "📺" } } ---- - -# B站内容助手 - -帮助 UP 主优化视频标题、描述、标签和封面,提升视频在 B 站的推荐和互动表现。 - -## 功能概述 - -- **标题优化**: 符合 B 站用户口味的标题写法 -- **描述撰写**: 含时间轴、关键词、引导语的视频简介 -- **标签策略**: 精准标签 + 热门标签组合,提升推荐 -- **分区建议**: 根据内容推荐最佳投稿分区 -- **封面设计**: 封面构图、文字、配色建议 -- **评论互动**: 置顶评论话术,提升互动率 - -## 使用示例 - -### 写标题和描述 -``` -我做了一个"用AI写代码"的教程视频,帮我写标题和描述 -``` - -### 分区推荐 -``` -我的视频内容是游戏+编程结合,应该投哪个分区? -``` - -### 封面建议 -``` -视频主题是"大学生省钱攻略",帮我设计封面方案 -``` - -## 标题公式 - -1. **疑问式**: "为什么XX?看完你就懂了" -2. **教程式**: "XX教程|从零开始手把手教学" -3. **测评式**: "花了XX元买了XX,值不值?" -4. **挑战式**: "挑战XX天只用XX" -5. **盘点式**: "XX年度十大XX盘点" -6. **震惊式**: "这也太XX了吧!"(B站经典体) - -## 描述模板 - -``` -【视频简介】 -一句话概括视频内容 - -【时间轴】 -00:00 开场 -01:23 第一部分 -05:00 第二部分 -08:30 总结 - -【相关链接】 -工具/资源链接 - -【关于我】 -一句话介绍 + 更新频率 - -三连支持一下吧~ 有问题评论区见! -``` - -## 分区选择指南 - -| 内容类型 | 推荐分区 | -|---------|---------| -| 编程教程 | 科技 → 计算机技术 | -| 日常 vlog | 生活 → 日常 | -| 游戏实况 | 游戏 → 单机/网游 | -| 知识科普 | 知识 → 社科人文/科学科普 | -| 美食制作 | 生活 → 美食圈 | -| AI/数码 | 科技 → 软件应用 | - -## 标签策略 - -- **核心标签**: 精确描述视频内容(2-3个) -- **分区热门**: 当前分区下的热门标签(2-3个) -- **全站热门**: B站当前热点话题(1-2个) -- **长尾标签**: 细分领域关键词(2-3个) -- 总计 8-12 个标签效果最佳 - -## 封面设计要点 - -- **尺寸**: 16:10(推荐 1146x717) -- **文字**: 不超过 10 字,字体加粗加描边 -- **表情**: 人物表情夸张更吸引点击 -- **配色**: 高饱和度,与B站粉色/蓝色背景形成对比 -- **避免**: 过多文字、低分辨率、与内容无关的封面 -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- china-search ---- -if [ ! -d "$SKILLS_TARGET/china-search" ]; then -mkdir -p "$SKILLS_TARGET/china-search" -cat > "$SKILLS_TARGET/china-search/SKILL.md" << 'SKILLEOF' ---- -name: china-search -description: "国内搜索引擎 - 百度、搜狗、Bing中国搜索,绕过GFW限制" -metadata: { "openclaw": { "emoji": "🔍" } } ---- - -# 国内搜索引擎助手 - -在无法访问 Google 的环境下,通过 curl 调用百度、搜狗、Bing 中国等国内搜索引擎获取信息。 - -## 功能概述 - -- **百度搜索**: 中文信息最全的搜索引擎 -- **搜狗搜索**: 微信公众号文章搜索利器 -- **Bing 中国**: 国际信息 + 国内可访问 - -## 搜索命令 - -### 百度搜索 -```bash -curl -s -L "https://www.baidu.com/s?wd=关键词" \ - -H "User-Agent: Mozilla/5.0" | head -200 -``` - -### 搜狗搜索(含微信文章) -```bash -curl -s -L "https://weixin.sogou.com/weixin?query=关键词" \ - -H "User-Agent: Mozilla/5.0" -``` - -### Bing 中国搜索 -```bash -curl -s -L "https://cn.bing.com/search?q=关键词" \ - -H "User-Agent: Mozilla/5.0" -``` - -## 搜索技巧 - -| 语法 | 说明 | 示例 | -|-----|------|------| -| "" | 精确匹配 | "人工智能" | -| site: | 限定网站 | site:zhihu.com AI | -| filetype: | 限定文件类型 | filetype:pdf 机器学习 | -| - | 排除关键词 | 苹果 -手机 | -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- china-translate ---- -if [ ! -d "$SKILLS_TARGET/china-translate" ]; then -mkdir -p "$SKILLS_TARGET/china-translate" -cat > "$SKILLS_TARGET/china-translate/SKILL.md" << 'SKILLEOF' ---- -name: china-translate -description: "中英互译 + 本地化 - 技术翻译、UI本地化、文化适配、避免机翻腔" -metadata: { "openclaw": { "emoji": "🌐" } } ---- - -# 中英互译 + 本地化助手 - -专业的中英双向翻译工具,专注技术文档翻译、产品本地化和文化适配,杜绝机翻腔。 - -## 功能概述 - -- **技术翻译**: 编程/AI/互联网领域的专业术语翻译 -- **UI 本地化**: 将英文界面文案翻译为符合中文习惯的表达 -- **文化适配**: 处理中西文化差异,避免直译造成的误解 -- **去机翻腔**: 将僵硬的机器翻译改写为自然流畅的中文 - -## 常见术语对照表 - -| English | 中文(推荐) | 避免使用 | -|---------|------------|---------| -| Machine Learning | 机器学习 | 机械学习 | -| Deploy | 部署 | 配置/展开 | -| Repository | 仓库 / 代码仓库 | 存储库 | -| Pull Request | PR / 合并请求 | 拉取请求 | -| Container | 容器 | 集装箱 | -| Middleware | 中间件 | 中间软件 | -| Render | 渲染 | 呈现 | -| Token | Token / 令牌 | 代币(非区块链语境) | -| Prompt | 提示词 / Prompt | 提示语 | -| Fine-tune | 微调 | 精调 | - -## UI 本地化指南 - -- "Submit" → "提交" -- "Cancel" → "取消" -- "Get Started" → "立即开始" -- "Learn More" → "了解更多" -- "Sign Up" → "注册" -- 中文 UI 不需要句号(按钮、标签) -- 中英文之间加半角空格 -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- china-weather ---- -if [ ! -d "$SKILLS_TARGET/china-weather" ]; then -mkdir -p "$SKILLS_TARGET/china-weather" -cat > "$SKILLS_TARGET/china-weather/SKILL.md" << 'SKILLEOF' ---- -name: china-weather -description: "中国城市天气查询 - 支持中文城市名、农历日期、wttr.in接口" -metadata: { "openclaw": { "emoji": "🌤️" } } ---- - -# 中国城市天气查询 - -通过 wttr.in 查询中国各城市天气信息,支持中文城市名输入。 - -## 查询方式 - -```bash -# 基础查询(中文输出) -curl -s "wttr.in/深圳?lang=zh" - -# 精简单行格式 -curl -s "wttr.in/深圳?format=3&lang=zh" - -# JSON 格式(便于解析) -curl -s "wttr.in/深圳?format=j1" -``` - -## 使用示例 - -- 深圳今天天气怎么样? -- 明天要去杭州出差,需要带伞吗? -- 北京和上海这周末天气哪个好? - -## 注意事项 - -- wttr.in 为免费服务,偶尔可能响应较慢 -- 温度默认摄氏度,风速默认 km/h -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- deepseek-helper ---- -if [ ! -d "$SKILLS_TARGET/deepseek-helper" ]; then -mkdir -p "$SKILLS_TARGET/deepseek-helper" -cat > "$SKILLS_TARGET/deepseek-helper/SKILL.md" << 'SKILLEOF' ---- -name: deepseek-helper -description: "DeepSeek API 助手 - 编程辅助、模型选择、API调用指南、定价信息" -metadata: { "openclaw": { "emoji": "🤖" } } ---- - -# DeepSeek API 助手 - -帮助用户高效使用 DeepSeek 系列模型,包括模型选择建议、API 调用示例和定价计算。 - -## 模型对比 - -| 模型 | 适用场景 | 上下文长度 | -|------|---------|-----------| -| deepseek-v4-flash | 日常对话、文案写作、知识问答,快且便宜 | 128K | -| deepseek-v4-pro | 复杂推理、数学、代码 | 128K | - -> 注意:旧名 `deepseek-chat` / `deepseek-coder` / `deepseek-reasoner` 已被 -> api.deepseek.com 拒绝,调用会直接返回 HTTP 400。 - -## 关键提示 - -- DeepSeek API 兼容 OpenAI 格式,base_url 改为 `https://api.deepseek.com` -- 国内访问无需翻墙,延迟低 -- 支持 function calling 和 JSON mode -- API Key 申请地址: https://platform.deepseek.com -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- douyin-script ---- -if [ ! -d "$SKILLS_TARGET/douyin-script" ]; then -mkdir -p "$SKILLS_TARGET/douyin-script" -cat > "$SKILLS_TARGET/douyin-script/SKILL.md" << 'SKILLEOF' ---- -name: douyin-script -description: "抖音/快手短视频脚本 - 前3秒hook、脚本结构、热门音乐建议、话题标签策略" -metadata: { "openclaw": { "emoji": "🎬" } } ---- - -# 抖音/快手短视频脚本助手 - -帮你写出完播率高、互动强的短视频脚本。 - -## 脚本结构模板 - -### 15秒脚本 -``` -【0-3秒】Hook: 抛出反常识/痛点 -【3-10秒】核心内容: 快速讲解 -【10-15秒】CTA: 引导互动 -``` - -### 60秒脚本 -``` -【0-3秒】Hook: 强烈的情绪/悬念 -【3-15秒】背景铺垫 -【15-40秒】内容展开 -【40-50秒】反转/高潮 -【50-60秒】CTA + 话题标签 -``` - -## 前3秒 Hook 公式 - -1. **反常识**: "你一直在做的XX其实是错的" -2. **数字冲击**: "只花了100块,效果比1000块的还好" -3. **悬念提问**: "猜猜这个东西是干什么的?" -4. **情绪共鸣**: "打工人看完都沉默了..." -5. **结果前置**: "最终效果太绝了!往下看做法" - -## 话题标签策略 - -- **大话题**: #抖音热门 #今日份分享(1-2个) -- **中话题**: #健身打卡 #美食教程(2-3个) -- **小话题**: #深圳探店 #程序员日常(2-3个) - -## 发布建议 - -- **黄金时段**: 早7-9点、午12-14点、晚18-22点 -- **封面**: 竖屏 9:16,文字大且少(不超过8字) -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- wechat-article ---- -if [ ! -d "$SKILLS_TARGET/wechat-article" ]; then -mkdir -p "$SKILLS_TARGET/wechat-article" -cat > "$SKILLS_TARGET/wechat-article/SKILL.md" << 'SKILLEOF' ---- -name: wechat-article -description: "微信公众号文章写作 - 文章结构、排版规范、阅读转化优化、封面建议" -metadata: { "openclaw": { "emoji": "💚" } } ---- - -# 微信公众号文章写作助手 - -帮助运营者写出高阅读、高转发的微信公众号文章。 - -## 文章结构模板 - -``` -【标题】控制在 30 字以内,前 15 字抓眼球 -【摘要】出现在分享卡片,控制在 54 字 - -【引言】1-2 段,建立共鸣或抛出问题 - -【正文】 -## 小标题一 -内容段落...(每段 3-5 行) - -## 小标题二 -内容段落... - -【总结】回扣主题,升华观点 - -【尾部】 -觉得有收获?点个「在看」让更多人看到 -``` - -## 微信排版规范 - -- **正文字号**: 15-16px -- **行间距**: 1.75-2倍 -- **段间距**: 空一行 -- **配色**: 正文 #3f3f3f,强调 #007AFF -- **图片**: 宽度 100%,JPG,单张不超过 5MB - -## 标题技巧 - -1. **数字开头**: "3个方法/5分钟学会" -2. **疑问式**: "为什么XX?答案出乎意料" -3. **对比式**: "XX和XX的差距,在于这一点" -4. **紧迫感**: "再不XX就晚了" -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- weibo-poster ---- -if [ ! -d "$SKILLS_TARGET/weibo-poster" ]; then -mkdir -p "$SKILLS_TARGET/weibo-poster" -cat > "$SKILLS_TARGET/weibo-poster/SKILL.md" << 'SKILLEOF' ---- -name: weibo-poster -description: "微博内容创作 - 140字优化、话题热搜、@提及策略、配图描述、发布时机" -metadata: { "openclaw": { "emoji": "🔴" } } ---- - -# 微博内容创作助手 - -帮你写出高转发、高互动的微博内容。 - -## 微博内容模板 - -### 短微博(140字以内) -``` -【观点/金句】一句话表达核心观点 -【补充说明】1-2句展开 -【话题标签】#话题一# #话题二# -``` - -## 140字写作技巧 - -- **先写后删**: 先完整表达,再精简到 140 字 -- **一条一观点**: 不要在一条微博里讲太多 -- **金句收尾**: 最后一句要值得被转发 - -## 配图建议 - -- **1张图**: 重点突出,适合海报/截图 -- **3张图**: 对比/过程展示 -- **6张图**: 故事叙述 -- **9张图**: 九宫格,视觉冲击力最强 - -## 发布时间建议 - -- **工作日**: 午休 12:00-13:00、下班后 18:00-20:00 -- **周末**: 上午 10:00-11:00、晚上 20:00-22:00 -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- xiaohongshu-writer ---- -if [ ! -d "$SKILLS_TARGET/xiaohongshu-writer" ]; then -mkdir -p "$SKILLS_TARGET/xiaohongshu-writer" -cat > "$SKILLS_TARGET/xiaohongshu-writer/SKILL.md" << 'SKILLEOF' ---- -name: xiaohongshu-writer -description: "小红书笔记写作助手 - 标题优化、emoji策略、话题标签、封面文案、笔记结构" -metadata: { "openclaw": { "emoji": "📕" } } ---- - -# 小红书笔记写作助手 - -专业的小红书内容创作工具,帮你写出高互动、高收藏的爆款笔记。 - -## 笔记结构模板 - -``` -【标题】数字 + 痛点/好奇心 + emoji -例: 打工人必看!5个让老板刮目相看的汇报技巧 💼 - -【开头 Hook】1-2句直击痛点 -【正文】分点罗列,每点 2-3 行 -1️⃣ 第一点... -2️⃣ 第二点... - -【结尾 CTA】 -觉得有用就 ❤️ 收藏起来慢慢看! - -【话题标签】 -#职场干货 #汇报技巧 #打工人必看 -``` - -## 标题公式 - -1. **数字法**: "5个/10种/100元以内" + 关键词 -2. **反差法**: "月薪3千 vs 月薪3万的区别" -3. **身份法**: "作为XX人/XX年经验告诉你" -4. **测评法**: "亲测有效!" + 结果 -5. **合集法**: "XX合集|一篇搞定" - -## 写作要点 - -- 每段不超过 3 行 -- emoji 不要堆砌,每段 1-2 个 -- 话题标签 3-8 个为佳 -- 封面文案控制在 10 字以内 -- 发布时间: 早7-9点、午12-14点、晚20-22点 -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -# ---- zhihu-writer ---- -if [ ! -d "$SKILLS_TARGET/zhihu-writer" ]; then -mkdir -p "$SKILLS_TARGET/zhihu-writer" -cat > "$SKILLS_TARGET/zhihu-writer/SKILL.md" << 'SKILLEOF' ---- -name: zhihu-writer -description: "知乎回答/文章写作 - 回答结构、专业语气、引用规范、话题关联、盐值优化" -metadata: { "openclaw": { "emoji": "📝" } } ---- - -# 知乎回答/文章写作助手 - -帮助创作者写出高赞、高收藏的知乎内容。 - -## 回答结构模板 - -``` -【开头】直接回答问题 + 亮明立场 -"作为一个做了5年XX的人,我的回答是:..." - ---- - -【正文】分点论述,有理有据 -一、第一个论点 + 数据/案例 -二、第二个论点 + 个人经验 -三、第三个论点 + 行业分析 - -【总结】回扣问题,给出实操建议 -``` - -## 知乎写作风格 - -- **自信但不傲慢**: "以我的经验来看" -- **专业但易懂**: 术语需要解释 -- **有态度但包容**: 尊重不同立场 -- **真诚分享**: 多用个人经验和案例 - -## 盐值优化 - -- 回答字数建议 500-3000 字 -- 避免复制粘贴,用自己的语言 -- 回复评论,参与讨论 -- 持续在 2-3 个话题下创作 -SKILLEOF -SKILL_COUNT=$((SKILL_COUNT + 1)) -fi - -echo -e " ${GREEN}✓${NC} 中国技能安装完成 (+${SKILL_COUNT} 个)" echo "" # ============================================================ # Step 6: 交互式模型配置 # ============================================================ -echo -e " ${BOLD}[5/7] 配置 AI 模型 ...${NC}" +echo -e " ${BOLD}[5/7] Choosing a model${NC}" echo "" # 如果已有配置且包含 apiKey,跳过 if [ -f "$CONFIG_PATH" ] && grep -q '"apiKey"' "$CONFIG_PATH" 2>/dev/null; then - echo -e " ${GREEN}✓${NC} 已有模型配置,跳过" + echo -e " ${GREEN}✓${NC} A model is already configured" else # 检测是否可交互 if [ -t 0 ]; then - echo -e " 请选择 AI 模型:" + echo -e " Which model do you want to use?" echo "" - echo -e " ${BOLD}── 国内推荐(无需翻墙)──${NC}" - echo -e " ${GREEN}1)${NC} DeepSeek ⭐ 推荐,性价比最高" - echo -e " ${NC}2)${NC} Kimi/月之暗面" - echo -e " ${NC}3)${NC} 通义千问/阿里" - echo -e " ${NC}4)${NC} 智谱GLM" - echo -e " ${NC}5)${NC} MiniMax" - echo -e " ${NC}6)${NC} 豆包/火山引擎" - echo -e " ${NC}7)${NC} 硅基流动" + echo -e " ${GREEN}1)${NC} Gemini easiest to get a key for, free tier" + echo -e " ${NC}2)${NC} Claude best all-rounder" + echo -e " ${NC}3)${NC} GPT most widely used" + echo -e " ${NC}4)${NC} OpenRouter one key, many models" + echo -e " ${NC}5)${NC} SEA-LION Malay, Tamil and Singlish" + echo -e " ${NC}6)${NC} Local runs offline via Ollama" echo "" - echo -e " ${BOLD}── 海外模型 ──${NC}" - echo -e " ${NC}8)${NC} Claude ${NC}9)${NC} GPT" + echo -e " ${DIM}7) Other providers (DeepSeek, Kimi, Qwen, GLM, ...)${NC}" echo "" - echo -e " ${BOLD}── 本地 ──${NC}" - echo -e " ${NC}10)${NC} Ollama 本地模型" - echo "" - read -p " 请输入编号 [1]: " MODEL_CHOICE + read -p " Pick a number [1]: " MODEL_CHOICE MODEL_CHOICE=${MODEL_CHOICE:-1} - # 模型配置映射 + echo "" + + PROVIDER="custom" + NEED_KEY=true case $MODEL_CHOICE in 1) - MODEL_NAME="deepseek-v4-flash" - BASE_URL="https://api.deepseek.com/v1" - PROVIDER="custom" - KEY_LABEL="DeepSeek API Key" - KEY_HINT="获取地址: https://platform.deepseek.com/api_keys" - NEED_KEY=true + MODEL_NAME="gemini-2.5-flash" + BASE_URL="https://generativelanguage.googleapis.com/v1beta/openai" + KEY_LABEL="Gemini API key" + KEY_HINT="Get one at https://aistudio.google.com/apikey — sign in with Google, no card needed" ;; 2) - MODEL_NAME="moonshot-v1-auto" - BASE_URL="https://api.moonshot.cn/v1" - PROVIDER="custom" - KEY_LABEL="Moonshot API Key" - KEY_HINT="获取地址: https://platform.moonshot.cn/console/api-keys" - NEED_KEY=true + MODEL_NAME="claude-sonnet-4-20250514" + BASE_URL="https://api.anthropic.com/v1" + KEY_LABEL="Anthropic API key" + KEY_HINT="Get one at https://console.anthropic.com/settings/keys" ;; 3) - MODEL_NAME="qwen-plus" - BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1" - PROVIDER="custom" - KEY_LABEL="通义千问 API Key" - KEY_HINT="获取地址: https://dashscope.console.aliyun.com/apiKey(有免费额度)" - NEED_KEY=true + MODEL_NAME="gpt-4o" + BASE_URL="https://api.openai.com/v1" + KEY_LABEL="OpenAI API key" + KEY_HINT="Get one at https://platform.openai.com/api-keys" ;; 4) - MODEL_NAME="glm-4-plus" - BASE_URL="https://open.bigmodel.cn/api/paas/v4" - PROVIDER="custom" - KEY_LABEL="智谱 API Key" - KEY_HINT="获取地址: https://open.bigmodel.cn/usercenter/apikeys" - NEED_KEY=true + MODEL_NAME="anthropic/claude-sonnet-4" + BASE_URL="https://openrouter.ai/api/v1" + KEY_LABEL="OpenRouter API key" + KEY_HINT="Get one at https://openrouter.ai/keys" ;; 5) - MODEL_NAME="abab6.5s-chat" - BASE_URL="https://api.minimax.chat/v1" - PROVIDER="custom" - KEY_LABEL="MiniMax API Key" - KEY_HINT="获取地址: https://platform.minimaxi.com/" - NEED_KEY=true + MODEL_NAME="aisingapore/Qwen-SEA-LION-v4.5-27B-IT" + BASE_URL="https://api.sea-lion.ai/v1" + KEY_LABEL="SEA-LION API key" + KEY_HINT="Get one at https://playground.sea-lion.ai — free, but rate-limited to 10 requests a minute" ;; 6) - MODEL_NAME="doubao-pro-256k" - BASE_URL="https://ark.cn-beijing.volces.com/api/v3" - PROVIDER="custom" - KEY_LABEL="火山引擎 API Key" - KEY_HINT="获取地址: https://console.volcengine.com/ark" - NEED_KEY=true - ;; - 7) - MODEL_NAME="deepseek-ai/DeepSeek-V3" - BASE_URL="https://api.siliconflow.cn/v1" - PROVIDER="custom" - KEY_LABEL="硅基流动 API Key" - KEY_HINT="获取地址: https://cloud.siliconflow.cn/account/ak" - NEED_KEY=true - ;; - 8) - MODEL_NAME="claude-sonnet-4-20250514" - BASE_URL="" - PROVIDER="anthropic" - KEY_LABEL="Anthropic API Key" - KEY_HINT="获取地址: https://console.anthropic.com/settings/keys(需翻墙)" - NEED_KEY=true - ;; - 9) - MODEL_NAME="gpt-4o" - BASE_URL="" - PROVIDER="openai" - KEY_LABEL="OpenAI API Key" - KEY_HINT="获取地址: https://platform.openai.com/api-keys(需翻墙)" - NEED_KEY=true - ;; - 10) MODEL_NAME="llama3.2" BASE_URL="http://127.0.0.1:11434/v1" - PROVIDER="custom" KEY_LABEL="" - KEY_HINT="先安装 Ollama (https://ollama.com),然后运行: ollama run llama3.2" + KEY_HINT="Install Ollama from https://ollama.com, then run: ollama run llama3.2" NEED_KEY=false ;; + 7) + echo -e " Paste the endpoint and model for your provider." + read -p " API endpoint (e.g. https://api.example.com/v1): " BASE_URL + read -p " Model name: " MODEL_NAME + KEY_LABEL="API key" + KEY_HINT="Use the key your provider issued you" + ;; *) - echo -e " ${YELLOW}未知选项,使用默认 DeepSeek${NC}" - MODEL_NAME="deepseek-v4-flash" - BASE_URL="https://api.deepseek.com/v1" - PROVIDER="custom" - KEY_LABEL="DeepSeek API Key" - KEY_HINT="获取地址: https://platform.deepseek.com/api_keys" - NEED_KEY=true + echo -e " ${YELLOW}Not a listed option — using Gemini.${NC}" + MODEL_NAME="gemini-2.5-flash" + BASE_URL="https://generativelanguage.googleapis.com/v1beta/openai" + KEY_LABEL="Gemini API key" + KEY_HINT="Get one at https://aistudio.google.com/apikey" ;; esac @@ -895,9 +357,9 @@ else if [ "$NEED_KEY" = "true" ]; then echo -e " ${CYAN}$KEY_HINT${NC}" echo "" - read -p " 请输入 $KEY_LABEL: " API_KEY + read -p " Paste your $KEY_LABEL: " API_KEY if [ -z "$API_KEY" ]; then - echo -e " ${YELLOW}⚠ 未输入 API Key,稍后可通过 Config.html 配置${NC}" + echo -e " ${YELLOW}⚠ No key entered. You can add one later from Settings.${NC}" fi else echo -e " ${CYAN}$KEY_HINT${NC}" @@ -972,11 +434,11 @@ CFGEOF CFGEOF fi - echo -e " ${GREEN}✓${NC} 模型配置完成: $MODEL_NAME" + echo -e " ${GREEN}✓${NC} Model set: $MODEL_NAME" else # 非交互模式,写默认配置 - echo -e " ${YELLOW}⚠${NC} 管道模式,跳过模型选择" - echo -e " ${DIM}启动后用 Config.html 配置模型${NC}" + echo -e " ${YELLOW}⚠${NC} Running non-interactively — skipping model setup." + echo -e " ${DIM}Pick a model from Settings after the first launch.${NC}" if [ ! -f "$CONFIG_PATH" ]; then cat > "$CONFIG_PATH" << 'CFGEOF' { @@ -995,7 +457,7 @@ echo "" # ============================================================ # Step 7: 生成启动脚本 + 验证 + 摘要 # ============================================================ -echo -e " ${BOLD}[6/7] 生成启动脚本 ...${NC}" +echo -e " ${BOLD}[6/7] Writing the start script${NC}" # Mac 启动脚本 cat > "$UCLAW_DIR/start.command" << 'STARTEOF' @@ -1012,13 +474,13 @@ fi [ ! -f "$NODE_BIN" ] && NODE_BIN="$(which node 2>/dev/null)" if [ -z "$NODE_BIN" ] || [ ! -f "$NODE_BIN" ]; then - echo "错误: 未找到 Node.js" + echo "U-Claw cannot start: the bundled Node.js is missing."; echo "Reinstall with: curl -fsSL https://u-claw.org/install.sh | bash" exit 1 fi OPENCLAW_MJS="$DIR/core/node_modules/openclaw/openclaw.mjs" if [ ! -f "$OPENCLAW_MJS" ]; then - echo "错误: 未找到 OpenClaw" + echo "U-Claw cannot start: OpenClaw is missing."; echo "Reinstall with: curl -fsSL https://u-claw.org/install.sh | bash" exit 1 fi @@ -1030,7 +492,7 @@ export OPENCLAW_CONFIG_PATH="$DIR/data/.openclaw/openclaw.json" PORT=18789 while lsof -i :$PORT >/dev/null 2>&1; do PORT=$((PORT + 1)) - [ $PORT -gt 18799 ] && echo "没有可用端口 (18789-18799)" && exit 1 + [ $PORT -gt 18799 ] && echo "No free port between 18789 and 18799 — U-Claw may already be running." && exit 1 done cd "$DIR/core" @@ -1047,8 +509,8 @@ for i in $(seq 1 30); do done echo "" -echo " 🦞 U-Claw 正在运行: http://127.0.0.1:$PORT/#token=uclaw" -echo " 按 Ctrl+C 停止" +echo " U-Claw is running: http://127.0.0.1:$PORT/#token=uclaw" +echo " Press Ctrl+C to stop." echo "" wait $PID @@ -1078,7 +540,7 @@ export OPENCLAW_CONFIG_PATH="$DIR/data/.openclaw/openclaw.json" PORT=18789 while ss -tln | grep -q ":$PORT "; do PORT=$((PORT + 1)) - [ $PORT -gt 18799 ] && echo "没有可用端口" && exit 1 + [ $PORT -gt 18799 ] && echo "No free port — U-Claw may already be running." && exit 1 done cd "$DIR/core" @@ -1087,8 +549,8 @@ PID=$! sleep 2 echo "" -echo " 🦞 U-Claw 正在运行: http://127.0.0.1:$PORT/#token=uclaw" -echo " 按 Ctrl+C 停止" +echo " U-Claw is running: http://127.0.0.1:$PORT/#token=uclaw" +echo " Press Ctrl+C to stop." echo "" xdg-open "http://127.0.0.1:$PORT/#token=uclaw" 2>/dev/null || true @@ -1097,13 +559,13 @@ STARTEOF chmod +x "$UCLAW_DIR/start.sh" fi -echo -e " ${GREEN}✓${NC} 启动脚本已生成" +echo -e " ${GREEN}✓${NC} Start script written" echo "" # ============================================================ # 验证 # ============================================================ -echo -e " ${BOLD}[7/7] 验证安装 ...${NC}" +echo -e " ${BOLD}[7/7] Checking the install${NC}" echo "" # Node.js @@ -1116,27 +578,27 @@ fi # OpenClaw if [ -f "$CORE_DIR/node_modules/openclaw/openclaw.mjs" ]; then - echo -e " ${GREEN}[✓]${NC} OpenClaw 已安装" + echo -e " ${GREEN}[✓]${NC} OpenClaw" else echo -e " ${RED}[✗]${NC} OpenClaw" fi # QQ 插件 if [ -d "$CORE_DIR/node_modules/@sliverp/qqbot" ]; then - echo -e " ${GREEN}[✓]${NC} QQ 插件" + echo -e " ${GREEN}[✓]${NC} QQ plugin" else - echo -e " ${YELLOW}[⚠]${NC} QQ 插件(未安装,不影响主功能)" + echo -e " ${YELLOW}[⚠]${NC} QQ plugin not installed — everything else works" fi # 技能 INSTALLED_SKILLS=$(ls -d "$SKILLS_TARGET"/*/ 2>/dev/null | wc -l | tr -d ' ') -echo -e " ${GREEN}[✓]${NC} 中国技能 (${INSTALLED_SKILLS}个)" +echo -e " ${GREEN}[✓]${NC} Skills (${INSTALLED_SKILLS})" # 配置文件 if [ -f "$CONFIG_PATH" ]; then - echo -e " ${GREEN}[✓]${NC} 配置文件" + echo -e " ${GREEN}[✓]${NC} Config file" else - echo -e " ${YELLOW}[⚠]${NC} 配置文件(需启动后配置)" + echo -e " ${YELLOW}[⚠]${NC} No config yet — set it up on first launch" fi echo "" @@ -1148,23 +610,23 @@ INSTALL_SIZE=$(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1) echo -e "${GREEN}${BOLD}" echo " ╔══════════════════════════════════════════╗" -echo " ║ ✅ U-Claw 安装成功! ║" +echo " ║ U-Claw is installed ║" echo " ╚══════════════════════════════════════════╝" echo -e "${NC}" -echo -e " ${BOLD}安装位置:${NC} $UCLAW_DIR" -echo -e " ${BOLD}大小:${NC} $INSTALL_SIZE" +echo -e " ${BOLD}Location:${NC} $UCLAW_DIR" +echo -e " ${BOLD}Size:${NC} $INSTALL_SIZE" echo "" -echo -e " ${BOLD}启动方式:${NC}" +echo -e " ${BOLD}To start it:${NC}" if [ "$OS" = "Darwin" ]; then - echo -e " 双击 ${CYAN}~/.uclaw/start.command${NC}" - echo -e " 或终端: ${CYAN}bash ~/.uclaw/start.command${NC}" + echo -e " Double-click ${CYAN}~/.uclaw/start.command${NC}" + echo -e " or run ${CYAN}bash ~/.uclaw/start.command${NC}" else - echo -e " 终端: ${CYAN}bash ~/.uclaw/start.sh${NC}" + echo -e " Run ${CYAN}bash ~/.uclaw/start.sh${NC}" fi echo "" -echo -e " ${BOLD}打开后:${NC}" -echo -e " 浏览器自动打开 → 开始和 AI 对话" +echo -e " ${BOLD}Then:${NC}" +echo -e " Your browser opens and you can start talking." echo "" -echo -e " ${DIM}如需重新配置模型,编辑 ~/.uclaw/data/.openclaw/openclaw.json${NC}" -echo -e " ${DIM}卸载: rm -rf ~/.uclaw${NC}" +echo -e " ${DIM}To change model or key later, open Settings from the app.${NC}" +echo -e " ${DIM}To remove it: rm -rf ~/.uclaw${NC}" echo "" diff --git a/lib/install-skills.mjs b/lib/install-skills.mjs new file mode 100644 index 0000000..6c3b7a5 --- /dev/null +++ b/lib/install-skills.mjs @@ -0,0 +1,167 @@ +#!/usr/bin/env node +// Installs skills from skills/manifest.json into a target directory. +// +// This is the only place skill content is handled. install.sh and install.ps1 +// call it and contain no skill text of their own, which is what keeps the two +// platforms provably identical (see tests/skills-manifest.test.mjs) and keeps +// non-ASCII bytes out of .bat launchers (see tests/windows-launchers.test.mjs). +// +// node lib/install-skills.mjs --target [--locale en] [--persona general] +// [--source ] [--ref ] +// [--list] [--dry-run] [--json] + +import { mkdirSync, readFileSync, writeFileSync, existsSync, copyFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Where to fetch from lives in origin.json so a move to our own host is one +// edit. Falling back to literals keeps this working when the file is absent — +// the remote installers download this script on its own, without the repo. +const ORIGIN = (() => { + for (const dir of [join(scriptDirOf(), '..'), scriptDirOf()]) { + try { return JSON.parse(readFileSync(join(dir, 'origin.json'), 'utf8')); } catch { /* try next */ } + } + return null; +})(); + +// A template rather than a base URL: Gitea and GitHub lay raw paths out +// differently, and hardcoding either shape makes the other impossible. +const RAW_TEMPLATE = ORIGIN?.urls?.rawTemplate + ?? 'https://gitea.fanghe.it.com/zhenghy/u-claw/raw/branch/{ref}/{path}'; +const DEFAULT_REF = ORIGIN?.repo?.ref ?? 'main'; +function scriptDirOf() { return dirname(fileURLToPath(import.meta.url)); } +const scriptDir = scriptDirOf(); + +function parseArgs(argv) { + const opts = { locale: 'en', personas: [], list: false, dryRun: false, json: false, ref: DEFAULT_REF }; + for (let i = 0; i < argv.length; i++) { + const arg = argv[i]; + const next = () => { + const value = argv[++i]; + if (value === undefined) fail(`${arg} needs a value`); + return value; + }; + switch (arg) { + case '--target': opts.target = next(); break; + case '--source': opts.source = next(); break; + case '--locale': opts.locale = next(); break; + case '--persona': opts.personas.push(next()); break; + case '--ref': opts.ref = next(); break; + case '--list': opts.list = true; break; + case '--dry-run': opts.dryRun = true; break; + case '--json': opts.json = true; break; + case '--help': case '-h': usage(); process.exit(0); break; + default: fail(`unknown argument: ${arg}`); + } + } + return opts; +} + +function usage() { + process.stdout.write( + 'Usage: install-skills.mjs --target [--locale en] [--persona ]...\n' + + ' [--source ] [--ref ] [--list] [--dry-run] [--json]\n' + ); +} + +function fail(message) { + process.stderr.write(`install-skills: ${message}\n`); + process.exit(1); +} + +// Content lives in the repo checkout or on the USB. The one-line installers have +// neither, so they fall through to fetching from GitHub at a pinned ref. +function resolveLocalSource(explicit) { + const candidates = [explicit, join(scriptDir, '..', 'skills'), join(scriptDir, 'skills')]; + for (const dir of candidates) { + if (dir && existsSync(join(dir, 'manifest.json'))) return resolve(dir); + } + return null; +} + +async function fetchText(url) { + const response = await fetch(url); + if (!response.ok) throw new Error(`${response.status} ${response.statusText} for ${url}`); + return response.text(); +} + +function rawUrl(ref, path) { + return RAW_TEMPLATE.replace('{ref}', ref).replace('{path}', `skills/${path}`); +} + +function selectSkills(manifest, { locale, personas }) { + return manifest.skills + .filter((skill) => skill.status === 'shipping') + .filter((skill) => (skill.locales ?? []).includes(locale)) + // No --persona means install everything available for the locale. + .filter((skill) => personas.length === 0 || personas.some((p) => (skill.personas ?? []).includes(p))) + .sort((a, b) => a.id.localeCompare(b.id)); +} + +async function main() { + const opts = parseArgs(process.argv.slice(2)); + if (!opts.target && !opts.list) fail('--target is required (or use --list)'); + + const localSource = resolveLocalSource(opts.source); + const remote = localSource === null; + + let manifest; + try { + manifest = JSON.parse( + remote + ? await fetchText(rawUrl(opts.ref, 'manifest.json')) + : readFileSync(join(localSource, 'manifest.json'), 'utf8') + ); + } catch (error) { + fail(`could not read the skill manifest: ${error.message}`); + } + + const selected = selectSkills(manifest, opts); + + if (opts.list) { + process.stdout.write( + opts.json + ? `${JSON.stringify(selected.map((s) => s.id))}\n` + : `${selected.map((s) => s.id).join('\n')}\n` + ); + return; + } + + let installed = 0; + let skipped = 0; + const failures = []; + + for (const skill of selected) { + const destDir = join(opts.target, skill.id); + const destFile = join(destDir, 'SKILL.md'); + + if (existsSync(destFile)) { skipped++; continue; } + if (opts.dryRun) { installed++; continue; } + + try { + mkdirSync(destDir, { recursive: true }); + if (remote) { + writeFileSync(destFile, await fetchText(rawUrl(opts.ref, `${opts.locale}/${skill.id}/SKILL.md`)), 'utf8'); + } else { + const src = join(localSource, opts.locale, skill.id, 'SKILL.md'); + if (!existsSync(src)) throw new Error(`missing ${src}`); + copyFileSync(src, destFile); + } + installed++; + } catch (error) { + // One bad skill should not abort the install — report at the end instead. + failures.push(`${skill.id}: ${error.message}`); + } + } + + if (opts.json) { + process.stdout.write(`${JSON.stringify({ installed, skipped, failed: failures })}\n`); + } else { + process.stdout.write(`skills installed: ${installed}, already present: ${skipped}\n`); + for (const failure of failures) process.stderr.write(` failed: ${failure}\n`); + } + + if (failures.length > 0 && installed === 0) process.exit(1); +} + +main().catch((error) => fail(error.message)); diff --git a/origin.json b/origin.json new file mode 100644 index 0000000..5c60e13 --- /dev/null +++ b/origin.json @@ -0,0 +1,44 @@ +{ + "comment": [ + "Where this build points at for downloads, updates and support.", + "", + "This is a fork of github.com/dongsheng123132/u-claw, now hosted on our own", + "Gitea. Every URL the build fetches at runtime is listed here so moving hosts", + "is one edit, not a hunt.", + "", + "The one-line installers (install/install.sh, install/install.ps1) run via", + "curl|bash with no checkout, so they cannot read this file — they carry the", + "same URLs as literals. tests/origin.test.mjs fails if those literals and this", + "file ever disagree, so a migration cannot half-happen.", + "", + "rawTemplate is a template, not a base URL, because Gitea and GitHub lay raw", + "paths out differently: Gitea is /{owner}/{repo}/raw/branch/{ref}/{path},", + "GitHub is raw.githubusercontent.com/{owner}/{repo}/{ref}/{path}." + ], + "repo": { + "host": "gitea.fanghe.it.com", + "sshPort": 222, + "owner": "zhenghy", + "name": "u-claw", + "ref": "main" + }, + "urls": { + "web": "https://gitea.fanghe.it.com/zhenghy/u-claw", + "ssh": "ssh://git@gitea.fanghe.it.com:222/zhenghy/u-claw.git", + "rawTemplate": "https://gitea.fanghe.it.com/zhenghy/u-claw/raw/branch/{ref}/{path}", + "releases": "https://gitea.fanghe.it.com/zhenghy/u-claw/releases", + "issues": "https://gitea.fanghe.it.com/zhenghy/u-claw/issues", + "website": "https://u-claw.org" + }, + "support": { + "help": "help@u-claw.org", + "security": "hefangsheng@u-claw.org", + "author": "hello@u-claw.org", + "ciBot": "bot@u-claw.org", + "note": "website, security and author still point at the upstream project. Vulnerability reports currently reach someone who did not write this code and cannot fix it. Replace them once we have our own, and tests/origin.test.mjs will confirm nothing was missed." + }, + "upstream": { + "repo": "https://github.com/dongsheng123132/u-claw", + "note": "Kept for reference only. We do not send changes back — the overseas fork removes the China-market defaults that are the point of the upstream project." + } +} diff --git a/portable/Config.html b/portable/Config.html deleted file mode 100644 index dc0dd25..0000000 --- a/portable/Config.html +++ /dev/null @@ -1,748 +0,0 @@ - - - - - -U-Claw Pro — 模型配置 - - - -
-

🦞 U-Claw Pro

-

便携版 — 选择模型,填入 API Key,一键启动

- - -
-
1选模型
-
2填 Key
-
3启动
-
- - -
-

选择 AI 模型

-

最省心:用「虾盘云」一个 Key 调用国内外全部大模型(中转站)。也可用下面各家自己的官方 Key。

- -
-
- -

虾盘云 首选中转站

-

一个 Key 用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙

- → 注册 / 充值 / 获取 API Key -
-
- -

DeepSeek 国内便宜

-

deepseek-v4-flash / deepseek-v4-pro,超低价格

- → 获取 API Key -
-
- -

MiniMax 国内

-

MiniMax-M2,速度快,性价比高

- → 获取 API Key -
-
- -

Kimi (月之暗面) 国内

-

kimi-k2,长上下文强

- → 获取 API Key -
-
- -

智谱 GLM 国内有免费

-

glm-5(zai provider),免费额度可用

- → 获取 API Key -
-
- -

通义千问 国内有免费

-

qwen-plus / qwen3-max,阿里云出品

- → 获取 API Key -
-
- -

豆包 (字节) 国内

-

doubao-seed-1.6,字节跳动

- → 获取 API Key -
-
- -

OpenAI

-

GPT-5.4,需翻墙或中转

- → 获取 API Key -
-
- -

Claude

-

Claude Opus 4.6 / Sonnet 4.6,需翻墙或中转

- → 获取 API Key -
-
- -

Groq 极快有免费

-

Llama 3.3 70B,超高速推理

- → 获取 API Key -
-
- -

硅基流动 国内便宜

-

多模型聚合,价格低

- → 获取 API Key -
-
- -

自定义 OpenAI 兼容

-

填写任意 OpenAI 兼容 API 地址

-
-
- - - - -
- -
-
- - -
-

填写 API Key

-

请填写对应模型的 API Key

- -
-

📌 获取 / 充值 API Key

- -
- - - - -
- -
- - -
-

你的 Key 仅保存在本地 U 盘,不会上传到任何服务器

-
- -
- - -
-
- - -
-
-
🦞
-

配置完成!

-

模型和 API Key 已保存,准备好后点击下方按钮启动

-
http://127.0.0.1:18789
- -
-

📱 接入更多渠道(可选)

-

点击展开卡片填写配置,启动时自动写入。不填也可以直接启动:

-
-
-

✈️ Telegram

-

接入 Telegram Bot

-
-
- - -

→ 从 @BotFather 获取

-
-
-
-
-

🐧 QQ Bot

-

接入 QQ 群/私聊机器人

-
-
- - -
-
- - -

→ 从 QQ 开放平台获取

-
-
-
-
-

📘 飞书

-

接入飞书机器人

-
-
- - -
-
- - -

→ 从飞书开放平台获取

-
-
-
-
-

📲 钉钉 国内·最易

-

WebSocket 接入,免公网 IP

-
-
- - -
-
- - -

→ 从钉钉开放平台创建机器人应用

-
-
-
-
-

🏢 企业微信

-

接入企业微信机器人

-
-
- - -
- -
-
-
-
- -
- -

启动后会自动打开控制台,渠道配置会自动写入 openclaw.json

-
- -
- -
-
-
- - -
-

📦 技能 & 文档

-

技能存放在 skills/ 目录,文档存放在 docs/ 目录,随 U 盘携带

-
-
-
-

skills/ — 技能目录

-

放入 .md 技能文件,OpenClaw 会自动加载

-
- 📁 -
-
-
-

docs/ — 文档目录

-

存放使用说明、帮助文档等

-
- 📁 -
-
-
-

data/ — 配置和聊天记录

-

API Key、聊天历史等保存在此

-
- 🔒 -
-
-
-
- -
- - - - diff --git a/portable/Mac-Start.command b/portable/Mac-Start.command deleted file mode 100755 index 78b0531..0000000 --- a/portable/Mac-Start.command +++ /dev/null @@ -1,235 +0,0 @@ -#!/bin/bash -# ============================================================ -# U-Claw - Portable AI Agent (macOS) -# Double-click to start / 双击启动 -# ============================================================ - -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" -APP_DIR="$UCLAW_DIR/app" -CORE_DIR="$APP_DIR/core" -DATA_DIR="$UCLAW_DIR/data" -STATE_DIR="$DATA_DIR/.openclaw" -CONFIG_FILE="$STATE_DIR/openclaw.json" - -# Migration shim: rename old core-mac to core for existing USB users -if [ -d "$APP_DIR/core-mac" ] && [ ! -d "$APP_DIR/core" ]; then - mv "$APP_DIR/core-mac" "$APP_DIR/core" -fi - -RED='\033[0;31m' -GREEN='\033[0;32m' -CYAN='\033[0;36m' -YELLOW='\033[1;33m' -NC='\033[0m' - -echo "" -echo -e "${CYAN}" -echo " ╔══════════════════════════════════════╗" -echo " ║ 🦞 U-Claw v1.1 ║" -echo " ║ Portable AI Agent ║" -echo " ╚══════════════════════════════════════╝" -echo -e "${NC}" - -# ---- 1. Detect CPU & set runtime ---- -ARCH=$(uname -m) -if [ "$ARCH" = "arm64" ]; then - NODE_DIR="$APP_DIR/runtime/node-mac-arm64" - echo -e " ${GREEN}Apple Silicon (M series)${NC}" -elif [ "$ARCH" = "x86_64" ]; then - NODE_DIR="$APP_DIR/runtime/node-mac-x64" - echo -e " ${GREEN}Intel Mac (x64)${NC}" -else - echo -e " ${RED}Unsupported architecture: $ARCH${NC}" - echo "" - read -p " Press Enter to exit..." - exit 1 -fi - -NODE_BIN="$NODE_DIR/bin/node" -export PATH="$NODE_DIR/bin:$PATH" - -# ---- 2. Remove macOS quarantine ---- -if xattr -l "$NODE_BIN" 2>/dev/null | grep -q "com.apple.quarantine"; then - echo -e " ${YELLOW}Removing macOS security restriction...${NC}" - xattr -rd com.apple.quarantine "$UCLAW_DIR" 2>/dev/null || true - echo -e " ${GREEN}Done${NC}" -fi - -# ---- 3. Check runtime ---- -if [ ! -f "$NODE_BIN" ]; then - echo -e " ${RED}Error: Node.js runtime not found${NC}" - echo " Please run: bash setup.sh" - read -p " Press Enter to exit..." - exit 1 -fi - -NODE_VER=$("$NODE_BIN" --version) -echo -e " Node.js: ${GREEN}${NODE_VER}${NC}" -echo "" - -# ---- 4. Init data directories ---- -mkdir -p "$STATE_DIR" "$DATA_DIR/memory" "$DATA_DIR/backups" "$DATA_DIR/logs" - -# ---- 4b. 加速:把"重 IO、可重建"的缓存从 U 盘搬到本机硬盘 ---- -# portable-cache.mjs 算出本机缓存目录(~/Library/Caches/U-Claw/slot,UUID 隔离, -# 换盘符仍复用),并把 .openclaw/browser 做成 symlink 指向本机盘。 -# 浏览器 user-data(几百 MB 随机小写)和 V8 编译缓存因此落本机盘,不再拖慢 U 盘。 -# 静默失败:取不到就跳过,缓存留 U 盘,照常启动。 -while IFS='=' read -r _k _v; do - case "$_k" in - UCLAW_COMPILE_CACHE_DIR) export NODE_COMPILE_CACHE="$_v" ;; - UCLAW_CACHE_ROOT) UCLAW_CACHE_ROOT="$_v" ;; - esac -done < <("$NODE_BIN" "$UCLAW_DIR/lib/portable-cache.mjs" "$STATE_DIR" "$UCLAW_DIR" 2>/dev/null) -[ -n "$NODE_COMPILE_CACHE" ] && echo -e " ${GREEN}Cache on local disk:${NC} $UCLAW_CACHE_ROOT" - -# ---- 5. Default config ---- -if [ ! -f "$CONFIG_FILE" ]; then - if [ -f "$DATA_DIR/config.json" ]; then - echo -e " ${YELLOW}Migrating legacy config...${NC}" - cp "$DATA_DIR/config.json" "$CONFIG_FILE" - echo -e " ${GREEN}Config migrated${NC}" - else - echo -e " ${YELLOW}First run - creating default config...${NC}" - cat > "$CONFIG_FILE" << 'CFGEOF' -{ - "gateway": { - "mode": "local", - "auth": { "token": "uclaw" } - } -} -CFGEOF - echo -e " ${GREEN}Config created${NC}" - fi - echo "" -fi - -# ---- 6. Set environment (portable mode) ---- -export OPENCLAW_HOME="$DATA_DIR" -export OPENCLAW_STATE_DIR="$STATE_DIR" -export OPENCLAW_CONFIG_PATH="$CONFIG_FILE" -# U-Claw opens the local dashboard directly; disable mDNS/Bonjour discovery. -# On macOS the bonjour plugin auto-starts and advertises the gateway on the LAN -# (_openclaw-gw._tcp.local), which is unnecessary for local use and triggers -# "no IPv4 address available on utunN" warnings on machines with VPN/Tailscale. -export OPENCLAW_DISABLE_BONJOUR=1 - -# ---- 7. Check dependencies ---- -if [ ! -d "$CORE_DIR/node_modules" ]; then - echo -e " ${YELLOW}[WARN] node_modules not found${NC}" - echo " This release should ship with deps pre-installed." - echo " Falling back to npm install (USB drives may take 20+ min)." - echo " TIP: re-download u-claw-portable-*.zip with bundled deps." - cd "$CORE_DIR" - # 把 npm 缓存留在盘内,避免污染系统 ~/.npm(拔盘不留痕) - npm_config_cache="$APP_DIR/.npm-cache" \ - "$NODE_BIN" "$NODE_DIR/bin/npm" install --registry=https://registry.npmmirror.com --ignore-scripts --no-audit --no-fund --omit=dev 2>&1 - echo -e " ${GREEN}Dependencies installed${NC}" - echo "" -fi - -# ---- 7b. Async update check (non-blocking, 5s timeout, silent failure) ---- -# Writes data/.openclaw/update-available.json if a newer version is on OSS. -# Welcome.html / Config.html read this file and show a banner. -# Version file lookup: portable/OPENCLAW_VERSION (USB) → ../OPENCLAW_VERSION (dev) -VERSION_FILE="$UCLAW_DIR/OPENCLAW_VERSION" -[ -f "$VERSION_FILE" ] || VERSION_FILE="$UCLAW_DIR/../OPENCLAW_VERSION" -if [ -f "$VERSION_FILE" ]; then - "$NODE_BIN" "$UCLAW_DIR/lib/check-update.mjs" "$VERSION_FILE" "$STATE_DIR" >/dev/null 2>&1 & -fi - -# ---- 7c. Intranet/self-hosted model fix ---- -# Keep the configured model host(s) off any corporate HTTP_PROXY/HTTPS_PROXY. -# OpenClaw routes ALL fetch through the env proxy when it is set, which breaks -# calls to internal model endpoints (http://10.x / 192.168.x / a machine-room IP). -# Add those hosts + loopback to NO_PROXY so they connect directly. -# Silent no-op when no proxy/model is configured. -NO_PROXY_LINE="$("$NODE_BIN" "$UCLAW_DIR/lib/resolve-no-proxy.mjs" "$CONFIG_FILE" 2>/dev/null)" -case "$NO_PROXY_LINE" in - UCLAW_NO_PROXY=*) - export NO_PROXY="${NO_PROXY_LINE#UCLAW_NO_PROXY=}" - export no_proxy="$NO_PROXY" - echo " Direct-connect (NO_PROXY): $NO_PROXY" - ;; -esac - -# ---- 8. Find available port ---- -PORT=18789 -while lsof -i :$PORT >/dev/null 2>&1; do - echo -e " ${YELLOW}Port $PORT in use, trying next...${NC}" - PORT=$((PORT + 1)) - if [ $PORT -gt 18799 ]; then - echo -e " ${RED}No available port (18789-18799)${NC}" - read -p " Press Enter to exit..." - exit 1 - fi -done - -# ---- 9. Start Config Server in background ---- -echo -e " ${CYAN}Starting Config Center on port 18788...${NC}" -CONFIG_SERVER="$UCLAW_DIR/config-server" -"$NODE_BIN" "$CONFIG_SERVER/server.js" & -CONFIG_PID=$! -sleep 1 - -# ---- 10. Start gateway ---- -echo -e " ${CYAN}Starting OpenClaw on port $PORT...${NC}" -echo "" - -cd "$CORE_DIR" -OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs" -"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT & -GW_PID=$! - -# ---- 11. 立刻打开"启动首屏",给用户即时反馈(移植自 4.0 splash)---- -# 首屏 loading.html 自己轮询 /ready,就绪后停在选择页,不再自动冲进 Dashboard。 -echo -e " ${YELLOW}首次启动需准备运行环境,约 30-90 秒,请稍候...${NC}" -# 用 file:// URL 确保 query string(?port=)能传给浏览器;裸路径 open 会把整串当文件名。 -open "file://$UCLAW_DIR/lib/loading.html?port=$PORT&token=uclaw" 2>/dev/null || true -# 每次都打开 Config Center,方便改模型、充值/获取 Key、连接微信等渠道。 -open "http://127.0.0.1:18788/" 2>/dev/null || true - -# ---- 11b. gateway 首轮预热(后台、静默、非阻塞)---- -# 就绪后先唤醒 config/model 子系统,用户首次点发送时不再等。移植自 4.0 first-turn-prewarm。 -"$NODE_BIN" "$UCLAW_DIR/lib/prewarm.mjs" "$PORT" uclaw >/dev/null 2>&1 & - -# ---- 11c. 兜底:万一首屏页的 file:// fetch 被浏览器拦,仍静默轮询端口 ---- -# 慢盘首启可达 90s+,轮询上限覆盖这段。最多 ~3 分钟(180×1s)。 -( - for i in $(seq 1 180); do - if curl -s -o /dev/null "http://127.0.0.1:$PORT/" 2>/dev/null; then - exit 0 - fi - sleep 1 - done -) & - -echo -e " ${GREEN}════════════════════════════════${NC}" -echo -e " ${GREEN}🦞 U-Claw is running!${NC}" -echo -e " ${GREEN} Dashboard: http://127.0.0.1:$PORT/#token=uclaw${NC}" -echo -e " ${GREEN} Config Center: http://127.0.0.1:18788/${NC}" -echo "" -echo -e " ${YELLOW}Press Ctrl+C to stop${NC}" -echo -e " ${GREEN}════════════════════════════════${NC}" -echo "" - -# ---- Cleanup on exit ---- -cleanup() { - kill $GW_PID 2>/dev/null - kill $CONFIG_PID 2>/dev/null - echo "" - echo -e " 🦞 U-Claw stopped." - exit 0 -} -trap cleanup INT TERM - -wait $GW_PID -GW_EXIT=$? - -# Ctrl+C 走 trap cleanup(exit 0)不会到这;走到这里说明 gateway 自己退了。 -if [ "$GW_EXIT" -ne 0 ]; then - echo -e " ${YELLOW}OpenClaw exited unexpectedly (code $GW_EXIT)${NC}" -fi -kill $CONFIG_PID 2>/dev/null -echo "" -echo -e " 🦞 U-Claw stopped." diff --git a/portable/Welcome.html b/portable/Read me first.html similarity index 57% rename from portable/Welcome.html rename to portable/Read me first.html index 98e3d6a..4140bce 100644 --- a/portable/Welcome.html +++ b/portable/Read me first.html @@ -1,9 +1,9 @@ - + -U-Claw 使用指南 +U-Claw — Getting Started + + +
-

🦞 U-Claw 使用指南

-
AI助手便携U盘 · 3步开始使用
+

🦞 U-Claw — Getting Started

+
Your AI assistant on a USB drive · three steps
-
快速开始
+
Quick start
-
第1步:启动服务
+
1. Start U-Claw
- 根据您的系统,双击对应的启动文件:

- Windows 用户:双击 Windows-Start.bat
- Mac 用户:双击 Mac-Start.command + Double-click the file for your computer:

+ WindowsSTART HERE - Windows.bat
+ MacSTART HERE - Mac.command
-
第2步:配置AI模型
+
2. Add a key
- 首次启动会自动打开配置页面,按照提示操作:
- 1. 选择一个AI模型(推荐 DeepSeek - 便宜好用)
- 2. 填写API Key(去模型官网注册获取)
- 3. 点击"保存配置" + Settings opens on its own the first time. You need one API key to get going — Google Gemini is the easiest to obtain: sign in with a Google account, no card required.
+ Get a free Gemini key →
-
第3步:开始对话
+
3. Start talking
- 配置完成后,浏览器会自动打开AI对话界面
- 地址:http://127.0.0.1:18789
- 现在可以和AI助手对话了! + Once the key is saved, the chat window opens by itself. That is it.
-

✅ 所有配置和对话记录保存在U盘的 data/ 目录,Mac和Windows自动共享!

+

✅ Your settings and history stay in the data/ folder on the drive, so they travel with you between Mac and Windows.

-
推荐AI模型
+
Which model?
-
- 🔥 DeepSeek - 编程首选,极便宜 -
-
- 📄 Kimi - 长文档处理专家 -
-
- 🆓 通义千问 - 免费额度大 -
🌟 Claude - 最强理解能力 + Best all-rounder +
+
+ 💬 GPT + Most widely used +
+
+ 🆓 Gemini + Free tier, easiest signup +
+
+ 🔒 Local model + Offline · nothing leaves this machine
+

More options, including SEA-LION for Malay, Tamil and Singlish, are in Settings.

-
遇到问题?
+
Something not working?
- 💡 运行诊断工具 + 💡 Run the check-up tool

- 如果启动失败,双击运行诊断工具:
- Windows: Windows-Diagnose.bat
- Mac: Mac-Diagnose.command + If U-Claw will not start, double-click:
+ Windows — Windows-Diagnose.bat
+ Mac — Mac-Diagnose.command

diff --git a/portable/START HERE - Mac.command b/portable/START HERE - Mac.command new file mode 100755 index 0000000..7a0ab77 --- /dev/null +++ b/portable/START HERE - Mac.command @@ -0,0 +1,33 @@ +#!/bin/bash +# ============================================================ +# U-Claw - Portable AI Agent (macOS) +# Double-click to start +# ============================================================ +# +# Thin launcher: locate the bundled node and hand off to lib/start.mjs. +# All checks, messages and error handling live there so macOS and Windows +# cannot drift apart and so every string can be translated. + +UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" + +if [ "$(uname -m)" = "arm64" ]; then + NODE_BIN="$UCLAW_DIR/app/runtime/node-mac-arm64/bin/node" +else + NODE_BIN="$UCLAW_DIR/app/runtime/node-mac-x64/bin/node" +fi + +if [ ! -x "$NODE_BIN" ]; then + echo "" + echo " U-Claw is missing a file it needs to start." + echo " The copy onto this drive probably did not finish." + echo "" + echo " Copy the U-Claw folder onto the drive again, or run: bash setup.sh" + echo "" + read -r -p " Press Enter to close this window." + exit 1 +fi + +"$NODE_BIN" "$UCLAW_DIR/lib/start.mjs" +EXIT_CODE=$? +[ "$EXIT_CODE" -ne 0 ] && read -r -p " Press Enter to close this window." +exit $EXIT_CODE diff --git a/portable/START HERE - Windows.bat b/portable/START HERE - Windows.bat new file mode 100644 index 0000000..d195e6f --- /dev/null +++ b/portable/START HERE - Windows.bat @@ -0,0 +1,28 @@ +@echo off +chcp 65001 >nul 2>&1 +title U-Claw + +REM Thin launcher: locate the bundled node and hand off to lib\start.mjs. +REM All checks, messages and error handling live there so Windows and macOS +REM cannot drift apart, and so nothing user-facing has to be written in a .bat +REM (cmd.exe mis-parses non-ASCII as GBK, and treats an unescaped ) as +REM block-end -- both were recurring sources of flash-exit bugs). + +set "UCLAW_DIR=%~dp0" +set "NODE_BIN=%UCLAW_DIR%app\runtime\node-win-x64\node.exe" + +if not exist "%NODE_BIN%" ( + echo. + echo U-Claw is missing a file it needs to start. + echo The copy onto this drive probably did not finish. + echo. + echo Copy the U-Claw folder onto the drive again, then try once more. + echo. + pause + exit /b 1 +) + +"%NODE_BIN%" "%UCLAW_DIR%lib\start.mjs" +set "EXIT_CODE=%errorlevel%" +pause +exit /b %EXIT_CODE% diff --git a/portable/SkillHub.html b/portable/SkillHub.html deleted file mode 100644 index 4c0ffd1..0000000 --- a/portable/SkillHub.html +++ /dev/null @@ -1,703 +0,0 @@ - - - - - -U-Claw SkillHub - AI 技能市场 - - - - - - - - -
- - -
-

装上 Skill,解锁 AI 超能力

-

精选推荐 · 高速下载 · 轻松查找
ClawHub 13,000+ 个 AI Skills,U-Claw 为你加速

-
-
13,729
技能总数
-
32
分类
-
2,868
精选优质
-
52
U-Claw 预装
-
- -
- - - - - -
- - - - - -
-
-

全部分类

- 32 个分类 -
-
-
💻
编程 Agent
55 个技能
-
🌐
Web 前端
46 个技能
-
🔀
Git & GitHub
34 个技能
-
☁️
DevOps & 云
144 个技能
-
🖱
浏览器自动化
69 个技能
-
🧠
AI & LLMs
159 个技能
-
🎨
图片 & 视频
41 个技能
-
效率工具
93 个技能
-
📊
数据 & 分析
18 个技能
-
📝
笔记 & 知识
38 个技能
-
📧
邮件 & 通讯
24 个技能
-
💬
社交媒体
31 个技能
-
🔍
搜索 & 研究
47 个技能
-
🏠
智能家居
22 个技能
-
💰
金融 & 加密
28 个技能
-
🛡
安全防护
19 个技能
-
🎙
语音 & TTS
15 个技能
-
📁
文件管理
33 个技能
-
🌍
翻译
12 个技能
-
📅
日历 & 提醒
16 个技能
-
-
- 更多分类请在搜索框输入关键词,或使用命令:openclaw skills search 关键词 -
-
- - -
-
-

下载排行榜

- 2026 年 3 月 -
- - - - - - - - - - - - - - - - - - - - - -
#技能分类下载量安装命令
1Tavily Search搜索52,000+openclaw skills install @tavily/search
2GitHub开发48,000+openclaw skills install @openclaw/github
3Capability EvolverAI35,581openclaw skills install @cap/evolver
4Coding Agent编程31,000+openclaw skills install @openclaw/coding-agent
5Browser Relay自动化29,000+openclaw skills install @nicosql/browser-relay
6OpenAI Image Gen创作26,000+openclaw skills install @openclaw/openai-image-gen
7Obsidian笔记22,000+openclaw skills install @openclaw/obsidian
8Himalaya邮件21,000+openclaw skills install @sostrovsky/himalaya
9Notion效率19,000+openclaw skills install @openclaw/notion
10Weather生活18,000+openclaw skills install @openclaw/weather
11Peekaboo多模态17,000+openclaw skills install @nicosql/peekaboo
12Wacli自动化16,415openclaw skills install @nicosql/wacli
13ByteRover搜索16,004openclaw skills install @byterover/search
14Self-Improving AgentAI15,962openclaw skills install @self-improving-agent
15Apple Notes笔记15,000+openclaw skills install @openclaw/apple-notes
-
- - -
-
-

安装技能

-
- -
- - -
- -
-
-
-

将此提示发送给你的 Agent,以安装技能

-

复制下面的命令,粘贴到你的 OpenClaw 对话中。Agent 会自动搜索和安装。

-
- 帮我安装 [技能名称] 这个 skill - -
-
- 搜索关于 [功能描述] 的 skill 并安装最合适的 - -
-
-
-
- - - -
-

常用操作速查

- - - - - - - - - - - -
操作命令
搜索技能openclaw skills search 关键词
安装技能openclaw skills install @作者/技能名
查看已装技能openclaw skills list
卸载技能openclaw skills uninstall 技能名
更新技能openclaw skills update 技能名
ClawHub 搜索openclaw clawhub search 关键词
查看技能详情openclaw skills info @作者/技能名
-
- -
-

U-Claw 用户专属

-
-
-

52 个技能已预装,开箱即用

-

U-Claw 已内置最常用的 52 个官方技能,无需联网下载。在启动菜单选 [13] 可浏览完整列表。
需要更多技能?使用上面的命令从 ClawHub 在线安装。

-
-
-
-
- - - - -
- - - - -
- - - - diff --git a/portable/Windows-Start.bat b/portable/Windows-Start.bat deleted file mode 100644 index d287211..0000000 --- a/portable/Windows-Start.bat +++ /dev/null @@ -1,220 +0,0 @@ -@echo off -chcp 65001 >nul 2>&1 -title U-Claw - Portable AI Agent - -echo. -echo ======================================== -echo U-Claw v1.1 - Portable AI Agent -echo ======================================== -echo. - -set "UCLAW_DIR=%~dp0" -set "APP_DIR=%UCLAW_DIR%app" - -REM Migration shim: rename old core-win to core for existing USB users -if exist "%APP_DIR%\core-win" if not exist "%APP_DIR%\core" ren "%APP_DIR%\core-win" core - -set "CORE_DIR=%APP_DIR%\core" -set "DATA_DIR=%UCLAW_DIR%data" -set "STATE_DIR=%DATA_DIR%\.openclaw" -set "NODE_DIR=%APP_DIR%\runtime\node-win-x64" -set "NODE_BIN=%NODE_DIR%\node.exe" -set "NPM_BIN=%NODE_DIR%\npm.cmd" - -set "OPENCLAW_HOME=%DATA_DIR%" -set "OPENCLAW_STATE_DIR=%STATE_DIR%" -set "OPENCLAW_CONFIG_PATH=%STATE_DIR%\openclaw.json" -REM U-Claw opens the local dashboard directly; disable mDNS discovery on Windows -REM to avoid OpenClaw/@homebridge ciao crashes during bonjour re-advertise. -set "OPENCLAW_DISABLE_BONJOUR=1" - -REM Check runtime -if not exist "%NODE_BIN%" ( - echo [ERROR] Node.js runtime not found - echo Please ensure app\runtime\node-win-x64 is complete - pause - exit /b 1 -) - -for /f "tokens=*" %%v in ('"%NODE_BIN%" --version') do set NODE_VER=%%v -echo Node.js: %NODE_VER% -echo. - -set "PATH=%NODE_DIR%;%NODE_DIR%\node_modules\.bin;%PATH%" - -REM Init data directories -if not exist "%DATA_DIR%" mkdir "%DATA_DIR%" -if not exist "%STATE_DIR%" mkdir "%STATE_DIR%" -if not exist "%DATA_DIR%\memory" mkdir "%DATA_DIR%\memory" -if not exist "%DATA_DIR%\backups" mkdir "%DATA_DIR%\backups" -if not exist "%DATA_DIR%\logs" mkdir "%DATA_DIR%\logs" - -REM Startup cache acceleration. -REM portable-cache.mjs chooses a local-disk cache slot and redirects -REM .openclaw\browser there with a junction when possible. -REM Browser user data and V8 compile cache stay off the USB drive. -REM If this fails, startup continues with the cache on the USB drive. -for /f "usebackq tokens=1,* delims==" %%a in (`""%NODE_BIN%" "%UCLAW_DIR%lib\portable-cache.mjs" "%STATE_DIR%" "%UCLAW_DIR%" 2^>nul"`) do ( - if "%%a"=="UCLAW_COMPILE_CACHE_DIR" set "NODE_COMPILE_CACHE=%%b" - if "%%a"=="UCLAW_CACHE_ROOT" set "UCLAW_CACHE_ROOT=%%b" -) -if defined NODE_COMPILE_CACHE echo Cache on local disk: %UCLAW_CACHE_ROOT% - -REM Default config (migrate legacy if present, otherwise create) -if not exist "%STATE_DIR%\openclaw.json" ( - if exist "%DATA_DIR%\config.json" ( - echo Migrating legacy config... - copy "%DATA_DIR%\config.json" "%STATE_DIR%\openclaw.json" >nul - echo Config migrated - ) else ( - echo First run - creating default config... - (echo {"gateway":{"mode":"local","auth":{"token":"uclaw"}}})>"%STATE_DIR%\openclaw.json" - echo Config created - ) - echo. -) - -REM Check dependencies -REM Note: avoid unescaped parens inside this block -- cmd.exe treats ) as block-end. -if not exist "%CORE_DIR%\node_modules" ( - echo ======================================== - echo [WARN] node_modules not found - echo ======================================== - echo This release should ship with deps pre-installed. - echo Falling back to npm install ^(USB drives may take 20+ minutes^). - echo. - echo TIP: Re-download u-claw-portable-*.zip from GitHub releases, - echo which includes pre-installed deps ^(~200 MB^). - echo. - echo File system: NTFS recommended. exFAT/FAT32 will be very slow. - echo. - cd /d "%CORE_DIR%" - REM Keep npm cache inside the portable app instead of system APPDATA. - set "npm_config_cache=%APP_DIR%\.npm-cache" - call "%NPM_BIN%" install --registry=https://registry.npmmirror.com --ignore-scripts --no-audit --no-fund --omit=dev - echo. - echo Dependencies installed! - echo. -) - -REM Intranet/self-hosted model fix: keep the configured model host(s) off any -REM corporate HTTP_PROXY/HTTPS_PROXY. OpenClaw routes ALL fetch through the env -REM proxy when it is set, which breaks calls to internal model endpoints -REM (e.g. http://10.x / 192.168.x / a machine-room IP). Add those hosts + loopback -REM to NO_PROXY so they connect directly. Silent no-op when no proxy/model is set. -for /f "usebackq tokens=1,* delims==" %%a in (`""%NODE_BIN%" "%UCLAW_DIR%lib\resolve-no-proxy.mjs" "%STATE_DIR%\openclaw.json" 2^>nul"`) do ( - if "%%a"=="UCLAW_NO_PROXY" set "NO_PROXY=%%b" -) -if defined NO_PROXY ( - set "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) -REM Writes data\.openclaw\update-available.json if a newer version is on OSS. -REM Welcome.html / Config.html read this file and show a banner. -REM Version file lookup order: portable/OPENCLAW_VERSION (USB), then repo-root ../OPENCLAW_VERSION (dev) -set "VERSION_FILE=%UCLAW_DIR%OPENCLAW_VERSION" -if not exist "%VERSION_FILE%" set "VERSION_FILE=%UCLAW_DIR%..\OPENCLAW_VERSION" -if exist "%VERSION_FILE%" ( - start /B "" "%NODE_BIN%" "%UCLAW_DIR%lib\check-update.mjs" "%VERSION_FILE%" "%STATE_DIR%" >nul 2>&1 -) - - -REM Auto-install WeChat plugin if available -set "WECHAT_PLUGIN_SRC=%APP_DIR%\extensions\openclaw-weixin" -set "WECHAT_PLUGIN_DST=%USERPROFILE%\.openclaw\extensions\openclaw-weixin" -if exist "%WECHAT_PLUGIN_SRC%\openclaw.plugin.json" ( - if not exist "%WECHAT_PLUGIN_DST%\openclaw.plugin.json" ( - echo Installing WeChat plugin... - mkdir "%USERPROFILE%\.openclaw\extensions" 2>nul - xcopy /s /e /q /y "%WECHAT_PLUGIN_SRC%" "%WECHAT_PLUGIN_DST%\" >nul - echo WeChat plugin installed! - echo. - ) -) - -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 -if %errorlevel%==0 ( - echo Port %PORT% in use, trying next... - set /a PORT+=1 - if %PORT% gtr 18799 ( - echo No available port 18789-18799 - pause - exit /b 1 - ) - goto :check_port -) - -echo Starting OpenClaw on port %PORT%... -echo. - -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. -REM Config Center lets users change models, recharge/get keys, and connect channels. - -REM Open startup page with the gateway port and token in the query string. -echo Opening startup screen... -set "LOADING_PATH=%UCLAW_DIR%lib\loading.html" -set "LOADING_URL=file:///%LOADING_PATH:\=/%?port=%PORT%&token=uclaw" -start "" "%LOADING_URL%" - -echo Opening Config Center... -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% %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 - -echo. -echo ======================================== -echo Starting OpenClaw Gateway on port %PORT%... -echo First run on a USB drive may take 30-90 seconds -echo (unpacking bundled components). Please wait; -echo Config Center is open for model, key, recharge, and channel setup. -echo DO NOT close this window while using U-Claw! -echo ======================================== -echo. - -cd /d "%CORE_DIR%" -set "OPENCLAW_MJS=%CORE_DIR%\node_modules\openclaw\openclaw.mjs" -"%NODE_BIN%" "%OPENCLAW_MJS%" gateway run --allow-unconfigured --force --port %PORT% -set "GW_EXIT=%errorlevel%" - -echo. -if not "%GW_EXIT%"=="0" if not "%GW_EXIT%"=="-1073741510" ( - echo OpenClaw exited unexpectedly ^(code %GW_EXIT%^) -) -echo OpenClaw stopped. -pause diff --git a/portable/advanced/Config.html b/portable/advanced/Config.html new file mode 100644 index 0000000..4dfa883 --- /dev/null +++ b/portable/advanced/Config.html @@ -0,0 +1,120 @@ + + + + + +U-Claw Settings + + + + +
+
🦞
+
+

Opening settings…

+
+ +
+ + + + diff --git a/portable/Mac-Diagnose.command b/portable/advanced/Mac-Diagnose.command similarity index 95% rename from portable/Mac-Diagnose.command rename to portable/advanced/Mac-Diagnose.command index 7766897..8ace0aa 100644 --- a/portable/Mac-Diagnose.command +++ b/portable/advanced/Mac-Diagnose.command @@ -4,7 +4,7 @@ # 诊断工具 # ============================================================ -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" LOG_FILE="$UCLAW_DIR/diagnostic-log.txt" GREEN='\033[0;32m' @@ -16,10 +16,10 @@ clear echo "" echo " ========================================" echo " U-Claw Diagnostic Tool" -echo " 诊断工具" +echo " Check-up" echo " ========================================" echo "" -echo " Checking system... 正在检查系统..." +echo " Checking this computer…" echo "" # Clear old log @@ -135,7 +135,7 @@ echo " Log saved to: diagnostic-log.txt" echo "" echo " Next steps:" echo " 1. Check diagnostic-log.txt for details" -echo " 2. If errors found, try running Mac-Start.command" +echo " 2. If errors found, try running START HERE - Mac.command" echo " to auto-install missing dependencies" echo "" read -p " Press Enter to exit..." diff --git a/portable/Mac-Install.command b/portable/advanced/Mac-Install.command similarity index 71% rename from portable/Mac-Install.command rename to portable/advanced/Mac-Install.command index 63c3320..964ef81 100755 --- a/portable/Mac-Install.command +++ b/portable/advanced/Mac-Install.command @@ -6,7 +6,7 @@ set -e -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$UCLAW_DIR/app" INSTALL_TARGET="$HOME/.uclaw" @@ -18,16 +18,16 @@ NC='\033[0m' BOLD='\033[1m' DIM='\033[2m' -NODE_VER="v22.14.0" -MIRROR="https://registry.npmmirror.com" -NODE_MIRROR="https://npmmirror.com/mirrors/node" +NODE_VER="$(tr -d "[:space:]" < "$UCLAW_DIR/NODE_VERSION" 2>/dev/null || tr -d "[:space:]" < "$UCLAW_DIR/../NODE_VERSION" 2>/dev/null || echo v22.22.1)" +MIRROR="https://registry.npmjs.org" +NODE_MIRROR="https://nodejs.org/dist" clear echo "" echo -e "${CYAN}${BOLD}" echo " ╔══════════════════════════════════════╗" -echo " ║ U-Claw 安装到 Mac ║" -echo " ║ 从 U 盘离线安装 ║" +echo " ║ Install U-Claw on this Mac ║" +echo " ║ Offline, from the drive ║" echo " ╚══════════════════════════════════════╝" echo -e "${NC}" echo "" @@ -35,7 +35,7 @@ echo "" # ---- Check CPU ---- ARCH=$(uname -m) if [ "$ARCH" = "arm64" ]; then - echo -e " ${GREEN}Apple Silicon (M 系列) ✓${NC}" + echo -e " ${GREEN}Apple Silicon${NC}" NODE_PLATFORM="node-mac-arm64" else echo -e " ${YELLOW}Intel Mac${NC}" @@ -45,18 +45,18 @@ echo "" # ---- Check existing installation ---- if [ -d "$INSTALL_TARGET" ]; then - echo -e " ${YELLOW}检测到已有安装: $INSTALL_TARGET${NC}" - read -p " 覆盖安装?(y/n): " -n 1 OVERWRITE + echo -e " ${YELLOW}Already installed at $INSTALL_TARGET${NC}" + read -p " Install over it? (y/n): " -n 1 OVERWRITE echo "" if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then - echo -e " ${DIM}已取消${NC}" + echo -e " ${DIM}Cancelled${NC}" exit 0 fi echo "" fi # ---- Step 1: Check environment ---- -echo -e " ${BOLD}[1/4] 检查环境...${NC}" +echo -e " ${BOLD}[1/4] Checking${NC}" NEED_DOWNLOAD_NODE=false NEED_DOWNLOAD_OPENCLAW=false @@ -66,21 +66,21 @@ USB_NODE="$APP_DIR/runtime/$NODE_PLATFORM/bin/node" USB_NPM="$APP_DIR/runtime/$NODE_PLATFORM/bin/npm" if [ -f "$USB_NODE" ]; then - echo -e " ${GREEN}Node.js: 使用 U 盘内的 ($("$USB_NODE" --version))${NC}" + echo -e " ${GREEN}Node.js: using the copy on the drive ($("$USB_NODE" --version))${NC}" USE_NODE="usb" elif command -v node >/dev/null 2>&1; then SYS_VER=$(node --version) MAJOR=$(echo "$SYS_VER" | sed 's/v//' | cut -d. -f1) if [ "$MAJOR" -ge 20 ] 2>/dev/null; then - echo -e " ${GREEN}Node.js: 使用系统的 ($SYS_VER)${NC}" + echo -e " ${GREEN}Node.js: using the system copy ($SYS_VER)${NC}" USE_NODE="system" else - echo -e " ${YELLOW}Node.js: 系统版本太低 ($SYS_VER),需要 v20+${NC}" + echo -e " ${YELLOW}Node.js: the system copy is too old ($SYS_VER); v20 or newer is needed${NC}" NEED_DOWNLOAD_NODE=true USE_NODE="download" fi else - echo -e " ${YELLOW}Node.js: 未安装${NC}" + echo -e " ${YELLOW}Node.js: not installed${NC}" NEED_DOWNLOAD_NODE=true USE_NODE="download" fi @@ -88,10 +88,10 @@ fi # Check OpenClaw USB_OPENCLAW="$APP_DIR/core/node_modules/openclaw/openclaw.mjs" if [ -f "$USB_OPENCLAW" ]; then - echo -e " ${GREEN}OpenClaw: 使用 U 盘内的${NC}" + echo -e " ${GREEN}OpenClaw: using the copy on the drive${NC}" USE_OPENCLAW="usb" else - echo -e " ${YELLOW}OpenClaw: U 盘内未找到,需要在线下载${NC}" + echo -e " ${YELLOW}OpenClaw: not on the drive, will download it${NC}" NEED_DOWNLOAD_OPENCLAW=true USE_OPENCLAW="download" fi @@ -99,7 +99,7 @@ fi echo "" # ---- Step 2: Create install directory ---- -echo -e " ${BOLD}[2/4] 安装到 $INSTALL_TARGET ...${NC}" +echo -e " ${BOLD}[2/4] Installing to $INSTALL_TARGET${NC}" mkdir -p "$INSTALL_TARGET" mkdir -p "$INSTALL_TARGET/data/.openclaw" @@ -107,27 +107,27 @@ mkdir -p "$INSTALL_TARGET/data/memory" mkdir -p "$INSTALL_TARGET/data/backups" # ---- Step 3: Copy/Download Node.js ---- -echo -e " ${BOLD}[3/4] 安装 Node.js...${NC}" +echo -e " ${BOLD}[3/4] Installing Node.js${NC}" NODE_INSTALL_DIR="$INSTALL_TARGET/runtime/$NODE_PLATFORM" case $USE_NODE in usb) - echo -e " ${CYAN}从 U 盘复制 Node.js...${NC}" + echo -e " ${CYAN}Copying Node.js from the drive${NC}" mkdir -p "$NODE_INSTALL_DIR" cp -R "$APP_DIR/runtime/$NODE_PLATFORM/"* "$NODE_INSTALL_DIR/" chmod +x "$NODE_INSTALL_DIR/bin/node" INSTALL_NODE="$NODE_INSTALL_DIR/bin/node" INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm" - echo -e " ${GREEN}Node.js 安装完成 ✓${NC}" + echo -e " ${GREEN}Node.js installed${NC}" ;; system) INSTALL_NODE="$(which node)" INSTALL_NPM="$(which npm)" - echo -e " ${GREEN}使用系统 Node.js ✓${NC}" + echo -e " ${GREEN}Using the system Node.js${NC}" ;; download) - echo -e " ${CYAN}从国内镜像下载 Node.js $NODE_VER...${NC}" + echo -e " ${CYAN}Downloading Node.js $NODE_VER...${NC}" PLATFORM_NAME="darwin-$ARCH" TARBALL="node-${NODE_VER}-${PLATFORM_NAME}.tar.gz" URL="${NODE_MIRROR}/${NODE_VER}/${TARBALL}" @@ -139,26 +139,26 @@ case $USE_NODE in chmod +x "$NODE_INSTALL_DIR/bin/node" INSTALL_NODE="$NODE_INSTALL_DIR/bin/node" INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm" - echo -e " ${GREEN}Node.js 下载安装完成 ✓${NC}" + echo -e " ${GREEN}Node.js installed${NC}" ;; esac echo "" # ---- Step 4: Copy/Download OpenClaw ---- -echo -e " ${BOLD}[4/4] 安装 OpenClaw...${NC}" +echo -e " ${BOLD}[4/4] Installing OpenClaw${NC}" CORE_INSTALL_DIR="$INSTALL_TARGET/core" case $USE_OPENCLAW in usb) - echo -e " ${CYAN}从 U 盘复制 OpenClaw + 插件...${NC}" + echo -e " ${CYAN}Copying OpenClaw and its plugins from the drive${NC}" mkdir -p "$CORE_INSTALL_DIR" cp -R "$APP_DIR/core/"* "$CORE_INSTALL_DIR/" - echo -e " ${GREEN}OpenClaw 安装完成 ✓${NC}" + echo -e " ${GREEN}OpenClaw installed${NC}" ;; download) - echo -e " ${CYAN}从国内镜像下载 OpenClaw...${NC}" + echo -e " ${CYAN}Downloading OpenClaw${NC}" mkdir -p "$CORE_INSTALL_DIR" cat > "$CORE_INSTALL_DIR/package.json" << 'PKGEOF' { @@ -173,7 +173,7 @@ PKGEOF cd "$CORE_INSTALL_DIR" "$INSTALL_NODE" "$INSTALL_NPM" install --registry="$MIRROR" 2>&1 | tail -3 "$INSTALL_NODE" "$INSTALL_NPM" install @sliverp/qqbot@latest --registry="$MIRROR" 2>&1 | tail -2 - echo -e " ${GREEN}OpenClaw 下载安装完成 ✓${NC}" + echo -e " ${GREEN}OpenClaw installed${NC}" ;; esac @@ -198,7 +198,7 @@ done # ---- Create launch script ---- cat > "$INSTALL_TARGET/start.command" << 'STARTEOF' #!/bin/bash -DIR="$(cd "$(dirname "$0")" && pwd)" +DIR="$(cd "$(dirname "$0")/.." && pwd)" ARCH=$(uname -m) NODE_PLATFORM="node-mac-$( [ "$ARCH" = "arm64" ] && echo "arm64" || echo "x64" )" @@ -240,18 +240,18 @@ echo "" INSTALL_SIZE=$(du -sh "$INSTALL_TARGET" | cut -f1) echo -e " ${GREEN}${BOLD}╔══════════════════════════════════════╗" -echo -e " ║ ✅ 安装成功! ║" +echo -e " ║ Installed. ║" echo -e " ╚══════════════════════════════════════╝${NC}" echo "" -echo -e " ${BOLD}安装位置:${NC} $INSTALL_TARGET" -echo -e " ${BOLD}大小:${NC} $INSTALL_SIZE" +echo -e " ${BOLD}Location:${NC} $INSTALL_TARGET" +echo -e " ${BOLD}Size:${NC} $INSTALL_SIZE" echo "" -echo -e " ${BOLD}启动方式:${NC}" -echo -e " 双击 ${CYAN}$INSTALL_TARGET/start.command${NC}" -echo -e " 或终端运行: ${CYAN}bash ~/.uclaw/start.command${NC}" +echo -e " ${BOLD}To start it:${NC}" +echo -e " Double-click ${CYAN}$INSTALL_TARGET/start.command${NC}" +echo -e " or run: ${CYAN}bash ~/.uclaw/start.command${NC}" echo "" -echo -e " ${BOLD}首次使用:${NC}" -echo -e " 启动后浏览器自动打开配置页面" -echo -e " 选择 AI 模型 → 填写 API Key → 开始用" +echo -e " ${BOLD}First time:${NC}" +echo -e " Settings opens in your browser by itself" +echo -e " Paste an API key and you are ready" echo "" -read -p " 按回车关闭..." +read -p " Press Enter to close…" diff --git a/portable/Mac-IntranetFix.command b/portable/advanced/Mac-IntranetFix.command similarity index 77% rename from portable/Mac-IntranetFix.command rename to portable/advanced/Mac-IntranetFix.command index 99e02da..00baacb 100755 --- a/portable/Mac-IntranetFix.command +++ b/portable/advanced/Mac-IntranetFix.command @@ -4,7 +4,7 @@ # 双击运行:代理env + 直连可达 + 真发一条对话 # ============================================================ -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$UCLAW_DIR/app" CONFIG_FILE="$UCLAW_DIR/data/.openclaw/openclaw.json" @@ -17,8 +17,8 @@ esac # 退而求其次:用系统 node if [ ! -x "$NODE_BIN" ]; then NODE_BIN="$(command -v node)"; fi if [ -z "$NODE_BIN" ] || [ ! -x "$NODE_BIN" ]; then - echo " [错误] 找不到 Node 运行环境。请先正常启动一次 U-Claw。" - read -p " 按回车关闭..." + echo " Node.js is missing. Start U-Claw once first, then run this." + read -p " Press Enter to close." exit 1 fi @@ -28,6 +28,6 @@ xattr -rd com.apple.quarantine "$UCLAW_DIR" 2>/dev/null || true "$NODE_BIN" "$UCLAW_DIR/lib/intranet-check.mjs" "$CONFIG_FILE" echo "" -echo " 把整个窗口截图发给技术支持即可。" +echo " Screenshot this whole window if you need to send it to someone." echo "" -read -p " 按回车关闭..." +read -p " Press Enter to close." diff --git a/portable/Mac-LocalModel.command b/portable/advanced/Mac-LocalModel.command similarity index 80% rename from portable/Mac-LocalModel.command rename to portable/advanced/Mac-LocalModel.command index c8b530a..1b759c6 100755 --- a/portable/Mac-LocalModel.command +++ b/portable/advanced/Mac-LocalModel.command @@ -4,7 +4,7 @@ # 双击运行:命令行配 Ollama / newapi 并当场实测(不碰网页设置) # ============================================================ -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$UCLAW_DIR/app" CONFIG_FILE="$UCLAW_DIR/data/.openclaw/openclaw.json" @@ -16,8 +16,8 @@ case "$ARCH" in esac if [ ! -x "$NODE_BIN" ]; then NODE_BIN="$(command -v node)"; fi if [ -z "$NODE_BIN" ] || [ ! -x "$NODE_BIN" ]; then - echo " [错误] 找不到 Node 运行环境。请先正常启动一次 U-Claw。" - read -p " 按回车关闭..." + echo " Node.js is missing. Start U-Claw once first, then run this." + read -p " Press Enter to close." exit 1 fi @@ -26,4 +26,4 @@ xattr -rd com.apple.quarantine "$UCLAW_DIR" 2>/dev/null || true "$NODE_BIN" "$UCLAW_DIR/lib/setup-local-model.mjs" "$CONFIG_FILE" echo "" -read -p " 按回车关闭..." +read -p " Press Enter to close." diff --git a/portable/Mac-Menu.command b/portable/advanced/Mac-Menu.command similarity index 54% rename from portable/Mac-Menu.command rename to portable/advanced/Mac-Menu.command index 56e2501..7d2aef9 100755 --- a/portable/Mac-Menu.command +++ b/portable/advanced/Mac-Menu.command @@ -2,7 +2,7 @@ # U-Claw Menu - Portable AI Agent # macOS version -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$UCLAW_DIR/app" # Migration shim: rename old core-mac to core for existing USB users @@ -60,66 +60,66 @@ run_oc() { show_menu() { clear local NODE_VER=$("$NODE_BIN" --version 2>/dev/null || echo "N/A") - local CFG_STATUS="${RED}未配置${NC}" - [ -f "$CONFIG_PATH" ] && CFG_STATUS="${GREEN}已配置${NC}" + local CFG_STATUS="${RED}not set up${NC}" + [ -f "$CONFIG_PATH" ] && CFG_STATUS="${GREEN}ready${NC}" echo "" echo -e " ${CYAN}${BOLD}╔══════════════════════════════════════╗" - echo -e " ║ U-Claw 虾盘 v1.1 ║" + echo -e " ║ U-Claw v1.1 ║" echo -e " ║ Portable AI Agent ║" echo -e " ╚══════════════════════════════════════╝${NC}" echo "" - echo -e " Node: ${GREEN}${NODE_VER}${NC} 配置: ${CFG_STATUS}" + echo -e " Node: ${GREEN}${NODE_VER}${NC} Model: ${CFG_STATUS}" echo "" - echo -e " ${WHITE}${BOLD}── 配置 ──────────────────────────────${NC}" - echo -e " ${GREEN}[1]${NC} 配置向导(选模型、填 API Key)" - echo -e " ${GREEN}[2]${NC} 打开网页控制台" + echo -e " ${WHITE}${BOLD}-- Setup ---------------------------------${NC}" + echo -e " ${GREEN}[1]${NC} Set up a model and paste your key" + echo -e " ${GREEN}[2]${NC} Open Settings in the browser" echo "" - echo -e " ${WHITE}${BOLD}── 聊天平台 ──────────────────────────${NC}" - echo -e " ${GREEN}[3]${NC} 接入 QQ 机器人(推荐,1分钟搞定)" - echo -e " ${GREEN}[4]${NC} 接入其他平台(飞书/Telegram/微信)" + echo -e " ${WHITE}${BOLD}-- Chat apps -----------------------------${NC}" + echo -e " ${GREEN}[3]${NC} Connect WhatsApp / Telegram / Slack / Discord" + echo -e " ${GREEN}[4]${NC} Connect a chat app used in China" echo "" - echo -e " ${WHITE}${BOLD}── 维护 ──────────────────────────────${NC}" - echo -e " ${GREEN}[5]${NC} 诊断修复" - echo -e " ${GREEN}[6]${NC} 备份配置" - echo -e " ${GREEN}[7]${NC} 恢复备份" - echo -e " ${GREEN}[8]${NC} 系统信息" + echo -e " ${WHITE}${BOLD}-- Maintenance ---------------------------${NC}" + echo -e " ${GREEN}[5]${NC} Check and fix problems" + echo -e " ${GREEN}[6]${NC} Back up your settings" + echo -e " ${GREEN}[7]${NC} Restore a backup" + echo -e " ${GREEN}[8]${NC} System information" echo "" - echo -e " ${WHITE}${BOLD}── 高级维护 ──────────────────────────${NC}" - echo -e " ${GREEN}[9]${NC} 杀死残留进程" - echo -e " ${GREEN}[10]${NC} 查看日志" - echo -e " ${GREEN}[11]${NC} 恢复出厂设置" - echo -e " ${GREEN}[12]${NC} 卸载" - echo -e " ${GREEN}[13]${NC} 检查更新" - echo -e " ${GREEN}[14]${NC} 清理空间" - echo -e " ${GREEN}[15]${NC} 插件管理" + echo -e " ${WHITE}${BOLD}-- Advanced ------------------------------${NC}" + echo -e " ${GREEN}[9]${NC} Stop leftover processes" + echo -e " ${GREEN}[10]${NC} View logs" + echo -e " ${GREEN}[11]${NC} Reset to factory settings" + echo -e " ${GREEN}[12]${NC} Uninstall" + echo -e " ${GREEN}[13]${NC} Check for updates" + echo -e " ${GREEN}[14]${NC} Free up space" + echo -e " ${GREEN}[15]${NC} Plugins" echo "" - echo -e " ${DIM}[0] 退出${NC}" + echo -e " ${DIM}[0] Quit${NC}" echo "" } # [1] Config wizard do_config() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 配置向导 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Set up a model ---${NC}" echo "" - echo -e " ${WHITE}国产模型选择提示:${NC}" + echo -e " ${WHITE}Picking a provider in the wizard:${NC}" echo "" - echo -e " DeepSeek → 选 Custom Provider" + echo -e " DeepSeek → choose Custom Provider" echo -e " URL: https://api.deepseek.com/v1" - echo -e " 模型: deepseek-v4-flash" - echo -e " Kimi → 选 Moonshot AI" - echo -e " 通义千问 → 选 Qwen" - echo -e " 豆包 → 选 Volcano Engine" + echo -e " model: deepseek-v4-flash" + echo -e " Kimi → choose Moonshot AI" + echo -e " Qwen -> choose Qwen" + echo -e " Doubao -> choose Volcano Engine" echo "" - read -p " 按回车启动配置向导..." + read -p " Press Enter to start the wizard…" run_oc onboard } # [2] Web dashboard do_dashboard() { echo "" - echo -e " ${CYAN}启动网页控制台...${NC}" + echo -e " ${CYAN}Opening Settings…${NC}" echo "" cd "$CORE_DIR" @@ -128,7 +128,7 @@ do_dashboard() { while lsof -i :$PORT >/dev/null 2>&1; do PORT=$((PORT + 1)) if [ $PORT -gt 18799 ]; then - echo -e " ${RED}端口 18789-18799 全被占用${NC}" + echo -e " ${RED}Ports 18789-18799 are all in use — U-Claw may already be running${NC}" return fi done @@ -142,79 +142,79 @@ do_dashboard() { sleep 0.5 if curl --noproxy '*' -s -o /dev/null "http://127.0.0.1:$PORT/" 2>/dev/null; then local URL="http://127.0.0.1:$PORT/#token=$TOKEN" - echo -e " ${GREEN}控制台: $URL${NC}" + echo -e " ${GREEN}Settings: $URL${NC}" open "$URL" 2>/dev/null break fi done - echo " 关闭此窗口会停止服务" + echo " Closing this window stops U-Claw" wait $PID } # [3] QQ Bot (pre-installed) do_qq() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 接入 QQ 机器人 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Connect a QQ bot ---${NC}" echo "" - echo -e " ${GREEN}QQ 插件已预装!只需输入 AppID 和 AppSecret。${NC}" + echo -e " ${GREEN}The QQ plugin is already installed. You only need the AppID and AppSecret.${NC}" echo "" - echo " 获取方式: 访问 q.qq.com → 创建机器人" + echo " Get them at q.qq.com by creating a bot" echo "" read -p " AppID: " QQ_ID read -p " AppSecret: " QQ_SECRET echo "" if [ -z "$QQ_ID" ] || [ -z "$QQ_SECRET" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi run_oc channels add --channel qqbot --token "${QQ_ID}:${QQ_SECRET}" 2>&1 || true echo "" - read -p " 你的 QQ 号(设白名单,留空跳过): " QQ_ALLOW + read -p " Your QQ number, to allow only you (blank to skip): " QQ_ALLOW if [ -n "$QQ_ALLOW" ]; then run_oc config set channels.qqbot.allowFrom "\"${QQ_ALLOW}\"" 2>&1 || true - echo -e " ${GREEN}白名单已设置${NC}" + echo -e " ${GREEN}Allow-list set${NC}" fi echo "" - echo -e " ${GREEN}QQ 机器人配置完成!重启网关后生效。${NC}" + echo -e " ${GREEN}QQ bot configured. Restart U-Claw for it to take effect.${NC}" } # [4] Other platforms do_platforms() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 其他聊天平台 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Other chat apps ---${NC}" echo "" - echo -e " ${GREEN}[a]${NC} 飞书 Feishu — 企业首选" - echo -e " ${GREEN}[b]${NC} Telegram — 海外推荐" - echo -e " ${GREEN}[c]${NC} 微信(社区插件) — iPad协议" + echo -e " ${GREEN}[a]${NC} Feishu / Lark" + echo -e " ${GREEN}[b]${NC} Telegram" + echo -e " ${GREEN}[c]${NC} WeChat (community plugin)" echo -e " ${GREEN}[d]${NC} Discord" echo "" - read -p " 选择 (a-d): " -n 1 CH + read -p " Choose (a-d): " -n 1 CH echo "" echo "" case $CH in - a) echo " 飞书: 访问 open.feishu.cn/app 创建应用" ;; - b) echo " Telegram: 找 @BotFather 创建机器人" ;; + a) echo " Feishu: create an app at open.feishu.cn/app" ;; + b) echo " Telegram: create a bot with @BotFather" ;; c) - echo -e " ${YELLOW}安装微信插件...${NC}" + echo -e " ${YELLOW}Installing the WeChat plugin…${NC}" run_oc plugins install @icesword760/openclaw-wechat 2>&1 || true ;; - d) echo " Discord: 访问 discord.com/developers/applications" ;; - *) echo " 无效选择" ;; + d) echo " Discord: create an app at discord.com/developers/applications" ;; + *) echo " Not a valid choice" ;; esac echo "" - echo " 配置完成后运行配置向导 [1] 绑定平台" + echo " Then run [1] to finish connecting it" } # [5] Doctor do_doctor() { echo "" - echo -e " ${CYAN}━━━ 诊断修复 ━━━${NC}" + echo -e " ${CYAN}━━━ Check and fix problems ━━━${NC}" echo "" - run_oc doctor --repair 2>&1 || echo -e " ${YELLOW}诊断命令执行失败${NC}" + run_oc doctor --repair 2>&1 || echo -e " ${YELLOW}The check could not run${NC}" } # [6] Backup @@ -228,8 +228,8 @@ do_backup() { [ -d "$DATA_DIR/memory" ] && cp -R "$DATA_DIR/memory" "$BK/" 2>/dev/null && echo -e " ${GREEN} + memory/${NC}" echo "" - echo -e " ${GREEN}备份完成: $BK${NC}" - echo " 大小: $(du -sh "$BK" | cut -f1)" + echo -e " ${GREEN}Backed up to $BK${NC}" + echo " Size: $(du -sh "$BK" | cut -f1)" } # [7] Restore @@ -237,48 +237,48 @@ do_restore() { echo "" local BK_DIR="$DATA_DIR/backups" if [ ! -d "$BK_DIR" ] || [ -z "$(ls -A "$BK_DIR" 2>/dev/null)" ]; then - echo -e " ${YELLOW}没有备份${NC}" + echo -e " ${YELLOW}No backups yet${NC}" return fi - echo " 可用备份:" + echo " Available backups:" local i=1 for b in "$BK_DIR"/*/; do echo -e " ${GREEN}[$i]${NC} $(basename "$b") ($(du -sh "$b" | cut -f1))" i=$((i+1)) done echo "" - read -p " 选择编号: " NUM + read -p " Which one? " NUM local j=1 for b in "$BK_DIR"/*/; do if [ "$j" = "$NUM" ]; then - [ -f "$b/openclaw.json" ] && cp "$b/openclaw.json" "$CONFIG_PATH" && echo -e " ${GREEN} + 配置已恢复${NC}" - [ -d "$b/memory" ] && cp -R "$b/memory" "$DATA_DIR/" && echo -e " ${GREEN} + 记忆已恢复${NC}" - echo -e " ${GREEN}恢复完成${NC}" + [ -f "$b/openclaw.json" ] && cp "$b/openclaw.json" "$CONFIG_PATH" && echo -e " ${GREEN} + settings restored${NC}" + [ -d "$b/memory" ] && cp -R "$b/memory" "$DATA_DIR/" && echo -e " ${GREEN} + memory restored${NC}" + echo -e " ${GREEN}Restored${NC}" return fi j=$((j+1)) done - echo -e " ${RED}无效选择${NC}" + echo -e " ${RED}Not a valid choice${NC}" } # [8] System info do_sysinfo() { echo "" - echo " 系统: $(sw_vers -productName 2>/dev/null) $(sw_vers -productVersion 2>/dev/null)" + echo " System: $(sw_vers -productName 2>/dev/null) $(sw_vers -productVersion 2>/dev/null)" echo " CPU: $(uname -m)" - echo " 内存: $(sysctl -n hw.memsize 2>/dev/null | awk '{printf "%.0f GB", $1/1024/1024/1024}')" + echo " Memory: $(sysctl -n hw.memsize 2>/dev/null | awk '{printf "%.0f GB", $1/1024/1024/1024}')" echo " Node: $("$NODE_BIN" --version 2>/dev/null)" - echo " 路径: $UCLAW_DIR" - echo " 大小: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)" - echo " 磁盘: $(df -h "$UCLAW_DIR" | tail -1 | awk '{print $4 " 可用"}')" + echo " Path: $UCLAW_DIR" + echo " Size: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)" + echo " Disk: $(df -h "$UCLAW_DIR" | tail -1 | awk '{print $4 " free"}')" } # Main loop while true; do show_menu - read -p " 请选择 [0-15]: " CHOICE + read -p " Choose [0-15]: " CHOICE echo "" case $CHOICE in @@ -297,10 +297,10 @@ while true; do 13) do_update ;; 14) do_cleanup ;; 15) do_plugins ;; - 0) echo -e " ${CYAN}再见!${NC}"; exit 0 ;; - *) echo -e " ${RED}无效选择${NC}" ;; + 0) echo -e " ${CYAN}Bye.${NC}"; exit 0 ;; + *) echo -e " ${RED}Not a valid choice${NC}" ;; esac echo "" - read -p " 按回车返回..." + read -p " Press Enter to go back…" done diff --git a/portable/Mac-OpenClaw-CLI.command b/portable/advanced/Mac-OpenClaw-CLI.command similarity index 83% rename from portable/Mac-OpenClaw-CLI.command rename to portable/advanced/Mac-OpenClaw-CLI.command index 86bacdd..a27a411 100644 --- a/portable/Mac-OpenClaw-CLI.command +++ b/portable/advanced/Mac-OpenClaw-CLI.command @@ -2,10 +2,10 @@ # ============================================================ # U-Claw - Interactive CLI (macOS) # 进阶用户:双击打开一个配置好环境的终端,可直接敲 openclaw 命令。 -# 复用与 Mac-Start.command 一致的便携环境(盘内 Node + 盘内数据)。 +# 复用与 START HERE - Mac.command 一致的便携环境(盘内 Node + 盘内数据)。 # ============================================================ -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$UCLAW_DIR/app" CORE_DIR="$APP_DIR/core" DATA_DIR="$UCLAW_DIR/data" @@ -13,7 +13,7 @@ STATE_DIR="$DATA_DIR/.openclaw" RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'; NC='\033[0m' -# Detect CPU & set runtime(与 Mac-Start.command 一致) +# Detect CPU & set runtime(与 START HERE - Mac.command 一致) ARCH=$(uname -m) if [ "$ARCH" = "arm64" ]; then NODE_DIR="$APP_DIR/runtime/node-mac-arm64" @@ -27,12 +27,12 @@ fi NODE_BIN="$NODE_DIR/bin/node" if [ ! -f "$NODE_BIN" ]; then - echo -e " ${RED}Node.js runtime not found.${NC} Run Mac-Start.command once first." + echo -e " ${RED}Node.js runtime not found.${NC} Run START HERE - Mac.command once first." read -p " Press Enter to exit..." exit 1 fi if [ ! -x "$CORE_DIR/node_modules/.bin/openclaw" ]; then - echo -e " ${RED}OpenClaw not installed yet.${NC} Run Mac-Start.command once first." + echo -e " ${RED}OpenClaw not installed yet.${NC} Run START HERE - Mac.command once first." read -p " Press Enter to exit..." exit 1 fi diff --git a/portable/Mac-OpenClaw-Doctor.command b/portable/advanced/Mac-OpenClaw-Doctor.command similarity index 71% rename from portable/Mac-OpenClaw-Doctor.command rename to portable/advanced/Mac-OpenClaw-Doctor.command index 433fe12..3e601d1 100755 --- a/portable/Mac-OpenClaw-Doctor.command +++ b/portable/advanced/Mac-OpenClaw-Doctor.command @@ -5,7 +5,7 @@ # 只读:故意不传 --fix/--repair/--force。卡住可按 Ctrl+C 安全中断。 # ============================================================ -UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)" +UCLAW_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$UCLAW_DIR/app" CORE_DIR="$APP_DIR/core" DATA_DIR="$UCLAW_DIR/data" @@ -20,13 +20,13 @@ case "$ARCH" in esac if [ ! -x "$NODE_BIN" ]; then NODE_BIN="$(command -v node)"; fi if [ -z "$NODE_BIN" ] || [ ! -x "$NODE_BIN" ]; then - echo " [错误] 找不到 Node 运行环境。" - read -p " 按回车关闭..." + echo " Node.js is missing from this drive." + read -p " Press Enter to close." exit 1 fi if [ ! -f "$OPENCLAW_MJS" ]; then - echo " [错误] 找不到 OpenClaw 运行时 (app/core/node_modules/openclaw)。" - read -p " 按回车关闭..." + echo " OpenClaw is missing from this drive." + read -p " Press Enter to close." exit 1 fi @@ -39,14 +39,14 @@ xattr -rd com.apple.quarantine "$UCLAW_DIR" 2>/dev/null || true echo "" echo " ========================================" -echo " OpenClaw Doctor (官方体检, 英文, 较慢)" +echo " OpenClaw Doctor — the upstream check. Thorough, and slow." echo " ========================================" -echo " 请确保 U-Claw 已经在运行。卡住可 Ctrl+C 中断(只读,安全)。" -echo " 想要快速的中文体检请改用 Mac-IntranetFix.command。" +echo " U-Claw needs to be running. Ctrl+C is safe at any point — this only reads." +echo " For a network-focused check, use Mac-IntranetFix.command instead." echo "" -read -p " 按回车开始..." +read -p " Press Enter to start." "$NODE_BIN" "$OPENCLAW_MJS" doctor --non-interactive echo "" -read -p " 按回车关闭..." +read -p " Press Enter to close." diff --git a/portable/OpenClaw-CLI.bat b/portable/advanced/OpenClaw-CLI.bat similarity index 83% rename from portable/OpenClaw-CLI.bat rename to portable/advanced/OpenClaw-CLI.bat index d920178..6bac02c 100644 --- a/portable/OpenClaw-CLI.bat +++ b/portable/advanced/OpenClaw-CLI.bat @@ -3,9 +3,9 @@ chcp 65001 >nul 2>&1 title U-Claw Interactive CLI REM 进阶用户:打开一个已配置好环境变量的命令行,可直接敲 openclaw 命令。 -REM 复用与 Windows-Start.bat 一致的便携环境(盘内 Node + 盘内数据)。 +REM 复用与 START HERE - Windows.bat 一致的便携环境(盘内 Node + 盘内数据)。 -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "APP_DIR=%UCLAW_DIR%app" set "CORE_DIR=%APP_DIR%\core" set "DATA_DIR=%UCLAW_DIR%data" @@ -22,14 +22,14 @@ set "PATH=%NODE_DIR%;%CORE_DIR%\node_modules\.bin;%PATH%" if not exist "%NODE_BIN%" ( echo [ERROR] Node.js runtime not found - echo Please run Windows-Start.bat once first to set up the runtime. + echo Please run START HERE - Windows.bat once first to set up the runtime. pause exit /b 1 ) if not exist "%CORE_DIR%\node_modules\.bin\openclaw.cmd" ( echo [ERROR] OpenClaw not installed yet - echo Please run Windows-Start.bat once first. + echo Please run START HERE - Windows.bat once first. pause exit /b 1 ) diff --git a/portable/OpenClaw-Doctor.bat b/portable/advanced/OpenClaw-Doctor.bat similarity index 95% rename from portable/OpenClaw-Doctor.bat rename to portable/advanced/OpenClaw-Doctor.bat index 19963f3..ff7ec47 100644 --- a/portable/OpenClaw-Doctor.bat +++ b/portable/advanced/OpenClaw-Doctor.bat @@ -4,11 +4,11 @@ title U-Claw - OpenClaw Doctor (advanced) setlocal REM Official OpenClaw health check (English, advanced users). -REM NOTE: run this AFTER U-Claw is already running (double-click Windows-Start.bat +REM NOTE: run this AFTER U-Claw is already running (double-click START HERE - Windows.bat REM first), otherwise doctor stalls while probing a gateway that is not up yet. REM Read-only: we deliberately do NOT pass --fix/--repair/--force. -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "APP_DIR=%UCLAW_DIR%app" set "CORE_DIR=%APP_DIR%\core" set "DATA_DIR=%UCLAW_DIR%data" diff --git a/portable/advanced/README.md b/portable/advanced/README.md new file mode 100644 index 0000000..7d68002 --- /dev/null +++ b/portable/advanced/README.md @@ -0,0 +1,35 @@ +# advanced/ + +Everything here used to sit in the drive's root folder. Twenty-three clickable +files greeted anyone who plugged the drive in, and the first thing a +non-technical user had to do was work out which of them applied to their +computer — before anything had even run. + +The root now holds three things: the two `START HERE` files and a short guide. +Everything else lives here. + +| File | What it is | +|---|---| +| `Windows-Menu.bat` · `Mac-Menu.command` | Menu of every tool below | +| `Windows-Diagnose.bat` · `Mac-Diagnose.command` | Health check, collects logs for a bug report | +| `OpenClaw-Doctor.bat` · `Mac-OpenClaw-Doctor.command` | Read-only diagnosis from OpenClaw itself | +| `OpenClaw-CLI.bat` · `Mac-OpenClaw-CLI.command` | Drop into the raw `openclaw` CLI | +| `Windows-Install.bat` · `Mac-Install.command` | Copy the drive's contents onto this computer | +| `Windows-IntranetFix.bat` · `Mac-IntranetFix.command` | Fix a corporate proxy blocking your model endpoint | +| `Windows-LocalModel.bat` · `Mac-LocalModel.command` | Set up an offline local model | +| `setup.sh` · `setup.bat` · `setup.ps1` | Developer build: fetch Node.js + OpenClaw into `../app/` | +| `Config.html` | Redirect to Settings, kept for older links | +| `U-Claw.html` · `SkillHub.html` | Reference pages | + +## If you move a script out of here + +They all resolve the drive root as "one level up" from wherever they sit. Running +one from somewhere else will not find `app/` or `data/`. + +## Naming + +The entry points are `START HERE - Windows.bat` and `START HERE - Mac.command`, +with a hyphen rather than brackets. `cmd.exe` treats `)` as the end of an +`IF (...)` block, so a filename containing brackets breaks every `echo` that +mentions it inside a block — which is the flash-exit class of bug that +`tests/windows-launchers.test.mjs` guards against. The hyphen avoids it entirely. diff --git a/portable/advanced/SkillHub.html b/portable/advanced/SkillHub.html new file mode 100644 index 0000000..1e818a2 --- /dev/null +++ b/portable/advanced/SkillHub.html @@ -0,0 +1,125 @@ + + + + + +U-Claw Skills + + + + + + + + +
+

U-Claw Skills

+

These are on this drive already. Just ask for what you want — you do not have to name the skill.

+ +
+
+ + +
+

Skills live in the skills/ folder on this drive. Dropping a SKILL.md in there adds one.

+
+
+ + + + diff --git a/portable/U-Claw.html b/portable/advanced/U-Claw.html similarity index 50% rename from portable/U-Claw.html rename to portable/advanced/U-Claw.html index 0a6440a..a189b86 100644 --- a/portable/U-Claw.html +++ b/portable/advanced/U-Claw.html @@ -1,9 +1,9 @@ - + -U-Claw 虾盘 - 启动导航 +U-Claw — Start here + + +
-

🦞 U-Claw 虾盘 v1.1

-

Portable AI Agent — 插上就能用的 AI 助手

+

🦞 U-Claw v1.1

+

Portable AI agent — plug in and go

- OpenClaw 未运行 - + U-Claw is not running +
@@ -75,29 +78,29 @@ body { font-family: -apple-system, "Microsoft YaHei", sans-serif; background: #0
-

🚀 快速启动

+

🚀 Quick start

1
-
双击 Mac-Start.command
+
Double-click START HERE - Mac.command
2
-
首次运行自动打开配置页面,选模型、填 API Key 即可
+
Settings opens by itself the first time — pick a model and paste your key.
-

⚠️ 首次运行如果提示"无法验证开发者":右键点击 → 打开

-

📝 也可以直接双击 Config.html 打开中文配置页面

+

⚠️ If macOS says the developer cannot be verified: right-click the file, then choose Open.

+

📝 You can also double-click Config.html — it takes you to the settings page.

-

⚙️ 全部功能(配置/诊断/备份)

-

双击 Mac-Menu.command 打开全功能菜单:

+

⚙️ Everything else

+

Double-click Mac-Menu.command for the full menu:

-

中文配置页面

Config.html — 选模型、填 Key、接 QQ

-

QQ Bot 接入

已预装,只需 AppID + Secret

-

诊断修复

openclaw doctor 一键检测

-

备份恢复

配置和记忆一键备份

-

技能浏览

52 个预装技能

-

系统信息

版本、端口、运行状态

+

Settings

Model, key and chat apps

+

Check-up

Finds and fixes common problems

+

Backup

Save settings and memory in one click

+

Skills

Browse what U-Claw can do

+

System info

Version, port, running state

+

Command line

For advanced use

@@ -105,52 +108,52 @@ body { font-family: -apple-system, "Microsoft YaHei", sans-serif; background: #0
-

🚀 快速启动

+

🚀 Quick start

1
-
双击 Windows-Start.bat
+
Double-click START HERE - Windows.bat
2
-
首次运行自动打开配置页面,选模型、填 API Key 即可
+
Settings opens by itself the first time — pick a model and paste your key.
-

⚠️ 如果弹出安全警告:点击"更多信息" → "仍要运行"

+

⚠️ If Windows shows a security warning: click More info, then Run anyway.

-

⚙️ 全部功能(配置/诊断/备份)

-

双击 Windows-Menu.bat 打开全功能菜单:

+

⚙️ Everything else

+

Double-click Windows-Menu.bat for the full menu:

-

配置向导

选模型、填 API Key、选平台

-

QQ Bot 接入

腾讯官方,3条命令搞定

-

诊断修复

openclaw doctor 一键检测

-

备份恢复

配置和记忆一键备份

-

技能浏览

52 个预装技能

-

镜像配置

npm 淘宝镜像

+

Settings

Model, key and chat apps

+

Check-up

Finds and fixes common problems

+

Backup

Save settings and memory in one click

+

Skills

Browse what U-Claw can do

+

System info

Version, port, running state

+

Command line

For advanced use

-
🤖 支持的 AI 模型(国内免翻墙)
+
🤖 Models you can use
-

DeepSeek

编程首选,性价比最高

-

Kimi K2.5

256K 上下文,长文档

-

通义千问 Qwen

免费额度大

-

智谱 GLM

学术、中文 NLP

-

MiniMax

语音、多模态

-

豆包 Doubao

字节跳动,火山引擎

+

Claude

Best all-rounder

+

GPT

Most widely used

+

Gemini

Free tier, easiest signup

+

SEA-LION

Malay, Tamil and Singlish

+

Local model

Offline · nothing leaves this machine

+

More

Others are listed in Settings

-
📖 更多资料
+
📖 More
-

📖 帮助文档

完整使用指南

-

🎯 技能市场

39 个精选技能

-

💬 联系我们

微信: hecare888

-

🌐 官网

u-claw.org

+

📖 Getting started

The three-step walkthrough

+

🎯 Skills

Browse what U-Claw can do

+

💬 Contact

help@u-claw.org

+

🌐 Website

u-claw.org

@@ -195,13 +198,13 @@ async function checkStatus() { } if (found) { document.getElementById('statusDot').className = 'status-dot on'; - document.getElementById('statusText').textContent = 'OpenClaw 运行中 (端口 ' + found + ')'; + document.getElementById('statusText').textContent = window.UClawI18n.t('nav.status_on', { port: found }); var link = document.getElementById('statusLink'); link.style.display = 'inline'; link.href = 'http://127.0.0.1:' + found + '/#token=uclaw'; } else { document.getElementById('statusDot').className = 'status-dot off'; - document.getElementById('statusText').textContent = 'OpenClaw 未运行 — 请先双击启动脚本'; + document.getElementById('statusText').textContent = window.UClawI18n.t('nav.status_off_hint'); document.getElementById('statusLink').style.display = 'none'; } } diff --git a/portable/Windows-Diagnose.bat b/portable/advanced/Windows-Diagnose.bat similarity index 72% rename from portable/Windows-Diagnose.bat rename to portable/advanced/Windows-Diagnose.bat index 04485fe..2b31d4e 100644 --- a/portable/Windows-Diagnose.bat +++ b/portable/advanced/Windows-Diagnose.bat @@ -1,9 +1,9 @@ -@echo off +@echo off setlocal EnableDelayedExpansion chcp 65001 >nul 2>&1 title U-Claw - Diagnostic Tool -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "LOG_FILE=%UCLAW_DIR%diagnostic-log.txt" echo. @@ -27,18 +27,18 @@ for /f "tokens=2 delims==" %%v in ('wmic os get OSArchitecture /format:list 2^>n echo. >> "%LOG_FILE%" REM 1. Check Node.js -echo [1/7] 检查 Node.js 运行环境... +echo [1/7] Checking Node.js set "NODE_BIN=%UCLAW_DIR%app\runtime\node-win-x64\node.exe" set "ERROR_COUNT=0" if exist "%NODE_BIN%" ( echo [OK] Node.js found >> "%LOG_FILE%" for /f "tokens=*" %%v in ('"%NODE_BIN%" --version 2^>^&1') do ( echo Version: %%v >> "%LOG_FILE%" - echo ✓ Node.js 运行环境: %%v + echo [OK] Node.js: %%v ) ) else ( echo [ERROR] Node.js not found >> "%LOG_FILE%" - echo ✗ Node.js 运行环境: 缺失 + echo [!!] Node.js: missing echo Path: %NODE_BIN% >> "%LOG_FILE%" set /a ERROR_COUNT+=1 ) @@ -47,67 +47,67 @@ REM Migration shim: rename old core-win to core for existing USB users if exist "%UCLAW_DIR%app\core-win" if not exist "%UCLAW_DIR%app\core" ren "%UCLAW_DIR%app\core-win" core REM 2. Check core directory -echo [2/7] 检查依赖目录... +echo [2/7] Checking folders set "CORE_DIR=%UCLAW_DIR%app\core" if exist "%CORE_DIR%" ( echo [OK] core directory exists >> "%LOG_FILE%" - echo ✓ 依赖目录: 正常 + echo [OK] Folders: ok ) else ( echo [ERROR] core directory not found >> "%LOG_FILE%" - echo ✗ 依赖目录: 缺失 + echo [!!] Folders: missing set /a ERROR_COUNT+=1 ) REM 3. Check node_modules -echo [3/7] 检查 npm 依赖包... +echo [3/7] Checking dependencies if exist "%CORE_DIR%\node_modules" ( echo [OK] node_modules exists >> "%LOG_FILE%" - echo ✓ npm 依赖包: 已安装 + echo [OK] Dependencies: installed ) else ( echo [ERROR] node_modules not found >> "%LOG_FILE%" - echo ✗ npm 依赖包: 未安装 + echo [!!] Dependencies: not installed set /a ERROR_COUNT+=1 ) REM 4. Check OpenClaw -echo [4/7] 检查 OpenClaw 核心文件... +echo [4/7] Checking OpenClaw set "OPENCLAW_MJS=%CORE_DIR%\node_modules\openclaw\openclaw.mjs" if exist "%OPENCLAW_MJS%" ( echo [OK] openclaw.mjs found >> "%LOG_FILE%" - echo ✓ OpenClaw 核心: 正常 + echo [OK] OpenClaw: ok ) else ( echo [ERROR] openclaw.mjs not found >> "%LOG_FILE%" - echo ✗ OpenClaw 核心: 缺失 + echo [!!] OpenClaw: missing echo Path: %OPENCLAW_MJS% >> "%LOG_FILE%" set /a ERROR_COUNT+=1 ) REM 5. Check config -echo [5/7] 检查配置文件... +echo [5/7] Checking settings set "STATE_DIR=%UCLAW_DIR%data\.openclaw" if exist "%STATE_DIR%\openclaw.json" ( echo [OK] Config file exists >> "%LOG_FILE%" - echo ✓ 配置文件: 正常 + echo [OK] Settings file: ok REM Check if model is configured findstr /c:"model" "%STATE_DIR%\openclaw.json" >nul 2>&1 if !errorlevel!==0 ( - echo ✓ AI 模型: 已配置 + echo [OK] Model: configured ) else ( - echo ⚠ AI 模型: 未配置(首次使用请先配置) + echo [ ?] Model: not set up yet ) ) else ( echo [WARNING] Config not found >> "%LOG_FILE%" - echo ⚠ 配置文件: 未创建(首次启动会自动创建) + echo [ ?] Settings file: not created yet, U-Claw makes it on first run ) REM 6. Check port availability -echo [6/7] 检查端口占用... +echo [6/7] Checking ports set "PORT_ISSUE=0" for /l %%p in (18789,1,18799) do ( netstat -an | findstr ":%%p " | findstr "LISTENING" >nul 2>&1 if !errorlevel!==0 ( echo [WARNING] Port %%p is in use >> "%LOG_FILE%" - echo ⚠ 端口 %%p: 已被占用 + echo [ ?] Port %%p: in use for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":%%p " ^| findstr "LISTENING"') do ( echo PID: %%a >> "%LOG_FILE%" ) @@ -116,11 +116,11 @@ for /l %%p in (18789,1,18799) do ( ) if "!PORT_ISSUE!"=="0" ( echo [OK] Ports 18789-18799 available >> "%LOG_FILE%" - echo ✓ 端口 18789-18799: 全部可用 + echo [OK] Ports 18789-18799: all free ) REM 7. Test OpenClaw startup -echo [7/7] 测试 OpenClaw 启动... +echo [7/7] Testing OpenClaw echo. >> "%LOG_FILE%" echo Testing OpenClaw startup: >> "%LOG_FILE%" echo ---------------------------------------- >> "%LOG_FILE%" @@ -133,15 +133,15 @@ if exist "%NODE_BIN%" if exist "%OPENCLAW_MJS%" ( cd /d "%CORE_DIR%" for /f "tokens=*" %%v in ('"%NODE_BIN%" "%OPENCLAW_MJS%" --version 2^>^&1') do ( echo %%v >> "%LOG_FILE%" - echo ✓ OpenClaw 启动测试: 通过 (%%v^) + echo [OK] OpenClaw starts: yes (%%v^) ) if !errorlevel! neq 0 ( - echo ✗ OpenClaw 启动测试: 失败 + echo [!!] OpenClaw starts: no echo [ERROR] OpenClaw failed to start >> "%LOG_FILE%" set /a ERROR_COUNT+=1 ) ) else ( - echo ⚠ OpenClaw 启动测试: 跳过(文件缺失) + echo [ ?] OpenClaw starts: skipped, files missing echo [SKIP] Cannot test - required files missing >> "%LOG_FILE%" ) @@ -159,28 +159,28 @@ echo Diagnostic complete. >> "%LOG_FILE%" echo Error count: !ERROR_COUNT! >> "%LOG_FILE%" echo ======================================== -echo 诊断完成 +echo Check complete echo ======================================== echo. if !ERROR_COUNT!==0 ( - echo ✅ 检查结果: 全部正常! - echo 所有必需的组件都已就绪,可以正常使用。 + echo [OK] Everything checks out. + echo Every component U-Claw needs is present. echo. - echo 下一步: - echo - 双击 Windows-Start.bat 启动服务 - echo - 或双击 Config.html 配置 AI 模型 + echo Next: + echo - Double-click START HERE - Windows.bat to run it + echo - Settings opens by itself the first time ) else ( - echo ❌ 检查结果: 发现 !ERROR_COUNT! 个问题 + echo [!!] Found !ERROR_COUNT! problem^(s^). echo. - echo 解决方案: - echo 1. 查看 diagnostic-log.txt 了解详细错误 - echo 2. 尝试重新运行 Windows-Start.bat - echo (会自动安装缺失的依赖) - echo 3. 如问题仍然存在,访问: - echo github.com/dongsheng123132/u-claw + echo What to do: + echo 1. Open diagnostic-log.txt for the details + echo 2. Run START HERE - Windows.bat again + echo it reinstalls anything missing by itself + echo 3. Still stuck? See: + echo gitea.fanghe.it.com/zhenghy/u-claw ) echo. -echo 诊断日志已保存: diagnostic-log.txt +echo Saved a log to diagnostic-log.txt echo. pause diff --git a/portable/Windows-Install.bat b/portable/advanced/Windows-Install.bat similarity index 77% rename from portable/Windows-Install.bat rename to portable/advanced/Windows-Install.bat index 581d0f4..0f55d61 100644 --- a/portable/Windows-Install.bat +++ b/portable/advanced/Windows-Install.bat @@ -1,62 +1,62 @@ -@echo off +@echo off setlocal EnableDelayedExpansion chcp 65001 >nul 2>&1 title U-Claw - Install to Windows echo. echo ======================================== -echo U-Claw 安装到 Windows -echo 从 U 盘离线安装 +echo Install U-Claw on this PC +echo Offline, from the drive echo ======================================== echo. -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "APP_DIR=%UCLAW_DIR%app" set "INSTALL_TARGET=%USERPROFILE%\.uclaw" -set "MIRROR=https://registry.npmmirror.com" -set "NODE_MIRROR=https://npmmirror.com/mirrors/node" +set "MIRROR=https://registry.npmjs.org" +set "NODE_MIRROR=https://nodejs.org/dist" set "NODE_VER=v22.22.1" REM ---- Step 1: Check environment ---- -echo [1/4] 检查环境... +echo [1/4] Checking set "USE_NODE=none" set "USB_NODE=%APP_DIR%\runtime\node-win-x64\node.exe" if exist "%USB_NODE%" ( - for /f "tokens=*" %%v in ('"%USB_NODE%" --version') do echo Node.js: 使用 U 盘内的 %%v + for /f "tokens=*" %%v in ('"%USB_NODE%" --version') do echo Node.js: using the copy on the drive, %%v set "USE_NODE=usb" ) else ( where node >nul 2>&1 if !errorlevel!==0 ( for /f "tokens=*" %%v in ('node --version') do ( - echo Node.js: 检查系统版本 %%v + echo Node.js: checking the system copy, %%v set "SYS_VER=%%v" ) REM Use only supported LTS majors. Newer Current releases can break native deps. for /f "tokens=1 delims=." %%m in ("!SYS_VER:v=!") do set "MAJOR=%%m" if !MAJOR! equ 20 ( - echo Node.js: 使用系统的 !SYS_VER! + echo Node.js: using the system copy, !SYS_VER! set "USE_NODE=system" ) else if !MAJOR! equ 22 ( - echo Node.js: 使用系统的 !SYS_VER! + echo Node.js: using the system copy, !SYS_VER! set "USE_NODE=system" ) else ( - echo Node.js: 系统版本不兼容 ^(!SYS_VER!^), 将使用内置 v22 LTS + echo Node.js: system copy !SYS_VER! is not compatible, using the bundled v22 LTS set "USE_NODE=download" ) ) else ( - echo Node.js: 未安装 + echo Node.js: not installed set "USE_NODE=download" ) ) set "USB_OPENCLAW=%APP_DIR%\core\node_modules\openclaw\openclaw.mjs" if exist "%USB_OPENCLAW%" ( - echo OpenClaw: 使用 U 盘内的 + echo OpenClaw: using the copy on the drive set "USE_OPENCLAW=usb" ) else ( - echo OpenClaw: U 盘内未找到,需要在线下载 + echo OpenClaw: not on the drive, will download it set "USE_OPENCLAW=download" ) @@ -64,10 +64,10 @@ echo. REM ---- Step 2: Check existing ---- if exist "%INSTALL_TARGET%" ( - echo 检测到已有安装: %INSTALL_TARGET% - set /p OVERWRITE=" 覆盖安装?(y/n): " + echo Already installed: %INSTALL_TARGET% + set /p OVERWRITE=" Install over it?(y/n): " if /i not "!OVERWRITE!"=="y" ( - echo 已取消 + echo Cancelled pause exit /b 0 ) @@ -75,7 +75,7 @@ if exist "%INSTALL_TARGET%" ( ) REM ---- Step 3: Create directories ---- -echo [2/4] 创建安装目录... +echo [2/4] Creating folders mkdir "%INSTALL_TARGET%" 2>nul mkdir "%INSTALL_TARGET%\data\.openclaw" 2>nul mkdir "%INSTALL_TARGET%\data\memory" 2>nul @@ -84,20 +84,20 @@ mkdir "%INSTALL_TARGET%\data\logs" 2>nul echo. REM ---- Step 4: Copy/Download Node.js ---- -echo [3/4] 安装 Node.js... +echo [3/4] Installing Node.js if "!USE_NODE!"=="usb" ( - echo 从 U 盘复制 Node.js... + echo Copying Node.js from the drive xcopy /s /e /q /y "%APP_DIR%\runtime\node-win-x64" "%INSTALL_TARGET%\runtime\node-win-x64\" >nul set "INSTALL_NODE=%INSTALL_TARGET%\runtime\node-win-x64\node.exe" set "INSTALL_NPM=%INSTALL_TARGET%\runtime\node-win-x64\npm.cmd" - echo Node.js 安装完成! + echo Node.js Installed! ) else if "!USE_NODE!"=="system" ( set "INSTALL_NODE=node" set "INSTALL_NPM=npm" - echo 使用系统 Node.js + echo Using the system Node.js ) else ( - echo 从国内镜像下载 Node.js %NODE_VER%... + echo Downloading Node.js %NODE_VER% set "NODE_ZIP=node-%NODE_VER%-win-x64.zip" set "NODE_URL=%NODE_MIRROR%/%NODE_VER%/!NODE_ZIP!" echo URL: !NODE_URL! @@ -106,13 +106,13 @@ if "!USE_NODE!"=="usb" ( REM Download using curl (available on Windows 10+) curl -# -L "!NODE_URL!" -o "%TEMP%\!NODE_ZIP!" if !errorlevel! neq 0 ( - echo [ERROR] 下载失败!请检查网络连接 - echo 也可以手动下载: !NODE_URL! + echo [ERROR] Download failed. Check your network connection. + echo You can also download it yourself: !NODE_URL! pause exit /b 1 ) - echo 解压中... + echo Unpacking mkdir "%INSTALL_TARGET%\runtime\node-win-x64" 2>nul powershell -command "Expand-Archive -Path '%TEMP%\!NODE_ZIP!' -DestinationPath '%TEMP%\node-extract' -Force" xcopy /s /e /q /y "%TEMP%\node-extract\node-%NODE_VER%-win-x64\*" "%INSTALL_TARGET%\runtime\node-win-x64\" >nul @@ -121,31 +121,31 @@ if "!USE_NODE!"=="usb" ( set "INSTALL_NODE=%INSTALL_TARGET%\runtime\node-win-x64\node.exe" set "INSTALL_NPM=%INSTALL_TARGET%\runtime\node-win-x64\npm.cmd" - echo Node.js 下载安装完成! + echo Node.js installed ) echo. REM ---- Step 5: Copy/Download OpenClaw ---- -echo [4/4] 安装 OpenClaw... +echo [4/4] Installing OpenClaw if "!USE_OPENCLAW!"=="usb" ( - echo 从 U 盘复制 OpenClaw + 插件... + echo Copying OpenClaw and its plugins from the drive xcopy /s /e /q /y "%APP_DIR%\core" "%INSTALL_TARGET%\core\" >nul - echo OpenClaw 安装完成! + echo OpenClaw Installed! ) else ( - echo 从国内镜像下载 OpenClaw... + echo Downloading OpenClaw mkdir "%INSTALL_TARGET%\core" 2>nul (echo {"name":"u-claw-core","version":"1.0.0","private":true,"dependencies":{"openclaw":"latest"}})>"%INSTALL_TARGET%\core\package.json" cd /d "%INSTALL_TARGET%\core" call "!INSTALL_NPM!" install --registry=%MIRROR% call "!INSTALL_NPM!" install @sliverp/qqbot@latest --registry=%MIRROR% - echo OpenClaw 下载安装完成! + echo OpenClaw installed ) set "QQ_DIR=%INSTALL_TARGET%\core\node_modules\@sliverp\qqbot" if exist "!QQ_DIR!" ( if not exist "!QQ_DIR!\dist\index.js" ( - echo 编译 QQbot 插件运行文件... + echo Building the QQ plugin pushd "!QQ_DIR!" call "!INSTALL_NPM!" install --include=dev --registry=%MIRROR% >nul 2>&1 call "!INSTALL_NPM!" run build >nul 2>&1 @@ -154,9 +154,9 @@ if exist "!QQ_DIR!" ( ) if exist "!QQ_DIR!\node_modules\openclaw" rmdir /s /q "!QQ_DIR!\node_modules\openclaw" 2>nul if exist "!QQ_DIR!\dist\index.js" ( - echo QQbot 插件运行文件已就绪! + echo QQ plugin ready ) else ( - echo [WARNING] QQbot 插件缺少 dist\index.js + echo [WARNING] The QQ plugin is missing dist\index.js ) ) @@ -212,18 +212,18 @@ echo pause echo. echo ======================================== -echo 安装成功! +echo Installed! echo ======================================== echo. -echo 安装位置: %INSTALL_TARGET% +echo Location: %INSTALL_TARGET% echo. -for /f "tokens=*" %%s in ('powershell -command "(Get-ChildItem '%INSTALL_TARGET%' -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum / 1MB" 2^>nul') do echo 大小: %%s MB +for /f "tokens=*" %%s in ('powershell -command "(Get-ChildItem '%INSTALL_TARGET%' -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum / 1MB" 2^>nul') do echo Size: %%s MB echo. -echo 启动方式: -echo 双击 %INSTALL_TARGET%\start.bat +echo To start it: +echo Double-click %INSTALL_TARGET%\start.bat echo. -echo 首次使用: -echo 启动后浏览器自动打开配置页面 -echo 选择 AI 模型 - 填写 API Key - 开始用 +echo First time: +echo Settings opens in your browser by itself +echo Paste an API key and you are ready echo. pause diff --git a/portable/Windows-IntranetFix.bat b/portable/advanced/Windows-IntranetFix.bat similarity index 75% rename from portable/Windows-IntranetFix.bat rename to portable/advanced/Windows-IntranetFix.bat index 3072b64..140f8b2 100644 --- a/portable/Windows-IntranetFix.bat +++ b/portable/advanced/Windows-IntranetFix.bat @@ -3,13 +3,13 @@ chcp 65001 >nul 2>&1 title U-Claw - Intranet Check setlocal -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "NODE_BIN=%UCLAW_DIR%app\runtime\node-win-x64\node.exe" set "CONFIG_PATH=%UCLAW_DIR%data\.openclaw\openclaw.json" if not exist "%NODE_BIN%" ( echo [ERROR] Node runtime not found. - echo Put this file inside your U-Claw folder, next to Windows-Start.bat, then run again. + echo Put this file inside your U-Claw folder, next to the START HERE files, then run again. echo. pause exit /b 1 diff --git a/portable/Windows-LocalModel.bat b/portable/advanced/Windows-LocalModel.bat similarity index 72% rename from portable/Windows-LocalModel.bat rename to portable/advanced/Windows-LocalModel.bat index 2705588..e4fd7d3 100644 --- a/portable/Windows-LocalModel.bat +++ b/portable/advanced/Windows-LocalModel.bat @@ -3,13 +3,13 @@ chcp 65001 >nul 2>&1 title U-Claw - Local / Intranet Model Setup setlocal -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "NODE_BIN=%UCLAW_DIR%app\runtime\node-win-x64\node.exe" set "CONFIG_PATH=%UCLAW_DIR%data\.openclaw\openclaw.json" if not exist "%NODE_BIN%" ( echo [ERROR] Node runtime not found. - echo Put this file inside your U-Claw folder, next to Windows-Start.bat, then run again. + echo Put this file inside your U-Claw folder, next to the START HERE files, then run again. echo. pause exit /b 1 diff --git a/portable/Windows-Menu.bat b/portable/advanced/Windows-Menu.bat similarity index 98% rename from portable/Windows-Menu.bat rename to portable/advanced/Windows-Menu.bat index b2b6364..a105c1f 100644 --- a/portable/Windows-Menu.bat +++ b/portable/advanced/Windows-Menu.bat @@ -3,7 +3,7 @@ setlocal EnableDelayedExpansion chcp 65001 >nul 2>&1 title U-Claw Menu -set "UCLAW_DIR=%~dp0" +for %%I in ("%~dp0..") do set "UCLAW_DIR=%%~fI\" set "APP_DIR=%UCLAW_DIR%app" REM Migration shim: rename old core-win to core for existing USB users @@ -474,7 +474,7 @@ for /f "tokens=*" %%v in ('"%NODE_BIN%" -e "console.log(require('%CORE_DIR:\=/%/ echo Current version: %CUR_VER% 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 +for /f "tokens=*" %%v in ('"%NODE_BIN%" -e "const https=require('https');https.get('https://registry.npmjs.org/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?^) @@ -507,7 +507,7 @@ if /i not "!doupdate!"=="y" ( echo. echo Updating... cd /d "%CORE_DIR%" -call "%NPM_BIN%" install openclaw@latest --registry=https://registry.npmmirror.com +call "%NPM_BIN%" install openclaw@latest --registry=https://registry.npmjs.org for /f "tokens=*" %%v in ('"%NODE_BIN%" -e "console.log(require('./node_modules/openclaw/package.json').version)"') do set NEW_VER=%%v echo. echo Updated! %CUR_VER% - %NEW_VER% diff --git a/portable/setup.bat b/portable/advanced/setup.bat similarity index 87% rename from portable/setup.bat rename to portable/advanced/setup.bat index 6103fd4..55fc85a 100644 --- a/portable/setup.bat +++ b/portable/advanced/setup.bat @@ -3,12 +3,12 @@ setlocal EnableDelayedExpansion chcp 65001 >nul 2>&1 title U-Claw Portable Setup -set "SCRIPT_DIR=%~dp0" +for %%I in ("%~dp0..") do set "SCRIPT_DIR=%%~fI\" set "APP_DIR=%SCRIPT_DIR%app" set "CORE_DIR=%APP_DIR%\core" set "RUNTIME_DIR=%APP_DIR%\runtime" -set "MIRROR=https://registry.npmmirror.com" -set "NODE_MIRROR=https://npmmirror.com/mirrors/node" +set "MIRROR=https://registry.npmjs.org" +set "NODE_MIRROR=https://nodejs.org/dist" set "NODE_VERSION=v22.22.1" set "ALL_PLATFORMS=false" if "%~1"=="--all-platforms" set "ALL_PLATFORMS=true" @@ -19,7 +19,7 @@ echo U-Claw Portable Setup echo ======================================== echo. -echo 系统: Windows x64 +echo System: Windows x64 echo. REM ---- 1. Download Node.js (Current Platform - Windows) ---- @@ -165,25 +165,16 @@ if exist "%QQ_DIR%\dist\index.js" ( ) :qq_build_done -REM ---- 4. Install China-optimized skills ---- -set "SKILLS_CN=%SCRIPT_DIR%skills-cn" +REM ---- 4. Install skills from the manifest ---- +REM Content lives in ..\skills (see skills\README.md); this script carries none. set "SKILLS_TARGET=%CORE_DIR%\node_modules\openclaw\skills" +set "SKILL_INSTALLER=%SCRIPT_DIR%lib\install-skills.mjs" +if not exist "%SKILL_INSTALLER%" set "SKILL_INSTALLER=%SCRIPT_DIR%..\lib\install-skills.mjs" -if not exist "%SKILLS_CN%" goto skip_skills_install -if not exist "%SKILLS_TARGET%" goto skip_skills_install - -echo [COPY] Installing China-optimized skills (skills-cn)... -set "SKILL_COUNT=0" -for /d %%s in ("%SKILLS_CN%\*") do ( - set "skill_name=%%~nxs" - if not exist "%SKILLS_TARGET%\!skill_name!" ( - xcopy /s /e /q /y "%%s" "%SKILLS_TARGET%\!skill_name!\" >nul - set /a SKILL_COUNT+=1 - ) +if exist "%SKILL_INSTALLER%" if exist "%SKILLS_TARGET%" ( + echo [SKILLS] Installing skills... + "%NODE_TARGET%\node.exe" "%SKILL_INSTALLER%" --target "%SKILLS_TARGET%" --locale en ) -echo [OK] China skills installed (+%SKILL_COUNT% skills) - -:skip_skills_install REM ---- Done ---- echo. @@ -192,8 +183,8 @@ echo Setup Complete! echo ======================================== echo. echo To start: -echo Mac: bash Mac-Start.command -echo Windows: Double-click Windows-Start.bat +echo Mac: bash START HERE - Mac.command +echo Windows: Double-click START HERE - Windows.bat echo. echo Directory structure: echo app\core\ - OpenClaw + dependencies diff --git a/portable/setup.ps1 b/portable/advanced/setup.ps1 similarity index 90% rename from portable/setup.ps1 rename to portable/advanced/setup.ps1 index 3b949cd..d4c48b9 100644 --- a/portable/setup.ps1 +++ b/portable/advanced/setup.ps1 @@ -4,13 +4,13 @@ param( $ErrorActionPreference = "Stop" -$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$scriptDir = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path) $appDir = Join-Path $scriptDir "app" $coreDir = Join-Path $appDir "core" $runtimeDir = Join-Path $appDir "runtime" -$mirror = "https://registry.npmmirror.com" -$nodeMirror = "https://npmmirror.com/mirrors/node" +$mirror = "https://registry.npmjs.org" +$nodeMirror = "https://nodejs.org/dist" $nodeVersion = "v22.22.1" function Write-Step { @@ -268,20 +268,14 @@ else { Ensure-QQPluginBuild -CoreDir $coreDir -NpmCmd $npmCmd -$skillsCn = Join-Path $scriptDir "skills-cn" +# Skills: content lives in ..\skills (see skills\README.md); this script carries none. $skillsTarget = Join-Path $coreDir "node_modules\openclaw\skills" +$skillInstaller = Join-Path $scriptDir "lib\install-skills.mjs" +if (-not (Test-Path $skillInstaller)) { $skillInstaller = Join-Path $scriptDir "..\lib\install-skills.mjs" } -if ((Test-Path -Path $skillsCn -PathType Container) -and (Test-Path -Path $skillsTarget -PathType Container)) { - Write-Step "->" "Installing localized skills from skills-cn..." "Cyan" - $skillCount = 0 - Get-ChildItem -Path $skillsCn -Directory | ForEach-Object { - $targetPath = Join-Path $skillsTarget $_.Name - if (-not (Test-Path -Path $targetPath -PathType Container)) { - Copy-Item -Path $_.FullName -Destination $targetPath -Recurse -Force - $skillCount++ - } - } - Write-Step "OK" ("Localized skills installed (+{0})." -f $skillCount) "Green" +if ((Test-Path $skillInstaller) -and (Test-Path -Path $skillsTarget -PathType Container)) { + Write-Step "->" "Installing skills..." "Cyan" + & (Join-Path $windowsNodeTarget "node.exe") $skillInstaller --target $skillsTarget --locale en } Write-Host "" @@ -290,8 +284,8 @@ Write-Host " Setup Complete" -ForegroundColor Green Write-Host "========================================" -ForegroundColor Green Write-Host "" Write-Host " Launch:" -Write-Host " Mac: bash Mac-Start.command" -ForegroundColor Cyan -Write-Host " Windows: double-click Windows-Start.bat" -ForegroundColor Cyan +Write-Host " Mac: bash START HERE - Mac.command" -ForegroundColor Cyan +Write-Host " Windows: double-click START HERE - Windows.bat" -ForegroundColor Cyan Write-Host "" Write-Host " Structure:" Write-Host " app/core/ -> OpenClaw and dependencies" diff --git a/portable/setup.sh b/portable/advanced/setup.sh similarity index 59% rename from portable/setup.sh rename to portable/advanced/setup.sh index cb06154..3af17c8 100755 --- a/portable/setup.sh +++ b/portable/advanced/setup.sh @@ -2,18 +2,18 @@ # ============================================================ # U-Claw Portable — 开发环境搭建脚本 # 用法: bash setup.sh -# 作用: 下载 Node.js 运行时 + 安装 OpenClaw 到 app/ 目录 +# 作用: 下载 Node.js 运行时 + Installing OpenClaw 到 app/ 目录 # ============================================================ set -e -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" APP_DIR="$SCRIPT_DIR/app" CORE_DIR="$APP_DIR/core" RUNTIME_DIR="$APP_DIR/runtime" -MIRROR="https://registry.npmmirror.com" -NODE_MIRROR="https://npmmirror.com/mirrors/node" -NODE_VERSION="v22.22.1" +MIRROR="https://registry.npmjs.org" +NODE_MIRROR="https://nodejs.org/dist" +NODE_VERSION="$(tr -d "[:space:]" < "$SCRIPT_DIR/NODE_VERSION" 2>/dev/null || tr -d "[:space:]" < "$SCRIPT_DIR/../NODE_VERSION" 2>/dev/null || echo v22.22.1)" ALL_PLATFORMS=false [ "$1" = "--all-platforms" ] && ALL_PLATFORMS=true @@ -41,20 +41,20 @@ if [ "$OS" = "Darwin" ]; then NODE_DIR_NAME="node-mac-x64" fi else - echo -e "${RED}请在 Mac 上运行此脚本。Windows 请用 setup.bat${NC}" + echo -e "${RED}Run this on a Mac. On Windows, use setup.bat instead.${NC}" exit 1 fi -echo -e " 系统: ${GREEN}$OS $ARCH${NC}" +echo -e " System: ${GREEN}$OS $ARCH${NC}" echo "" # ---- 1. Download Node.js (Current Platform) ---- NODE_TARGET="$RUNTIME_DIR/$NODE_DIR_NAME" if [ -f "$NODE_TARGET/bin/node" ]; then - echo -e " ${GREEN}✓${NC} Node.js ($PLATFORM) 已存在,跳过下载" + echo -e " ${GREEN}✓${NC} Node.js ($PLATFORM) already downloaded, skipping" else - echo -e " ${CYAN}↓${NC} 下载 Node.js $NODE_VERSION ($PLATFORM)..." + echo -e " ${CYAN}↓${NC} Downloading Node.js $NODE_VERSION ($PLATFORM)" mkdir -p "$NODE_TARGET" NODE_URL="$NODE_MIRROR/$NODE_VERSION/node-$NODE_VERSION-$PLATFORM.tar.gz" @@ -63,9 +63,9 @@ else curl -fSL "$NODE_URL" | tar xz -C "$NODE_TARGET" --strip-components=1 if [ -f "$NODE_TARGET/bin/node" ]; then - echo -e " ${GREEN}✓${NC} Node.js ($PLATFORM) 下载完成" + echo -e " ${GREEN}✓${NC} Node.js ($PLATFORM) downloaded" else - echo -e " ${RED}✗ Node.js 下载失败${NC}" + echo -e " ${RED}✗ Node.js Download failed${NC}" exit 1 fi fi @@ -74,9 +74,9 @@ fi if [ "$ALL_PLATFORMS" = "true" ]; then WIN_NODE_TARGET="$RUNTIME_DIR/node-win-x64" if [ -f "$WIN_NODE_TARGET/node.exe" ]; then - echo -e " ${GREEN}✓${NC} Node.js (win-x64) 已存在,跳过下载" + echo -e " ${GREEN}✓${NC} Node.js (win-x64) already downloaded, skipping" else - echo -e " ${CYAN}↓${NC} 下载 Node.js $NODE_VERSION (win-x64) - Windows支持..." + echo -e " ${CYAN}↓${NC} Downloading Node.js $NODE_VERSION (win-x64) for Windows" mkdir -p "$WIN_NODE_TARGET" WIN_NODE_URL="$NODE_MIRROR/$NODE_VERSION/node-$NODE_VERSION-win-x64.zip" @@ -95,18 +95,18 @@ if [ "$ALL_PLATFORMS" = "true" ]; then rm -f "$TMP_ZIP" if [ -f "$WIN_NODE_TARGET/node.exe" ]; then - echo -e " ${GREEN}✓${NC} Node.js (win-x64) 下载完成" + echo -e " ${GREEN}✓${NC} Node.js (win-x64) downloaded" else - echo -e " ${CYAN}⚠${NC} Windows runtime下载失败 (不影响当前平台使用)" + echo -e " ${CYAN}⚠${NC} Windows runtime download failed — this platform still works" fi fi fi # ---- 2. Install OpenClaw ---- if [ -d "$CORE_DIR/node_modules/openclaw" ]; then - echo -e " ${GREEN}✓${NC} OpenClaw 已安装,跳过" + echo -e " ${GREEN}✓${NC} OpenClaw already installed, skipping" else - echo -e " ${CYAN}↓${NC} 安装 OpenClaw..." + echo -e " ${CYAN}↓${NC} Installing OpenClaw..." mkdir -p "$CORE_DIR" # Init package.json if not exists (pinned OpenClaw version from OPENCLAW_VERSION) @@ -114,7 +114,7 @@ else if [ ! -f "$OPENCLAW_VERSION_FILE" ]; then OPENCLAW_VERSION_FILE="$(dirname "$0")/../OPENCLAW_VERSION" fi - OPENCLAW_VERSION="2026.4.29" + OPENCLAW_VERSION="2026.7.1-2" if [ -f "$OPENCLAW_VERSION_FILE" ]; then OPENCLAW_VERSION="$(tr -d '[:space:]' < "$OPENCLAW_VERSION_FILE")" # Copy version file into portable/ so USB users can read it without repo root @@ -136,55 +136,61 @@ PKGJSON # Install with China mirror(缓存留盘内,拔盘不留痕) # --ignore-scripts 必须加:openclaw 的 preinstall 脚本会调系统 `node`,但便携版 # 用的是 app/runtime 下的 node(不在 PATH),未装 Node 的 Mac 用户会因 - # "node: command not found" 安装失败 (code 127)。与 Mac-Start.command 的 fallback 对齐。 + # "node: command not found" 安装失败 (code 127)。与 START HERE - Mac.command 的 fallback 对齐。 NODE_BIN="$NODE_TARGET/bin/node" NPM_BIN="$NODE_TARGET/bin/npm" npm_config_cache="$APP_DIR/.npm-cache" "$NODE_BIN" "$NPM_BIN" install --prefix "$CORE_DIR" --registry="$MIRROR" --ignore-scripts --no-audit --no-fund --omit=dev - echo -e " ${GREEN}✓${NC} OpenClaw 安装完成" + echo -e " ${GREEN}✓${NC} OpenClaw installed" fi # ---- 3. Install QQ Plugin ---- if [ -d "$CORE_DIR/node_modules/@sliverp/qqbot" ]; then - echo -e " ${GREEN}✓${NC} QQ 插件已安装,跳过" + echo -e " ${GREEN}✓${NC} QQ plugin already installed, skipping" else - echo -e " ${CYAN}↓${NC} 安装 QQ 插件..." + echo -e " ${CYAN}↓${NC} Installing the QQ plugin..." NODE_BIN="$NODE_TARGET/bin/node" NPM_BIN="$NODE_TARGET/bin/npm" npm_config_cache="$APP_DIR/.npm-cache" "$NODE_BIN" "$NPM_BIN" install @sliverp/qqbot@latest --prefix "$CORE_DIR" --registry="$MIRROR" --ignore-scripts --no-audit --no-fund --omit=dev 2>/dev/null || true - echo -e " ${GREEN}✓${NC} QQ 插件安装完成" + echo -e " ${GREEN}✓${NC} QQ plugin installed" fi -# ---- 4. Install China-optimized skills ---- -SKILLS_CN="$SCRIPT_DIR/skills-cn" -SKILLS_TARGET="$CORE_DIR/node_modules/openclaw/skills" +# ---- 3b. Stage what the drive needs to stand alone ---- +# release.yml puts these on the drive; a locally built drive has to match, or the +# first-run wizard cannot install skills and the drive cannot switch locale offline. +for VERSION_FILE in OPENCLAW_VERSION NODE_VERSION; do + [ -f "$SCRIPT_DIR/$VERSION_FILE" ] || cp "$SCRIPT_DIR/../$VERSION_FILE" "$SCRIPT_DIR/$VERSION_FILE" 2>/dev/null || true +done +if [ -d "$SCRIPT_DIR/../skills" ] && [ ! -d "$SCRIPT_DIR/skills" ]; then + cp -R "$SCRIPT_DIR/../skills" "$SCRIPT_DIR/skills" +fi +mkdir -p "$SCRIPT_DIR/lib" +[ -f "$SCRIPT_DIR/lib/install-skills.mjs" ] || cp "$SCRIPT_DIR/../lib/install-skills.mjs" "$SCRIPT_DIR/lib/install-skills.mjs" 2>/dev/null || true -if [ -d "$SKILLS_CN" ] && [ -d "$SKILLS_TARGET" ]; then - echo -e " ${CYAN}↓${NC} 安装中国优化技能 (skills-cn)..." - SKILL_COUNT=0 - for skill_dir in "$SKILLS_CN"/*/; do - skill_name=$(basename "$skill_dir") - if [ ! -d "$SKILLS_TARGET/$skill_name" ]; then - cp -R "$skill_dir" "$SKILLS_TARGET/$skill_name" - SKILL_COUNT=$((SKILL_COUNT + 1)) - fi - done - echo -e " ${GREEN}✓${NC} 中国技能安装完成 (+$SKILL_COUNT 个)" +# ---- 4. Install skills from the manifest ---- +# Content lives in ../skills (see skills/README.md); this script carries none. +SKILLS_TARGET="$CORE_DIR/node_modules/openclaw/skills" +SKILL_INSTALLER="$SCRIPT_DIR/lib/install-skills.mjs" +[ -f "$SKILL_INSTALLER" ] || SKILL_INSTALLER="$SCRIPT_DIR/../lib/install-skills.mjs" + +if [ -f "$SKILL_INSTALLER" ] && [ -d "$SKILLS_TARGET" ]; then + echo -e " ${CYAN}\u2193${NC} Installing skills..." + "$NODE_TARGET/bin/node" "$SKILL_INSTALLER" --target "$SKILLS_TARGET" --locale "${UCLAW_LOCALE:-en}" fi # ---- Done ---- echo "" echo -e "${GREEN}════════════════════════════════════════${NC}" -echo -e "${GREEN} ✅ 搭建完成!${NC}" +echo -e "${GREEN} Done.${NC}" echo "" -echo -e " 启动方式:" -echo -e " Mac: ${CYAN}bash Mac-Start.command${NC}" -echo -e " Windows: 双击 ${CYAN}Windows-Start.bat${NC}" +echo -e " To start it:" +echo -e " Mac: ${CYAN}double-click \"START HERE - Mac.command\"${NC}" +echo -e " Windows: double-click ${CYAN}START HERE - Windows.bat${NC}" echo "" -echo -e " 目录结构:" -echo -e " app/core/ ← OpenClaw + 依赖" +echo -e " Layout:" +echo -e " app/core/ OpenClaw and its dependencies" echo -e " app/runtime/ ← Node.js $NODE_VERSION" -echo -e " data/ ← 运行后自动生成" +echo -e " data/ created on first run" echo "" -echo -e " ${CYAN}提示: 制作跨平台 U 盘请用 bash setup.sh --all-platforms${NC}" +echo -e " ${CYAN}Tip: use --all-platforms to prepare a drive that works on both Mac and Windows${NC}" echo -e "${GREEN}════════════════════════════════════════${NC}" diff --git a/portable/config-server/public/index.html b/portable/config-server/public/index.html index c6c98ea..dc00b6d 100644 --- a/portable/config-server/public/index.html +++ b/portable/config-server/public/index.html @@ -1,9 +1,9 @@ - + -U-Claw 配置中心 +U-Claw Settings + + + +
-

🦞 U-Claw 配置中心

-

选择模型,填入 API Key,一键启动

+

🦞 U-Claw Settings

+

Paste an API key and you are done.

-
检测中...
+
Checking…
-
1选模型
-
2填 Key
-
3启动
+
1Your key
+
2Done
- +
-

选择 AI 模型

-

最省心:用「虾盘云」一个 Key 调用国内外全部大模型(中转站)。也可用下面各家自己的官方 Key。

+

Paste your API key

+

U-Claw works out the rest by itself. Your key is saved on this drive only — it is never uploaded anywhere.

-
-
- -

虾盘云 首选中转站

-

一个 Key 用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙

- → 注册 / 充值 / 获取 API Key -
-
- -

MiniMax 推荐国内

-

MiniMax-Text-01,速度快,性价比高

- → 获取 API Key -
-
- -

Kimi (月之暗面) 国内

-

moonshot-v1-auto,智能选模型

- → 获取 API Key -
-
- -

DeepSeek 国内便宜

-

deepseek-v4-flash,超低价格

- → 获取 API Key -
-
- -

智谱 GLM 国内有免费

-

glm-5(zai provider),免费额度可用

- → 获取 API Key -
-
- -

通义千问 国内有免费

-

qwen-turbo,阿里云出品

- → 获取 API Key -
-
- -

豆包 (字节) 国内

-

doubao-1.5-pro,字节跳动

- → 获取 API Key -
-
- -

OpenAI

-

GPT-4o,需翻墙或中转

- → 获取 API Key -
-
- -

Claude

-

Claude Sonnet 4,需翻墙或中转

- → 获取 API Key -
-
- -

Groq 极快有免费

-

Llama 3.3 70B,超高速推理

- → 获取 API Key -
-
- -

硅基流动 国内便宜

-

多模型聚合,价格低

- → 获取 API Key -
-
- -

🔧 自定义 API OpenAI 兼容

-

填写任意 OpenAI 兼容 API 地址(OpenRouter、API2D、New API、One API 等)

+
+
+ +
+
+
+ + +
- -
-
- - -
-

填写 API Key

-

请填写对应模型的 API Key

- -
-

📌 获取 / 充值 API Key

- +
-
🦞
-

配置完成!

-

模型和 API Key 已保存到本地

+

You are set up

+

Your model and key are saved on this drive.

http://127.0.0.1:18789
-

📱 接入聊天平台(可选)

-

点击卡片展开填写,不填可直接跳过:

+

📱 Connect a chat app (optional)

+

Click a card to fill it in, or skip this entirely.

+
+

💬 WhatsApp

+

Talk to U-Claw from WhatsApp

+
+

⚠️ This uses an unofficial protocol. Your WhatsApp account can be banned for it. Do not connect a number you rely on.

+
+ + +
+
+

✈️ Telegram

-

接入 Telegram Bot

+

Talk to U-Claw from Telegram

-
-

🐧 QQ Bot

-

接入 QQ 群/私聊机器人

-
+
+

💼 Slack

+

Talk to U-Claw from your workspace

+
- - -
-
-
-

📘 飞书

-

接入飞书机器人

-
+
+

🎮 Discord

+

Talk to U-Claw from Discord

+ -
-
-

🏢 企业微信

-

接入企业微信机器人

-
-
- - -
- -
-
-
-

💬 微信 个人微信

-

扫码接入个人微信,用微信聊天控制 AI

-
-
-

点击此卡片开始扫码

-
-
+ + +
+ Chat apps used mainly in China +
+
+

🐧 QQ Bot

+
+
+ + +
+
+ + +

→ q.qq.com

+
+
+
+
+

📘 Feishu / Lark

+
+
+ + +
+
+ + +

→ open.feishu.cn

+
+
+
+
+

🏢 WeCom

+
+
+ + +
+
+ + +

→ work.weixin.qq.com

+
+
+
+
+

💬 WeChat

+

Scan a QR code to link a personal WeChat account

+
+
+

Click this card to show the QR code

+
+
+
+
+
+
- -

渠道配置会自动写入,Gateway 需重启生效

+ +

Chat app settings are saved now and take effect after U-Claw restarts.

+
+ +
+ +
- - + +
-
-

📦 目录说明

-

U 盘内的文件结构

+
+

📦 What is on the drive

+

How the folders are organised

-

skills-cn/ — 中文技能

-

放入 .md 技能文件,OpenClaw 自动加载

+

skills/ — Skills

+

Drop a SKILL.md in here and it is picked up automatically

📁
-

app/ — 运行时 + 核心

-

Node.js 运行时、OpenClaw 核心代码

+

app/ — Runtime

+

Node.js and the OpenClaw core

⚙️
-

data/ — 配置和数据

-

API Key、聊天历史等保存在此(仅本地)

+

data/ — Your data

+

Your key and chat history. Stays on this drive.

🔒
@@ -418,10 +406,10 @@ input:focus { border-color: #ff6b35; }
-

🐛 反馈 / 报 Bug

-

U-Claw 是开源项目。遇到问题欢迎到 GitHub 提 Issue —— 我们不会自动收集或上传你的任何数据。

+

🐛 Found a problem?

+

U-Claw is open source. Report anything that breaks on GitHub — nothing is collected or uploaded from your machine automatically.

@@ -430,70 +418,116 @@ input:focus { border-color: #ff6b35; } optional, written by the launcher + * + * + * + * Then mark text with data-i18n="key". Attributes use data-i18n-attr="placeholder:key". + * The HTML keeps English as its literal fallback, so a missing catalogue degrades + * to readable English instead of raw keys. + */ +(function (global) { + 'use strict'; + + var SUPPORTED = ['en', 'zh-CN']; + var FALLBACK = 'en'; + + function normalise(tag) { + if (!tag) return null; + var lower = String(tag).toLowerCase(); + if (lower.indexOf('zh') === 0) return 'zh-CN'; + if (lower.indexOf('en') === 0) return 'en'; + return null; + } + + // The language travels with the drive, not the machine: someone who set the + // drive up in Chinese and plugs it into a colleague's English Windows should + // still see Chinese. The launcher writes data/.openclaw/locale.js on startup; + // ?lang= is the manual override, and the browser language is the last resort. + function resolveLocale() { + var fromQuery = null; + try { + fromQuery = new URLSearchParams(global.location.search).get('lang'); + } catch (e) { /* older browser or opaque URL */ } + + return normalise(fromQuery) + || normalise(global.UCLAW_LOCALE) + || normalise(global.navigator && global.navigator.language) + || FALLBACK; + } + + var locale = resolveLocale(); + var catalogues = global.UCLAW_I18N_MESSAGES || {}; + var active = catalogues[SUPPORTED.indexOf(locale) === -1 ? FALLBACK : locale] || {}; + var fallback = catalogues[FALLBACK] || {}; + + function t(key, vars) { + var template = active[key]; + if (template === undefined) template = fallback[key]; + if (template === undefined) return key; + if (!vars) return template; + return template.replace(/\{(\w+)\}/g, function (match, name) { + return Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : match; + }); + } + + function apply(root) { + var scope = root || global.document; + + scope.querySelectorAll('[data-i18n]').forEach(function (node) { + var value = t(node.getAttribute('data-i18n')); + // Keep the literal in the HTML when a key has no translation, rather than + // replacing readable English with the key name. + if (value !== node.getAttribute('data-i18n')) node.textContent = value; + }); + + scope.querySelectorAll('[data-i18n-attr]').forEach(function (node) { + node.getAttribute('data-i18n-attr').split(',').forEach(function (pair) { + var parts = pair.split(':'); + if (parts.length !== 2) return; + var attr = parts[0].trim(); + var value = t(parts[1].trim()); + if (value !== parts[1].trim()) node.setAttribute(attr, value); + }); + }); + + global.document.documentElement.lang = locale; + } + + // Region defaults for Singapore. The old pages assumed China: Asia/Shanghai, + // YYYY-MM-DD, 24-hour, ¥. SG uses DD/MM/YYYY (neither Chinese nor American), + // 12-hour with am/pm, and S$. + var REGION = { + en: { locale: 'en-SG', timeZone: 'Asia/Singapore', currency: 'SGD', hour12: true }, + 'zh-CN': { locale: 'zh-SG', timeZone: 'Asia/Singapore', currency: 'SGD', hour12: true }, + }; + + function region() { + return REGION[locale] || REGION.en; + } + + function formatDate(date) { + var r = region(); + try { + return new Intl.DateTimeFormat(r.locale, { + timeZone: r.timeZone, day: '2-digit', month: '2-digit', year: 'numeric', + }).format(date); + } catch (e) { + return String(date); + } + } + + function formatTime(date) { + var r = region(); + try { + return new Intl.DateTimeFormat(r.locale, { + timeZone: r.timeZone, hour: 'numeric', minute: '2-digit', hour12: r.hour12, + }).format(date); + } catch (e) { + return String(date); + } + } + + // ICU renders SGD as a bare "$" in an en-SG locale, which is ambiguous next to + // USD prices. Prices are written S$ throughout the product, so format the + // number with Intl and put the symbol on ourselves rather than depending on + // whichever ICU build the browser or Node happens to ship. + function formatMoney(amount) { + var r = region(); + try { + return 'S$' + new Intl.NumberFormat(r.locale, { + minimumFractionDigits: 2, maximumFractionDigits: 2, + }).format(amount); + } catch (e) { + return 'S$' + amount; + } + } + + global.UClawI18n = { + locale: locale, + supported: SUPPORTED, + t: t, + apply: apply, + region: region, + formatDate: formatDate, + formatTime: formatTime, + formatMoney: formatMoney, + }; + + if (global.document.readyState === 'loading') { + global.document.addEventListener('DOMContentLoaded', function () { apply(); }); + } else { + apply(); + } +})(window); diff --git a/portable/lib/i18n/messages.js b/portable/lib/i18n/messages.js new file mode 100644 index 0000000..67699e0 --- /dev/null +++ b/portable/lib/i18n/messages.js @@ -0,0 +1,566 @@ +/* GENERATED FILE — do not edit. + * Source: lib/messages/*.json + * Regenerate: node lib/i18n/build-messages.mjs + * + * Exists because pages opened from file:// cannot fetch local JSON. + */ +window.UCLAW_I18N_MESSAGES = { + "en": { + "start.banner": "U-Claw · Portable AI Agent", + "start.node_version": "Node.js {version}", + "start.quarantine_removing": "Clearing the macOS security flag…", + "start.cache_local": "Cache on local disk: {path}", + "start.config_migrating": "Bringing your old settings across…", + "start.config_migrated": "Settings moved over.", + "start.config_creating": "First run — setting things up…", + "start.config_created": "Ready.", + "start.deps_preparing": "Getting things ready — about 20 seconds.", + "start.deps_slow_drive": "This drive is slow, so it may take a few minutes. You can leave it running.", + "start.deps_done": "Ready.", + "start.no_proxy": "Connecting directly to your model host: {hosts}", + "start.wechat_installing": "Installing the WeChat plugin…", + "start.wechat_installed": "WeChat plugin installed.", + "start.config_center_starting": "Starting the Control Panel…", + "start.config_center_port": "Control Panel is on port {port}.", + "start.port_in_use": "Port {port} is busy, trying the next one…", + "start.gateway_starting": "Starting U-Claw on port {port}…", + "start.opening_screen": "Opening the start screen…", + "start.opening_config": "Opening the Control Panel…", + "start.running_title": "U-Claw is running", + "start.running_dashboard": "Dashboard: {url}", + "start.running_config": "Control Panel: {url}", + "start.running_hint": "Keep this window open while you use U-Claw. Press Ctrl+C to stop.", + "start.first_run_wait": "First run from a USB drive takes 30–90 seconds while components unpack. The Control Panel is already open so you can pick a model and paste a key.", + "start.stopped": "U-Claw stopped.", + "start.exited_unexpectedly": "U-Claw closed on its own (code {code}).", + "error.node_missing.what": "A file U-Claw needs is missing from the drive.", + "error.node_missing.why": "This usually means the copy onto the USB drive did not finish.", + "error.node_missing.action": "Copy the U-Claw folder onto the drive again, or run setup.sh to rebuild it.", + "error.unsupported_arch.what": "This Mac's processor is not supported ({arch}).", + "error.unsupported_arch.why": "U-Claw ships builds for Apple Silicon and Intel Macs only.", + "error.unsupported_arch.action": "Try U-Claw on a different computer.", + "error.no_port.what": "U-Claw could not find a free port to start on.", + "error.no_port.why": "Ports {from}–{to} are all in use — U-Claw may already be running.", + "error.no_port.action": "Close any window already running U-Claw and start it again.", + "error.deps_failed.what": "U-Claw could not finish getting ready.", + "error.deps_failed.why": "The download did not complete — usually a dropped network connection.", + "error.deps_failed.action": "Check your Wi-Fi and start U-Claw again.", + "error.press_enter": "Press Enter to close this window.", + "loading.title": "Starting U-Claw", + "loading.starting": "Starting U-Claw…", + "loading.first_run": "First run from a USB drive unpacks the bundled components. Give it a moment — you will be told when it is ready.", + "loading.waiting_gateway": "Waiting for U-Claw to come up…", + "loading.ready": "U-Claw is ready", + "loading.choose_next": "Pick what to do next — start chatting, or set up your model and channels first.", + "loading.open_dashboard": "🚀 Start chatting", + "loading.open_settings": "⚙️ Settings", + "loading.settings_hint": "Add or change your API key, and connect chat apps.", + "loading.no_model_hint": "No model set up yet? Open Settings first to add a key.", + "loading.slow_drive_note": "A slow drive usually takes 30–90 seconds. If nothing happens for a long time, open Settings:", + "loading.elapsed": "Waited {seconds}s", + "loading.taking_long": "This is taking longer than usual. You can open Settings while you wait:", + "welcome.title": "U-Claw — Getting Started", + "welcome.subtitle": "Your AI assistant on a USB drive · three steps", + "welcome.quickstart": "Quick start", + "welcome.step1_title": "1. Start U-Claw", + "welcome.step1_desc": "Double-click the file for your computer:", + "welcome.step2_title": "2. Add a key", + "welcome.step2_desc": "Settings opens on its own the first time. You need one API key to get going — Google Gemini is the easiest to obtain: sign in with a Google account, no card required.", + "welcome.step2_link": "Get a free Gemini key →", + "welcome.step3_title": "3. Start talking", + "welcome.step3_desc": "Once the key is saved, the chat window opens by itself. That is it.", + "welcome.portable_note": "✅ Your settings and history stay in the data/ folder on the drive, so they travel with you between Mac and Windows.", + "welcome.models_title": "Which model?", + "welcome.model_claude": "Best all-rounder", + "welcome.model_gpt": "Most widely used", + "welcome.model_gemini": "Free tier, easiest signup", + "welcome.model_local": "Offline · nothing leaves this machine", + "welcome.models_more": "More options, including SEA-LION for Malay, Tamil and Singlish, are in Settings.", + "welcome.trouble_title": "Something not working?", + "welcome.trouble_lead": "💡 Run the check-up tool", + "welcome.trouble_desc": "If U-Claw will not start, double-click:", + "welcome.open_settings": "Open Settings", + "welcome.open_docs": "Documentation", + "nav.title": "U-Claw — Start here", + "nav.tagline": "Portable AI agent — plug in and go", + "nav.status_off": "U-Claw is not running", + "nav.open_console": "Open it →", + "nav.quickstart": "Quick start", + "nav.doubleclick": "Double-click", + "nav.step2": "Settings opens by itself the first time — pick a model and paste your key.", + "nav.mac_gatekeeper": "⚠️ If macOS says the developer cannot be verified: right-click the file, then choose Open.", + "nav.config_shortcut": "📝 You can also double-click Config.html — it takes you to the settings page.", + "nav.win_smartscreen": "⚠️ If Windows shows a security warning: click More info, then Run anyway.", + "nav.everything": "Everything else", + "nav.menu_opens": "for the full menu:", + "nav.g_settings": "Settings", + "nav.g_settings_d": "Model, key and chat apps", + "nav.g_checkup": "Check-up", + "nav.g_checkup_d": "Finds and fixes common problems", + "nav.g_backup": "Backup", + "nav.g_backup_d": "Save settings and memory in one click", + "nav.g_skills": "Skills", + "nav.g_skills_d": "Browse what U-Claw can do", + "nav.g_system": "System info", + "nav.g_system_d": "Version, port, running state", + "nav.g_cli": "Command line", + "nav.g_cli_d": "For advanced use", + "nav.models_title": "Models you can use", + "nav.model_sealion": "Malay, Tamil and Singlish", + "nav.model_local": "Local model", + "nav.model_more": "More", + "nav.model_more_d": "Others are listed in Settings", + "nav.more_title": "More", + "nav.link_guide": "Getting started", + "nav.link_guide_d": "The three-step walkthrough", + "nav.link_skills": "Skills", + "nav.link_skills_d": "Browse what U-Claw can do", + "nav.link_contact": "Contact", + "nav.link_site": "Website", + "nav.status_on": "U-Claw is running on port {port}", + "nav.status_off_hint": "U-Claw is not running — double-click the start file first", + "key.page_title": "U-Claw Settings", + "key.page_subtitle": "Paste an API key and you are done.", + "key.checking": "Checking…", + "key.step_key": "Your key", + "key.step_done": "Done", + "key.heading": "Paste your API key", + "key.desc": "U-Claw works out the rest by itself. Your key is saved on this drive only — it is never uploaded anywhere.", + "key.placeholder": "sk-…", + "key.show": "Show", + "key.hide": "Hide", + "key.continue": "Continue →", + "key.checking_key": "Checking this key…", + "key.ok": "✓ {provider} · connected in {ms}ms", + "key.custom_provider": "Your endpoint", + "key.no_key_title": "Do not have a key yet?", + "key.no_key_desc": "Google Gemini is the quickest to get: sign in with a Google account, no card needed, and there is a free tier.", + "key.get_gemini": "🔑 Get a free Gemini key", + "key.get_openrouter": "🔑 OpenRouter — one key for many models", + "key.advanced": "Advanced — set the endpoint manually", + "key.base_url": "API endpoint", + "key.model_name": "Model name", + "key.advanced_hint": "Only needed for a self-hosted or unlisted provider. Leave blank to let U-Claw decide.", + "key.saved": "Saved.", + "key.err_empty": "Paste a key to continue.", + "key.err_not_checked": "Hold on — still checking that key.", + "key.err_rejected": "That key was not accepted. Check you copied all of it — keys are long and easy to cut short.", + "key.err_quota": "This key has run out of credit. Top it up with your provider, or paste a different key.", + "key.err_offline": "Cannot reach the internet. Check your Wi-Fi and try again.", + "key.err_timeout": "The provider did not answer in time. Try again in a moment.", + "key.err_model": "That key works, but the model it points to was not found. Set the model name under Advanced.", + "key.err_provider_down": "The provider is having trouble right now. Try again shortly.", + "key.err_unrecognised": "This key is not one U-Claw recognises. Fill in the endpoint and model under Advanced.", + "key.err_unknown": "Could not check that key. Try again, or use Advanced to set the endpoint yourself.", + "key.err_save": "Could not save. Make sure the drive is still plugged in, then try again.", + "hub.title": "U-Claw Skills", + "done.title": "You are set up", + "done.subtitle": "Your model and key are saved on this drive.", + "done.open": "🚀 Start chatting", + "done.restart_note": "Chat app settings are saved now and take effect after U-Claw restarts.", + "done.change_key": "Change model or key", + "done.view_config": "View config file", + "ch.title": "📱 Connect a chat app (optional)", + "ch.desc": "Click a card to fill it in, or skip this entirely.", + "ch.whatsapp_d": "Talk to U-Claw from WhatsApp", + "ch.whatsapp_warning": "⚠️ This uses an unofficial protocol. Your WhatsApp account can be banned for it. Do not connect a number you rely on.", + "ch.whatsapp_number": "Phone number", + "ch.telegram_d": "Talk to U-Claw from Telegram", + "ch.telegram_get": "→ Get one from @BotFather", + "ch.slack_d": "Talk to U-Claw from your workspace", + "ch.slack_get": "→ Create an app at api.slack.com", + "ch.discord_d": "Talk to U-Claw from Discord", + "ch.discord_get": "→ Create an app in the Discord developer portal", + "ch.china_group": "Chat apps used mainly in China", + "ch.wechat_d": "Scan a QR code to link a personal WeChat account", + "ch.wechat_start": "Click this card to show the QR code", + "ch.saved": "Chat app settings saved.", + "ch.err_save": "Could not save the chat app settings. Check the drive is still plugged in.", + "info.layout_title": "What is on the drive", + "info.layout_desc": "How the folders are organised", + "info.skills": "Skills", + "info.skills_d": "Drop a SKILL.md in here and it is picked up automatically", + "info.app": "Runtime", + "info.app_d": "Node.js and the OpenClaw core", + "info.data": "Your data", + "info.data_d": "Your key and chat history. Stays on this drive.", + "info.feedback_title": "Found a problem?", + "info.feedback_desc": "U-Claw is open source. Report anything that breaks on GitHub — nothing is collected or uploaded from your machine automatically.", + "info.feedback_link": "→ Open an issue on GitHub", + "wx.getting_qr": "Fetching the QR code…", + "wx.scan": "Scan the code above with WeChat", + "wx.qr_failed": "Could not fetch the QR code", + "wx.connected": "✅ WeChat connected", + "wx.account": "Account", + "wx.restart_needed": "One more thing: restart U-Claw (close it and open it again) before WeChat will work.", + "wx.connected_toast": "WeChat connected. It works after U-Claw restarts.", + "wx.qr_refreshed": "The code refreshed — scan it again", + "wx.confirm_on_phone": "Scanned. Confirm on your phone…", + "wx.qr_expired": "That code expired.", + "wx.qr_retry": "Get a new one", + "wx.failed": "Could not connect", + "info.read_config_failed": "Could not read the config file:", + "status.running": "U-Claw is running on port {port}", + "status.open_dashboard": "Open it →", + "status.not_running": "U-Claw is not running — start it with Windows-Start.bat or Mac-Start.command", + "key.which_model": "Which model?", + "start.opening_language": "Asking which language to use…", + "persona.title": "What will you mostly use this for?", + "persona.subtitle": "This sets up the right tools for you. You can change it later, and picking more than one is fine.", + "persona.continue": "Continue →", + "persona.skip": "Skip this", + "persona.saving": "Setting things up…", + "persona.err_offline": "U-Claw is not running yet. Start it, then open this page again.", + "persona.err_save": "Could not save that. Check the drive is still plugged in, then try again.", + "persona.developer": "Writing code", + "persona.admin": "Documents and email", + "persona.sales": "Talking to customers", + "persona.marketing": "Content and social", + "persona.finance": "Numbers and spreadsheets", + "persona.boss": "Running a business", + "persona.general": "Just having a look", + "start.opening_persona": "Asking what you will use it for…", + "tier.label": "How much do you want to see?", + "tier.simple": "Just the essentials", + "tier.standard": "A bit more control", + "tier.expert": "Everything", + "tier.changed_simple": "Switched to the simple view — advanced options are hidden.", + "tier.changed_standard": "Switched to the standard view — you can now change models and connect more chat apps.", + "tier.changed_expert": "Switched to the full view — everything is visible, including the config file.", + "start.checking": "Something went wrong — checking…", + "start.repaired": "Fixed. Trying again.", + "start.diagnostics_written": "A report of what happened was saved to: {path}", + "start.diagnostics_hint": "API keys have been removed from it. Send it to help@u-claw.org if you want a hand.", + "skill.excel-helper.name": "Spreadsheets", + "skill.excel-helper.desc": "Formulas, pivot tables, charts, cleaning messy data", + "skill.word-writer.name": "Documents", + "skill.word-writer.desc": "Reports, proposals, CVs — drafting and formatting", + "skill.ppt-designer.name": "Slide decks", + "skill.ppt-designer.desc": "Structure, layout and speaker notes", + "skill.pdf-toolkit.name": "PDF tools", + "skill.pdf-toolkit.desc": "Merge, split, extract text — all on this machine", + "skill.image-compress.name": "Images", + "skill.image-compress.desc": "Shrink, resize and convert — nothing is uploaded", + "skill.qrcode-maker.name": "QR codes", + "skill.qrcode-maker.desc": "Links, text and WiFi details, generated offline", + "skill.web-to-markdown.name": "Save a web page", + "skill.web-to-markdown.desc": "Turn any article into clean Markdown", + "skill.linkedin-post.name": "LinkedIn posts", + "skill.linkedin-post.desc": "Hooks and structure, without the LinkedIn voice", + "skill.x-poster.name": "Posts for X", + "skill.x-poster.desc": "Short posts and threads that stand on their own", + "skill.tiktok-script.name": "TikTok scripts", + "skill.tiktok-script.desc": "Hooks that survive the first second", + "skill.youtube-script.name": "YouTube scripts", + "skill.youtube-script.desc": "Titles, the first 30 seconds, and chapters", + "skill.medium-writer.name": "Articles", + "skill.medium-writer.desc": "Long-form structure, and cutting the padding", + "skill.email-campaign.name": "Email campaigns", + "skill.email-campaign.desc": "Subject lines, one clear ask, PDPA-safe", + "skill.web-search.name": "Web search", + "skill.web-search.desc": "Find current information and read the sources", + "skill.sg-weather.name": "Singapore weather", + "skill.sg-weather.desc": "Forecast by area and air quality, from NEA", + "skill.sea-translate.name": "SEA translation", + "skill.sea-translate.desc": "English, Chinese, Malay, Tamil — and register", + "skill.claude-helper.name": "Better answers", + "skill.claude-helper.desc": "How to ask, and when to check the answer", + "skill.sg-transport.name": "Singapore transport", + "skill.sg-transport.desc": "Bus arrivals, MRT alerts, carpark lots", + "skill.meeting-notes.name": "Meeting notes", + "skill.meeting-notes.desc": "Decisions and owners, ready to send", + "cat.office": "Office", + "cat.data": "Data", + "cat.writing": "Writing", + "cat.files": "Files", + "cat.research": "Research", + "cat.social": "Social", + "cat.video": "Video", + "cat.language": "Language", + "cat.local": "Singapore", + "cat.ai": "Using AI", + "hub.lede": "These are on this drive already. Just ask for what you want — you do not have to name the skill.", + "hub.all": "All", + "hub.none": "Nothing in this category.", + "hub.add_note": "Skills live in the skills/ folder on this drive. Dropping a SKILL.md in there adds one." + }, + "zh-CN": { + "start.banner": "U-Claw · 便携 AI 助手", + "start.node_version": "Node.js {version}", + "start.quarantine_removing": "正在解除 macOS 安全限制…", + "start.cache_local": "缓存已放在本机硬盘:{path}", + "start.config_migrating": "正在迁移你原来的设置…", + "start.config_migrated": "设置已迁移。", + "start.config_creating": "第一次使用,正在准备…", + "start.config_created": "准备好了。", + "start.deps_preparing": "正在准备,约 20 秒。", + "start.deps_slow_drive": "这个 U 盘比较慢,可能要几分钟,放着就行。", + "start.deps_done": "准备好了。", + "start.no_proxy": "将直连你的模型地址:{hosts}", + "start.wechat_installing": "正在安装微信插件…", + "start.wechat_installed": "微信插件已安装。", + "start.config_center_starting": "正在启动控制台…", + "start.config_center_port": "控制台端口:{port}", + "start.port_in_use": "端口 {port} 被占用,换下一个…", + "start.gateway_starting": "正在启动 U-Claw,端口 {port}…", + "start.opening_screen": "正在打开启动页…", + "start.opening_config": "正在打开控制台…", + "start.running_title": "U-Claw 已启动", + "start.running_dashboard": "对话界面:{url}", + "start.running_config": "控制台: {url}", + "start.running_hint": "使用期间请不要关闭这个窗口。按 Ctrl+C 停止。", + "start.first_run_wait": "第一次从 U 盘启动需要 30–90 秒解压组件。控制台已经打开,可以先选模型、填密钥。", + "start.stopped": "U-Claw 已停止。", + "start.exited_unexpectedly": "U-Claw 自己退出了(代码 {code})。", + "error.node_missing.what": "U 盘里少了一个 U-Claw 需要的文件。", + "error.node_missing.why": "通常是拷贝到 U 盘时没有复制完整。", + "error.node_missing.action": "把 U-Claw 文件夹重新拷贝一遍,或运行 setup.sh 重建。", + "error.unsupported_arch.what": "这台 Mac 的处理器不受支持({arch})。", + "error.unsupported_arch.why": "U-Claw 只提供 Apple Silicon 和 Intel Mac 的版本。", + "error.unsupported_arch.action": "换一台电脑试试。", + "error.no_port.what": "U-Claw 找不到可用的端口来启动。", + "error.no_port.why": "{from}–{to} 都被占用了 —— 可能已经有一个 U-Claw 在运行。", + "error.no_port.action": "关掉已经在运行的那个窗口,再启动一次。", + "error.deps_failed.what": "U-Claw 没能准备完成。", + "error.deps_failed.why": "下载没有完成,通常是网络中断了。", + "error.deps_failed.action": "检查一下 Wi-Fi,然后重新启动 U-Claw。", + "error.press_enter": "按回车关闭这个窗口。", + "loading.title": "正在启动 U-Claw", + "loading.starting": "U-Claw 正在启动…", + "loading.first_run": "第一次从 U 盘启动需要展开内置组件,稍等片刻,就绪后会提示你下一步。", + "loading.waiting_gateway": "正在等待 U-Claw 启动…", + "loading.ready": "U-Claw 已就绪", + "loading.choose_next": "选择下一步 —— 直接开始聊天,或先去配置模型和渠道。", + "loading.open_dashboard": "🚀 开始聊天", + "loading.open_settings": "⚙️ 设置", + "loading.settings_hint": "填写或更换 API 密钥,连接聊天软件。", + "loading.no_model_hint": "还没配过模型?先打开设置填一个密钥。", + "loading.slow_drive_note": "慢 U 盘首次启动通常 30–90 秒。如果迟迟没反应,可以先打开设置:", + "loading.elapsed": "已等待 {seconds} 秒", + "loading.taking_long": "启动比平时慢,可以先打开设置:", + "welcome.title": "U-Claw 使用指南", + "welcome.subtitle": "装在 U 盘里的 AI 助手 · 三步开始", + "welcome.quickstart": "快速开始", + "welcome.step1_title": "1. 启动 U-Claw", + "welcome.step1_desc": "双击你电脑对应的那个文件:", + "welcome.step2_title": "2. 填一个密钥", + "welcome.step2_desc": "第一次启动会自动打开设置页。你需要一个 API 密钥才能开始 —— Google Gemini 最容易拿到:用 Google 账号登录即可,不用绑卡。", + "welcome.step2_link": "去领取免费的 Gemini 密钥 →", + "welcome.step3_title": "3. 开始对话", + "welcome.step3_desc": "密钥保存后,对话窗口会自己打开。就这样。", + "welcome.portable_note": "✅ 你的设置和聊天记录都存在盘上的 data/ 目录里,跟着盘走,Mac 和 Windows 通用。", + "welcome.models_title": "用哪个模型?", + "welcome.model_claude": "综合最强", + "welcome.model_gpt": "用的人最多", + "welcome.model_gemini": "有免费额度,注册最简单", + "welcome.model_local": "离线 · 数据不出本机", + "welcome.models_more": "更多选择在设置里,包括适合马来语、泰米尔语和 Singlish 的 SEA-LION。", + "welcome.trouble_title": "遇到问题?", + "welcome.trouble_lead": "💡 运行检查工具", + "welcome.trouble_desc": "如果 U-Claw 启动不了,双击:", + "welcome.open_settings": "打开设置", + "welcome.open_docs": "查看文档", + "nav.title": "U-Claw 启动导航", + "nav.tagline": "便携 AI 助手 — 插上就能用", + "nav.status_off": "U-Claw 尚未运行", + "nav.open_console": "打开它 →", + "nav.quickstart": "快速启动", + "nav.doubleclick": "双击", + "nav.step2": "第一次启动会自动打开设置页 —— 选一个模型,把密钥粘进去。", + "nav.mac_gatekeeper": "⚠️ 如果 macOS 提示「无法验证开发者」:右键点这个文件,选「打开」。", + "nav.config_shortcut": "📝 也可以双击 Config.html,它会带你到设置页。", + "nav.win_smartscreen": "⚠️ 如果 Windows 弹安全警告:点「更多信息」,再点「仍要运行」。", + "nav.everything": "其他功能", + "nav.menu_opens": "打开完整菜单:", + "nav.g_settings": "设置", + "nav.g_settings_d": "模型、密钥和聊天软件", + "nav.g_checkup": "检查修复", + "nav.g_checkup_d": "找出并修复常见问题", + "nav.g_backup": "备份", + "nav.g_backup_d": "一键保存设置和记忆", + "nav.g_skills": "技能", + "nav.g_skills_d": "看看 U-Claw 能做什么", + "nav.g_system": "系统信息", + "nav.g_system_d": "版本、端口、运行状态", + "nav.g_cli": "命令行", + "nav.g_cli_d": "给进阶用户", + "nav.models_title": "可以用的模型", + "nav.model_sealion": "马来语、泰米尔语和 Singlish", + "nav.model_local": "本地模型", + "nav.model_more": "更多", + "nav.model_more_d": "其他模型在设置里", + "nav.more_title": "更多", + "nav.link_guide": "使用指南", + "nav.link_guide_d": "三步上手", + "nav.link_skills": "技能", + "nav.link_skills_d": "看看 U-Claw 能做什么", + "nav.link_contact": "联系我们", + "nav.link_site": "官网", + "nav.status_on": "U-Claw 正在运行(端口 {port})", + "nav.status_off_hint": "U-Claw 尚未运行 —— 请先双击启动文件", + "key.page_title": "U-Claw 设置", + "key.page_subtitle": "粘贴一个 API 密钥就可以了。", + "key.checking": "检测中…", + "key.step_key": "填密钥", + "key.step_done": "完成", + "key.heading": "粘贴你的 API 密钥", + "key.desc": "剩下的 U-Claw 自己搞定。密钥只保存在这个 U 盘上,不会上传到任何地方。", + "key.placeholder": "sk-…", + "key.show": "显示", + "key.hide": "隐藏", + "key.continue": "继续 →", + "key.checking_key": "正在检查这个密钥…", + "key.ok": "✓ {provider} · 连接成功,用时 {ms} 毫秒", + "key.custom_provider": "你的地址", + "key.no_key_title": "还没有密钥?", + "key.no_key_desc": "Google Gemini 最容易拿到:用 Google 账号登录即可,不用绑卡,还有免费额度。", + "key.get_gemini": "🔑 领取免费的 Gemini 密钥", + "key.get_openrouter": "🔑 OpenRouter —— 一个密钥用多种模型", + "key.advanced": "高级 —— 手动填写接口地址", + "key.base_url": "接口地址", + "key.model_name": "模型名称", + "key.advanced_hint": "只有自建或未收录的服务才需要填。留空则由 U-Claw 自动判断。", + "key.saved": "已保存。", + "key.err_empty": "先粘贴一个密钥。", + "key.err_not_checked": "稍等,密钥还在检查中。", + "key.err_rejected": "这个密钥没被接受。检查一下是不是没复制全 —— 密钥很长,容易少一截。", + "key.err_quota": "这个密钥的额度用完了。去服务商那边充值,或者换一个密钥。", + "key.err_offline": "连不上网络。检查一下 Wi-Fi 再试。", + "key.err_timeout": "服务商没有及时响应。过一会儿再试。", + "key.err_model": "密钥是好的,但它指向的模型没找到。在「高级」里填写模型名称。", + "key.err_provider_down": "服务商那边现在有问题。稍后再试。", + "key.err_unrecognised": "U-Claw 认不出这个密钥。请在「高级」里填写接口地址和模型名称。", + "key.err_unknown": "没能检查这个密钥。再试一次,或者在「高级」里自己填接口地址。", + "key.err_save": "保存失败。确认 U 盘还插着,然后再试一次。", + "hub.title": "U-Claw 技能", + "done.title": "配置完成", + "done.subtitle": "模型和密钥已保存在这个 U 盘上。", + "done.open": "🚀 开始聊天", + "done.restart_note": "聊天软件的设置已保存,重启 U-Claw 后生效。", + "done.change_key": "换模型或密钥", + "done.view_config": "查看配置文件", + "ch.title": "📱 连接聊天软件(可选)", + "ch.desc": "点卡片展开填写,也可以直接跳过。", + "ch.whatsapp_d": "用 WhatsApp 和 U-Claw 对话", + "ch.whatsapp_warning": "⚠️ 这里用的是非官方协议,你的 WhatsApp 账号可能因此被封。不要接入你离不开的号码。", + "ch.whatsapp_number": "手机号", + "ch.telegram_d": "用 Telegram 和 U-Claw 对话", + "ch.telegram_get": "→ 从 @BotFather 获取", + "ch.slack_d": "在工作区里和 U-Claw 对话", + "ch.slack_get": "→ 在 api.slack.com 创建应用", + "ch.discord_d": "用 Discord 和 U-Claw 对话", + "ch.discord_get": "→ 在 Discord 开发者后台创建应用", + "ch.china_group": "主要在中国使用的聊天软件", + "ch.wechat_d": "扫码接入个人微信", + "ch.wechat_start": "点这张卡片开始扫码", + "ch.saved": "聊天软件设置已保存。", + "ch.err_save": "聊天软件设置没能保存。确认 U 盘还插着。", + "info.layout_title": "U 盘里有什么", + "info.layout_desc": "文件夹是怎么组织的", + "info.skills": "技能", + "info.skills_d": "把 SKILL.md 放进来就会自动加载", + "info.app": "运行时", + "info.app_d": "Node.js 和 OpenClaw 核心", + "info.data": "你的数据", + "info.data_d": "密钥和聊天记录,只留在这个盘上。", + "info.feedback_title": "遇到问题?", + "info.feedback_desc": "U-Claw 是开源项目。出问题欢迎去 GitHub 提 Issue —— 我们不会自动收集或上传你机器上的任何东西。", + "info.feedback_link": "→ 去 GitHub 提 Issue", + "wx.getting_qr": "正在获取二维码…", + "wx.scan": "请用微信扫描上方二维码", + "wx.qr_failed": "获取二维码失败", + "wx.connected": "✅ 微信已连接", + "wx.account": "账号", + "wx.restart_needed": "还差一步:重启 U-Claw(关掉再打开),微信才能用。", + "wx.connected_toast": "微信已连接,重启 U-Claw 后生效。", + "wx.qr_refreshed": "二维码已刷新,请重新扫码", + "wx.confirm_on_phone": "已扫码,请在手机上确认…", + "wx.qr_expired": "二维码已过期。", + "wx.qr_retry": "重新获取", + "wx.failed": "连接失败", + "info.read_config_failed": "读取配置文件失败:", + "status.running": "U-Claw 正在运行,端口 {port}", + "status.open_dashboard": "打开它 →", + "status.not_running": "U-Claw 尚未运行 —— 请先运行 Windows-Start.bat 或 Mac-Start.command", + "key.which_model": "用哪个模型?", + "start.opening_language": "正在询问使用哪种语言…", + "persona.title": "你主要用它做什么?", + "persona.subtitle": "这会帮你把合适的工具装好。以后可以改,也可以多选。", + "persona.continue": "继续 →", + "persona.skip": "跳过", + "persona.saving": "正在准备…", + "persona.err_offline": "U-Claw 还没启动。先启动它,再打开这个页面。", + "persona.err_save": "没能保存。确认 U 盘还插着,然后再试一次。", + "persona.developer": "写代码", + "persona.admin": "写文档、发邮件", + "persona.sales": "跟客户打交道", + "persona.marketing": "做内容、发社交媒体", + "persona.finance": "算数、做表格", + "persona.boss": "管公司", + "persona.general": "先随便看看", + "start.opening_persona": "正在询问你主要用它做什么…", + "tier.label": "想看到多少?", + "tier.simple": "只要最基本的", + "tier.standard": "多一点控制", + "tier.expert": "全部", + "tier.changed_simple": "已切换到简洁模式 —— 高级选项已隐藏。", + "tier.changed_standard": "已切换到标准模式 —— 现在可以换模型、接更多聊天软件了。", + "tier.changed_expert": "已切换到完整模式 —— 所有东西都可见,包括配置文件。", + "start.checking": "出了点问题,正在检查…", + "start.repaired": "已修复,重试一次。", + "start.diagnostics_written": "已把情况记录到:{path}", + "start.diagnostics_hint": "里面的密钥已被去掉。需要帮忙的话,把它发到 help@u-claw.org。", + "skill.excel-helper.name": "表格", + "skill.excel-helper.desc": "公式、透视表、图表、清洗乱数据", + "skill.word-writer.name": "文档", + "skill.word-writer.desc": "报告、方案、简历 —— 起草和排版", + "skill.ppt-designer.name": "幻灯片", + "skill.ppt-designer.desc": "结构、版式和演讲要点", + "skill.pdf-toolkit.name": "PDF 工具", + "skill.pdf-toolkit.desc": "合并、拆分、提取文字 —— 全在本机", + "skill.image-compress.name": "图片", + "skill.image-compress.desc": "压缩、改尺寸、转格式 —— 不上传", + "skill.qrcode-maker.name": "二维码", + "skill.qrcode-maker.desc": "网址、文本、WiFi,离线生成", + "skill.web-to-markdown.name": "保存网页", + "skill.web-to-markdown.desc": "把文章转成干净的 Markdown", + "skill.linkedin-post.name": "LinkedIn 帖子", + "skill.linkedin-post.desc": "钩子和结构,不要那股 LinkedIn 腔", + "skill.x-poster.name": "X 帖子", + "skill.x-poster.desc": "能独立成立的短帖和 thread", + "skill.tiktok-script.name": "TikTok 脚本", + "skill.tiktok-script.desc": "扛得住第一秒的钩子", + "skill.youtube-script.name": "YouTube 脚本", + "skill.youtube-script.desc": "标题、前 30 秒、章节", + "skill.medium-writer.name": "长文", + "skill.medium-writer.desc": "长文结构,以及怎么删水分", + "skill.email-campaign.name": "邮件营销", + "skill.email-campaign.desc": "标题、一个明确的 ask、符合 PDPA", + "skill.web-search.name": "网页搜索", + "skill.web-search.desc": "找当前信息并真的读来源", + "skill.sg-weather.name": "新加坡天气", + "skill.sg-weather.desc": "按区预报和空气质量,来自 NEA", + "skill.sea-translate.name": "东南亚翻译", + "skill.sea-translate.desc": "英 / 中 / 马来 / 泰米尔 —— 以及语域", + "skill.claude-helper.name": "问得更好", + "skill.claude-helper.desc": "怎么问,以及什么时候该核对答案", + "skill.sg-transport.name": "新加坡交通", + "skill.sg-transport.desc": "巴士到站、地铁故障、停车位", + "skill.meeting-notes.name": "会议纪要", + "skill.meeting-notes.desc": "决定和负责人,写完就能发", + "cat.office": "办公", + "cat.data": "数据", + "cat.writing": "写作", + "cat.files": "文件", + "cat.research": "资料", + "cat.social": "社交媒体", + "cat.video": "视频", + "cat.language": "语言", + "cat.local": "新加坡", + "cat.ai": "用好 AI", + "hub.lede": "这些已经在盘上了。直接说你想做什么就行,不用记技能名。", + "hub.all": "全部", + "hub.none": "这个分类下暂时没有。", + "hub.add_note": "技能放在盘上的 skills/ 目录里。丢一个 SKILL.md 进去就多一个。" + } +}; diff --git a/portable/lib/i18n/skills-data.js b/portable/lib/i18n/skills-data.js new file mode 100644 index 0000000..645b3c1 --- /dev/null +++ b/portable/lib/i18n/skills-data.js @@ -0,0 +1,281 @@ +/* GENERATED FILE — do not edit. + * Source: skills/manifest.json + * Regenerate: node lib/i18n/build-messages.mjs + */ +window.UCLAW_SKILLS = { + "personas": [ + { + "id": "developer", + "tier": "expert", + "emoji": "💻", + "channel": null + }, + { + "id": "admin", + "tier": "simple", + "emoji": "📝", + "channel": null + }, + { + "id": "sales", + "tier": "simple", + "emoji": "💬", + "channel": "whatsapp" + }, + { + "id": "marketing", + "tier": "standard", + "emoji": "🎨", + "channel": null + }, + { + "id": "finance", + "tier": "standard", + "emoji": "📊", + "channel": null + }, + { + "id": "boss", + "tier": "simple", + "emoji": "👔", + "channel": null + }, + { + "id": "general", + "tier": "simple", + "emoji": "🤷", + "channel": null + } + ], + "skills": [ + { + "id": "excel-helper", + "categories": [ + "office", + "data" + ], + "personas": [ + "admin", + "finance", + "boss", + "general" + ], + "emoji": "📊" + }, + { + "id": "word-writer", + "categories": [ + "office", + "writing" + ], + "personas": [ + "admin", + "sales", + "boss", + "general" + ], + "emoji": "📝" + }, + { + "id": "ppt-designer", + "categories": [ + "office", + "writing" + ], + "personas": [ + "admin", + "sales", + "marketing", + "boss" + ], + "emoji": "📽️" + }, + { + "id": "pdf-toolkit", + "categories": [ + "files" + ], + "personas": [ + "admin", + "finance", + "general" + ], + "emoji": "📄" + }, + { + "id": "image-compress", + "categories": [ + "files" + ], + "personas": [ + "marketing", + "general" + ], + "emoji": "🖼️" + }, + { + "id": "qrcode-maker", + "categories": [ + "files" + ], + "personas": [ + "marketing", + "sales", + "general" + ], + "emoji": "🔳" + }, + { + "id": "web-to-markdown", + "categories": [ + "research" + ], + "personas": [ + "developer", + "marketing", + "general" + ], + "emoji": "🔗" + }, + { + "id": "linkedin-post", + "categories": [ + "social" + ], + "personas": [ + "marketing", + "sales", + "boss" + ], + "emoji": "💼" + }, + { + "id": "x-poster", + "categories": [ + "social" + ], + "personas": [ + "marketing" + ], + "emoji": "🐦" + }, + { + "id": "tiktok-script", + "categories": [ + "social", + "video" + ], + "personas": [ + "marketing" + ], + "emoji": "🎬" + }, + { + "id": "youtube-script", + "categories": [ + "social", + "video" + ], + "personas": [ + "marketing" + ], + "emoji": "📺" + }, + { + "id": "medium-writer", + "categories": [ + "writing" + ], + "personas": [ + "marketing", + "developer" + ], + "emoji": "✍️" + }, + { + "id": "email-campaign", + "categories": [ + "writing", + "social" + ], + "personas": [ + "marketing", + "sales" + ], + "emoji": "✉️" + }, + { + "id": "web-search", + "categories": [ + "research" + ], + "personas": [ + "developer", + "marketing", + "general", + "finance" + ], + "emoji": "🔍" + }, + { + "id": "sg-weather", + "categories": [ + "local" + ], + "personas": [ + "general", + "sales" + ], + "emoji": "🌦️" + }, + { + "id": "sea-translate", + "categories": [ + "language" + ], + "personas": [ + "sales", + "admin", + "marketing", + "general", + "boss" + ], + "emoji": "🌏" + }, + { + "id": "claude-helper", + "categories": [ + "ai" + ], + "personas": [ + "developer", + "finance" + ], + "emoji": "🤖" + }, + { + "id": "sg-transport", + "categories": [ + "local" + ], + "personas": [ + "general", + "sales" + ], + "emoji": "🚇" + }, + { + "id": "meeting-notes", + "categories": [ + "writing" + ], + "personas": [ + "sales", + "admin", + "boss", + "finance" + ], + "emoji": "🗒️" + } + ] +}; diff --git a/portable/lib/intranet-check.mjs b/portable/lib/intranet-check.mjs index cb8db8e..48b5b8b 100644 --- a/portable/lib/intranet-check.mjs +++ b/portable/lib/intranet-check.mjs @@ -83,7 +83,7 @@ async function chatProbe(t) { const res = await requestText(url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(t.apiKey ? { Authorization: `Bearer ${t.apiKey}` } : {}) }, - body: JSON.stringify({ model: t.modelId, messages: [{ role: 'user', content: '请回复四个字:连接成功' }], max_tokens: 64, stream: false }), + body: JSON.stringify({ model: t.modelId, messages: [{ role: 'user', content: 'Reply with exactly: connection ok' }], max_tokens: 64, stream: false }), timeoutMs: CHAT_TIMEOUT_MS, }); const ms = Date.now() - started; @@ -126,76 +126,77 @@ function requestText(rawUrl, { method = 'GET', headers = {}, body, timeoutMs }) async function main() { const configPath = process.argv[2] || process.env.OPENCLAW_CONFIG_PATH; line('========================================'); - line(' U-Claw 内网体检 / Intranet Check'); + line(' U-Claw — corporate network check'); line(` Node ${process.version}`); line('========================================'); line(''); // 1) 代理环境 - line('【1】代理环境检查'); + line('[1] System proxy'); const proxyKeys = ['HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'http_proxy', 'https_proxy', 'all_proxy']; const setProxies = proxyKeys.filter((k) => process.env[k]); if (setProxies.length) { for (const k of setProxies) line(` ${k} = ${process.env[k]}`); - line(' → 检测到系统代理。发往内网模型的请求可能被它劫持(最常见的内网故障源)。'); + line(' A system proxy is set. Requests to an internal model endpoint may be routed through it — this is the single most common cause of a self-hosted model not working.'); } else { - line(' (未检测到系统代理)'); + line(' No system proxy set.'); } line(''); - if (!configPath) { line('未提供配置路径,结束。'); return; } + if (!configPath) { line('No config path given — nothing to check.'); return; } let config; try { config = JSON.parse(readFileSync(configPath, 'utf8')); } - catch (e) { line(`读取配置失败:${e?.message || e}`); return; } + catch (e) { line(`Could not read the config file: ${e?.message || e}`); return; } const providers = collectProviders(config?.models); - if (!providers.length) { line('配置里没有任何模型地址(baseUrl)。先配好模型再来跑。'); return; } + if (!providers.length) { line('No model endpoint is configured yet. Set one up in Settings first, then run this again.'); return; } // 2) NO_PROXY 建议 const hosts = Array.from(new Set(providers.map((p) => hostOf(p.baseUrl)).filter(Boolean))); const noProxy = applyNoProxy(hosts); - line('【2】建议的 NO_PROXY(让这些地址直连、绕开代理)'); + line('[2] Suggested NO_PROXY — hosts that should bypass the proxy'); line(` ${noProxy.join(',')}`); - line(' (新版 Windows-Start.bat 已会自动设置,无需手动操作)'); + line(' U-Claw already sets this for you at startup. Shown here in case you need it elsewhere.'); line(''); // 3) 直连可达 - line('【3】直连测试(绕过代理,看能否摸到模型服务)'); + line('[3] Direct connection — can this machine reach the model at all, proxy bypassed'); for (const p of providers) { const r = await reachProbe(p.baseUrl, p.apiKey); - if (r.ok) line(` [${p.name}] ${p.baseUrl} → ✓ 可达 HTTP ${r.status} (${r.ms}ms)`); - else line(` [${p.name}] ${p.baseUrl} → ✗ 失败 ${r.error} (${r.ms}ms)`); + if (r.ok) line(` [${p.name}] ${p.baseUrl} -> reachable, HTTP ${r.status} (${r.ms}ms)`); + else line(` [${p.name}] ${p.baseUrl} -> FAILED ${r.error} (${r.ms}ms)`); } line(''); // 4) 端到端实测 - line('【4】实测:真发一条对话给模型'); + line('[4] Real request — actually asking the model something'); const t = pickTarget(config, providers); - if (!t) { line(' 找不到可测的模型 id,跳过。'); } + if (!t) { line(' No model ID to test with — skipped.'); } else { - line(` 模型:${t.provName} / ${t.modelId}`); - line(' 发送中,请稍候...'); + line(` Model: ${t.provName} / ${t.modelId}`); + line(' Sending…'); const c = await chatProbe(t); if (c.ok) { line(''); - line(` ✓✓ 跑通了!模型回复 (${c.ms}ms):${c.reply.slice(0, 120) || '(空回复但请求成功)'}`); + line(` It works. The model replied in ${c.ms}ms: ${c.reply.slice(0, 120) || '(empty reply, but the request succeeded)'}`); } else if (c.status) { line(''); - line(` ✗ 服务端 HTTP ${c.status} (${c.ms}ms):${c.body}`); + line(` The server answered with HTTP ${c.status} in ${c.ms}ms: ${c.body}`); } else { line(''); - line(` ✗ 直连失败:${c.error} (${c.ms}ms)`); + line(` Could not connect: ${c.error} (${c.ms}ms)`); } } line(''); // 结论 line('========================================'); - line(' 怎么看结果:'); - line(' · 第4步「跑通了」 → 一切正常,以后双击 Windows-Start.bat 即可。'); - line(' · 第3步可达但程序里用不了 → 是系统代理在劫持,新版启动脚本已自动绕开(NO_PROXY)。'); - line(' · 第3步「直连失败/超时」 → 地址错 / 内网不通 / 防火墙 / 模型服务没起,找机房管理员。'); - line(' · 出现 401/403 → 网络是通的,只是 API Key 不对。'); + line(' What the results mean:'); + line(' Step 4 worked Everything is fine. Start U-Claw normally.'); + line(' Step 3 reachable but A proxy is intercepting the request. U-Claw already') + line(' the app cannot use it bypasses it at startup via NO_PROXY.'); + line(' Step 3 failed Wrong address, blocked network, firewall, or the service is down. Ask whoever runs the server.'); + line(' 401 or 403 The network is fine — the key is wrong.'); line('========================================'); } diff --git a/portable/lib/language.html b/portable/lib/language.html new file mode 100644 index 0000000..70ee314 --- /dev/null +++ b/portable/lib/language.html @@ -0,0 +1,101 @@ + + + + + +U-Claw + + + + +
🦞
+
+ + +
+

+ + + + diff --git a/portable/lib/loading.html b/portable/lib/loading.html index 2af204b..8fec06c 100644 --- a/portable/lib/loading.html +++ b/portable/lib/loading.html @@ -1,9 +1,9 @@ - + -U-Claw 正在启动… +Starting U-Claw +
-

U-Claw 正在启动

-
首次从 U 盘启动需要展开内置组件,
稍等片刻,就绪后会提示你下一步。
+

Starting U-Claw…

+
First run from a USB drive unpacks the bundled components. Give it a moment — you will be told when it is ready.
-
正在等待 OpenClaw 网关…
+
Waiting for U-Claw to come up…
- 慢 U 盘首次启动通常 30–90 秒。
- 如果迟迟没反应,可先打开 - 配置中心。 + A slow drive usually takes 30–90 seconds. If nothing happens for a long time, open Settings: + ⚙️ Settings
- +
-

U-Claw 已就绪

-
选择下一步 — 直接开始聊天,或先去配置模型和渠道。
+

U-Claw is ready

+
Pick what to do next — start chatting, or set up your model and channels first.
-
没配过模型或余额不足?先点「配置 / 改模型」处理 Key 或充值。
+
No model set up yet? Open Settings first to add a key.
@@ -156,7 +157,7 @@ body.ready .ready-wrap { display: block; } function fmt(ms) { var s = Math.floor(ms / 1000); - return '已等待 ' + s + ' 秒'; + return window.UClawI18n ? window.UClawI18n.t('loading.elapsed', { seconds: s }) : s + 's'; } function tickElapsed() { @@ -187,8 +188,10 @@ body.ready .ready-wrap { display: block; } // 兜底:5 分钟还没起来,提示去控制台 setTimeout(function () { if (!ready) { + var label = window.UClawI18n ? window.UClawI18n.t('loading.open_settings') : 'Settings'; + var slow = window.UClawI18n ? window.UClawI18n.t('loading.taking_long') : 'This is taking longer than usual. You can open Settings while you wait:'; document.getElementById('status').innerHTML = - '启动较慢,可先打开 配置中心 检查'; + slow + ' ' + label + ''; } }, 300000); })(); diff --git a/portable/lib/maintain.sh b/portable/lib/maintain.sh index f555c04..831b368 100644 --- a/portable/lib/maintain.sh +++ b/portable/lib/maintain.sh @@ -26,7 +26,7 @@ detect_install_mode() { do_kill_gateway() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 杀死残留进程 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Stop leftover processes ---${NC}" echo "" local FOUND=0 @@ -42,7 +42,7 @@ do_kill_gateway() { if [ -n "$PIDS" ]; then for PID in $PIDS; do local CMD=$(ps -p "$PID" -o comm= 2>/dev/null || echo "unknown") - echo -e " ${YELLOW}端口 $PORT: PID $PID ($CMD)${NC}" + echo -e " ${YELLOW}Port $PORT: PID $PID ($CMD)${NC}" FOUND=1 done fi @@ -52,20 +52,20 @@ do_kill_gateway() { local OC_PIDS=$(pgrep -f "openclaw.mjs gateway" 2>/dev/null) if [ -n "$OC_PIDS" ]; then for PID in $OC_PIDS; do - echo -e " ${YELLOW}OpenClaw 网关进程: PID $PID${NC}" + echo -e " ${YELLOW}OpenClaw gateway: PID $PID${NC}" FOUND=1 done fi if [ "$FOUND" = "0" ]; then - echo -e " ${GREEN}没有发现残留进程${NC}" + echo -e " ${GREEN}Nothing left running${NC}" return fi echo "" - read -p " 确认杀死以上进程? (y/N): " CONFIRM + read -p " Stop these? (y/N): " CONFIRM if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi @@ -82,24 +82,24 @@ do_kill_gateway() { pgrep -f "openclaw.mjs gateway" 2>/dev/null | xargs kill 2>/dev/null sleep 1 - echo -e " ${GREEN}进程已清理${NC}" + echo -e " ${GREEN}Processes stopped${NC}" } # ── [10] View/export/clean logs ────────────────────────────── do_logs() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 日志管理 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Logs ---${NC}" echo "" mkdir -p "$LOG_DIR" local LOG_FILE="$LOG_DIR/gateway.log" - echo -e " ${GREEN}[a]${NC} 查看最近日志(最后 50 行)" - echo -e " ${GREEN}[b]${NC} 导出日志到桌面" - echo -e " ${GREEN}[c]${NC} 清理 7 天前的旧日志" + echo -e " ${GREEN}[a]${NC} Show the last 50 lines" + echo -e " ${GREEN}[b]${NC} Copy the log to the desktop" + echo -e " ${GREEN}[c]${NC} Delete logs older than 7 days" echo "" - read -p " 选择 (a-c): " -n 1 LOG_CHOICE + read -p " Choose (a-c): " -n 1 LOG_CHOICE echo "" echo "" @@ -110,13 +110,13 @@ do_logs() { echo "" tail -50 "$LOG_FILE" else - echo -e " ${YELLOW}日志文件不存在: $LOG_FILE${NC}" - echo " 启动网关后会自动生成日志。" + echo -e " ${YELLOW}No log file yet: $LOG_FILE${NC}" + echo " One is created the first time U-Claw runs." fi ;; b) if [ ! -f "$LOG_FILE" ]; then - echo -e " ${YELLOW}没有日志可导出${NC}" + echo -e " ${YELLOW}No log to copy${NC}" return fi local TS=$(date +%Y%m%d_%H%M%S) @@ -124,26 +124,26 @@ do_logs() { [ ! -d "$EXPORT_DIR" ] && EXPORT_DIR="$HOME" local EXPORT_FILE="$EXPORT_DIR/uclaw-logs-$TS.txt" cp "$LOG_FILE" "$EXPORT_FILE" - echo -e " ${GREEN}日志已导出: $EXPORT_FILE${NC}" - echo " 大小: $(du -sh "$EXPORT_FILE" | cut -f1)" + echo -e " ${GREEN}Copied to: $EXPORT_FILE${NC}" + echo " Size: $(du -sh "$EXPORT_FILE" | cut -f1)" ;; c) local COUNT=$(find "$LOG_DIR" -name "*.log" -mtime +7 2>/dev/null | wc -l | tr -d ' ') if [ "$COUNT" = "0" ]; then - echo -e " ${GREEN}没有需要清理的旧日志${NC}" + echo -e " ${GREEN}No old logs to delete${NC}" return fi - echo -e " 找到 ${YELLOW}$COUNT${NC} 个超过 7 天的日志文件" - read -p " 确认清理? (y/N): " CONFIRM + echo -e " Found ${YELLOW}$COUNT${NC} log files older than 7 days" + read -p " Delete them? (y/N): " CONFIRM if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then find "$LOG_DIR" -name "*.log" -mtime +7 -delete 2>/dev/null - echo -e " ${GREEN}旧日志已清理${NC}" + echo -e " ${GREEN}Old logs deleted${NC}" else - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" fi ;; *) - echo -e " ${RED}无效选择${NC}" + echo -e " ${RED}Not a valid choice${NC}" ;; esac } @@ -152,46 +152,46 @@ do_logs() { do_factory_reset() { echo "" - echo -e " ${RED}${BOLD}━━━ 恢复出厂设置 ━━━${NC}" + echo -e " ${RED}${BOLD}--- Reset to factory settings ---${NC}" echo "" - echo -e " ${RED}警告: 此操作将删除所有配置和记忆数据!${NC}" + echo -e " ${RED}This deletes every setting and everything the AI remembers.${NC}" echo "" - echo " 将执行以下操作:" - echo " 1. 自动备份当前配置和记忆" - echo " 2. 删除配置文件 (openclaw.json)" - echo " 3. 删除记忆数据 (memory/)" - echo " 4. 恢复默认配置" + echo " It will:" + echo " 1. Back up your settings and memory first" + echo " 2. Delete openclaw.json" + echo " 3. Delete memory/" + echo " 4. Put the defaults back" echo "" - echo -e " ${YELLOW}请输入 RESET 确认(区分大小写):${NC}" + echo -e " ${YELLOW}Type RESET to confirm (case-sensitive):${NC}" read -p " > " CONFIRM if [ "$CONFIRM" != "RESET" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi # Step 1: Auto backup echo "" - echo -e " ${CYAN}[1/4] 自动备份...${NC}" + echo -e " ${CYAN}[1/4] Backing up…${NC}" local TS=$(date +%Y%m%d_%H%M%S) local BK="$BACKUP_DIR/pre-reset_$TS" mkdir -p "$BK" [ -f "$CONFIG_PATH" ] && cp "$CONFIG_PATH" "$BK/" 2>/dev/null [ -d "$DATA_DIR/memory" ] && cp -R "$DATA_DIR/memory" "$BK/" 2>/dev/null - echo -e " ${GREEN}备份已保存: $BK${NC}" + echo -e " ${GREEN}Backup saved to $BK${NC}" # Step 2: Delete config - echo -e " ${CYAN}[2/4] 删除配置...${NC}" + echo -e " ${CYAN}[2/4] Removing settings…${NC}" rm -f "$CONFIG_PATH" 2>/dev/null rm -f "$DATA_DIR/config.json" 2>/dev/null # Step 3: Delete memory - echo -e " ${CYAN}[3/4] 清理记忆数据...${NC}" + echo -e " ${CYAN}[3/4] Removing memory…${NC}" rm -rf "$DATA_DIR/memory" 2>/dev/null mkdir -p "$DATA_DIR/memory" # Step 4: Restore default config - echo -e " ${CYAN}[4/4] 恢复默认配置...${NC}" + echo -e " ${CYAN}[4/4] Restoring defaults…${NC}" mkdir -p "$STATE_DIR" if [ -f "$DEFAULT_CONFIG" ]; then cp "$DEFAULT_CONFIG" "$CONFIG_PATH" @@ -207,75 +207,75 @@ CFGEOF fi echo "" - echo -e " ${GREEN}出厂设置已恢复!${NC}" - echo -e " 备份位置: $BK" - echo -e " 请重新运行配置向导 [1] 设置模型。" + echo -e " ${GREEN}Reset complete.${NC}" + echo -e " Your old settings are at $BK" + echo -e " Run the setup wizard again to add a model." } # ── [12] Uninstall ─────────────────────────────────────────── do_uninstall() { echo "" - echo -e " ${RED}${BOLD}━━━ 卸载 U-Claw ━━━${NC}" + echo -e " ${RED}${BOLD}--- Uninstall U-Claw ---${NC}" echo "" local MODE=$(detect_install_mode) case $MODE in installed) - echo " 检测到: 已安装版本 (~/.uclaw/)" + echo " Found: installed copy at ~/.uclaw/" echo "" - echo " 将删除以下目录:" + echo " These folders will be deleted:" echo -e " ${YELLOW}$HOME/.uclaw/${NC}" if [ -d "$HOME/.uclaw" ]; then - echo " 大小: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)" + echo " Size: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)" fi echo "" - echo -e " ${RED}请输入 UNINSTALL 确认:${NC}" + echo -e " ${RED}Type UNINSTALL to confirm:${NC}" read -p " > " CONFIRM if [ "$CONFIRM" != "UNINSTALL" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi rm -rf "$HOME/.uclaw" - echo -e " ${GREEN}卸载完成!${NC}" + echo -e " ${GREEN}Uninstalled.${NC}" ;; usb) - echo " 检测到: U 盘模式" + echo " Found: running from a USB drive" echo "" - echo " 便携版不需要卸载 —— 只需:" - echo " 1. 关闭所有 U-Claw 窗口" - echo " 2. 安全弹出 U 盘" - echo " 3. 如需清理电脑上的数据,删除 ~/.uclaw/ (如果存在)" + echo " There is nothing to uninstall. Just:" + echo " 1. Close every U-Claw window" + echo " 2. Eject the drive" + echo " 3. If you want nothing left on this computer, delete ~/.uclaw/" echo "" if [ -d "$HOME/.uclaw" ]; then - echo -e " ${YELLOW}发现本机数据: ~/.uclaw/${NC}" - echo " 大小: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)" - read -p " 是否删除本机数据? (y/N): " DEL + echo -e " ${YELLOW}Found data on this computer: ~/.uclaw/${NC}" + echo " Size: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)" + read -p " Delete it? (y/N): " DEL if [ "$DEL" = "y" ] || [ "$DEL" = "Y" ]; then rm -rf "$HOME/.uclaw" - echo -e " ${GREEN}本机数据已清理${NC}" + echo -e " ${GREEN}Deleted${NC}" fi fi ;; portable) - echo " 检测到: 便携版本" + echo " Found: portable copy" echo "" - echo " 便携版不需要卸载 —— 直接删除文件夹即可:" + echo " There is nothing to uninstall — just delete the folder:" echo -e " ${YELLOW}$UCLAW_DIR${NC}" echo "" if [ -d "$HOME/.uclaw" ]; then - echo -e " ${YELLOW}发现本机数据: ~/.uclaw/${NC}" - echo " 大小: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)" - read -p " 是否删除本机数据? (y/N): " DEL + echo -e " ${YELLOW}Found data on this computer: ~/.uclaw/${NC}" + echo " Size: $(du -sh "$HOME/.uclaw" 2>/dev/null | cut -f1)" + read -p " Delete it? (y/N): " DEL if [ "$DEL" = "y" ] || [ "$DEL" = "Y" ]; then rm -rf "$HOME/.uclaw" - echo -e " ${GREEN}本机数据已清理${NC}" + echo -e " ${GREEN}Deleted${NC}" fi fi echo "" - echo " Electron 桌面版卸载:" - echo " macOS: 将 U-Claw.app 从「应用程序」拖到废纸篓" + echo " Electron desktop app:" + echo " macOS: drag U-Claw.app from Applications to the Trash" ;; esac } @@ -284,15 +284,15 @@ do_uninstall() { do_update() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 检查更新 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Check for updates ---${NC}" echo "" if [ ! -f "$NODE_BIN" ]; then - echo -e " ${RED}Node.js 未找到,无法检查更新${NC}" + echo -e " ${RED}Node.js is missing, so updates cannot be checked${NC}" return fi - echo -e " ${DIM}正在查询最新版本...${NC}" + echo -e " ${DIM}Looking up the latest version…${NC}" # Get current version local CUR_VER="" @@ -301,58 +301,58 @@ do_update() { fi if [ -z "$CUR_VER" ]; then - echo -e " ${RED}无法读取当前版本(OpenClaw 可能未安装)${NC}" + echo -e " ${RED}Cannot read the installed version — OpenClaw may not be installed${NC}" return fi - # Get latest version from npmmirror - local LATEST_VER=$(curl -s --connect-timeout 10 "https://registry.npmmirror.com/openclaw/latest" 2>/dev/null | "$NODE_BIN" -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).version)}catch(e){console.log('error')}})" 2>/dev/null) + # Get latest version from the npm registry + local LATEST_VER=$(curl -s --connect-timeout 10 "https://registry.npmjs.org/openclaw/latest" 2>/dev/null | "$NODE_BIN" -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).version)}catch(e){console.log('error')}})" 2>/dev/null) if [ -z "$LATEST_VER" ] || [ "$LATEST_VER" = "error" ]; then - echo -e " ${YELLOW}无法获取最新版本(网络问题?)${NC}" - echo " 当前版本: $CUR_VER" + echo -e " ${YELLOW}Could not reach the registry. Check your network.${NC}" + echo " Installed: $CUR_VER" return fi - echo " 当前版本: $CUR_VER" - echo " 最新版本: $LATEST_VER" + echo " Installed: $CUR_VER" + echo " Latest: $LATEST_VER" echo "" if [ "$CUR_VER" = "$LATEST_VER" ]; then - echo -e " ${GREEN}已是最新版本!${NC}" + echo -e " ${GREEN}Already up to date.${NC}" return fi - echo -e " ${YELLOW}有新版本可用!${NC}" - read -p " 是否立即升级? (y/N): " DO_UPDATE + echo -e " ${YELLOW}A newer version is available.${NC}" + read -p " Update now? (y/N): " DO_UPDATE if [ "$DO_UPDATE" != "y" ] && [ "$DO_UPDATE" != "Y" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi echo "" - echo -e " ${CYAN}正在升级...${NC}" + echo -e " ${CYAN}Updating…${NC}" cd "$CORE_DIR" - "$NPM_BIN" install openclaw@latest --registry=https://registry.npmmirror.com 2>&1 + "$NPM_BIN" install openclaw@latest --registry=https://registry.npmjs.org 2>&1 local NEW_VER=$("$NODE_BIN" -e "console.log(require('./node_modules/openclaw/package.json').version)" 2>/dev/null) echo "" - echo -e " ${GREEN}升级完成!${NC} $CUR_VER → $NEW_VER" + echo -e " ${GREEN}Updated.${NC} $CUR_VER → $NEW_VER" } # ── [14] Disk cleanup (P1) ─────────────────────────────────── do_cleanup() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 清理空间 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Free up space ---${NC}" echo "" # Show directory sizes - echo -e " ${WHITE}目录占用:${NC}" + echo -e " ${WHITE}Space used:${NC}" [ -d "$CORE_DIR/node_modules" ] && echo " node_modules: $(du -sh "$CORE_DIR/node_modules" 2>/dev/null | cut -f1)" [ -d "$DATA_DIR/memory" ] && echo " memory: $(du -sh "$DATA_DIR/memory" 2>/dev/null | cut -f1)" [ -d "$BACKUP_DIR" ] && echo " backups: $(du -sh "$BACKUP_DIR" 2>/dev/null | cut -f1)" [ -d "$LOG_DIR" ] && echo " logs: $(du -sh "$LOG_DIR" 2>/dev/null | cut -f1)" - echo " 总计: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)" + echo " Total: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)" echo "" local CLEANED=0 @@ -362,17 +362,17 @@ do_cleanup() { local BK_COUNT=$(ls -d "$BACKUP_DIR"/*/ 2>/dev/null | wc -l | tr -d ' ') if [ "$BK_COUNT" -gt 3 ]; then local OLD_COUNT=$((BK_COUNT - 3)) - echo -e " ${YELLOW}发现 $BK_COUNT 个备份,保留最新 3 个,删除 $OLD_COUNT 个旧备份${NC}" - read -p " 确认? (y/N): " DEL_BK + echo -e " ${YELLOW}Found $BK_COUNT backups. Keeping the newest 3, deleting $OLD_COUNT.${NC}" + read -p " Go ahead? (y/N): " DEL_BK if [ "$DEL_BK" = "y" ] || [ "$DEL_BK" = "Y" ]; then ls -dt "$BACKUP_DIR"/*/ 2>/dev/null | tail -n "$OLD_COUNT" | while read -r DIR; do rm -rf "$DIR" done - echo -e " ${GREEN}旧备份已清理${NC}" + echo -e " ${GREEN}Old backups deleted${NC}" CLEANED=1 fi else - echo " 备份: ${BK_COUNT} 个(无需清理)" + echo " Backups: ${BK_COUNT} — nothing to clear" fi fi @@ -380,33 +380,33 @@ do_cleanup() { if [ -d "$LOG_DIR" ]; then local OLD_LOGS=$(find "$LOG_DIR" -name "*.log" -mtime +7 2>/dev/null | wc -l | tr -d ' ') if [ "$OLD_LOGS" -gt 0 ]; then - echo -e " ${YELLOW}发现 $OLD_LOGS 个超过 7 天的日志${NC}" - read -p " 确认清理? (y/N): " DEL_LOG + echo -e " ${YELLOW}Found $OLD_LOGS log files older than 7 days${NC}" + read -p " Delete them? (y/N): " DEL_LOG if [ "$DEL_LOG" = "y" ] || [ "$DEL_LOG" = "Y" ]; then find "$LOG_DIR" -name "*.log" -mtime +7 -delete 2>/dev/null - echo -e " ${GREEN}旧日志已清理${NC}" + echo -e " ${GREEN}Old logs deleted${NC}" CLEANED=1 fi else - echo " 日志: 无需清理" + echo " Logs: nothing to clear" fi fi # Clean npm cache echo "" - read -p " 是否清理 npm 缓存? (y/N): " DEL_CACHE + read -p " Clear the npm cache? (y/N): " DEL_CACHE if [ "$DEL_CACHE" = "y" ] || [ "$DEL_CACHE" = "Y" ]; then "$NPM_BIN" cache clean --force 2>/dev/null - echo -e " ${GREEN}npm 缓存已清理${NC}" + echo -e " ${GREEN}npm cache cleared${NC}" CLEANED=1 fi if [ "$CLEANED" = "0" ]; then echo "" - echo -e " ${GREEN}没有需要清理的内容${NC}" + echo -e " ${GREEN}Nothing to clear${NC}" else echo "" - echo " 清理后总计: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)" + echo " Now using: $(du -sh "$UCLAW_DIR" 2>/dev/null | cut -f1)" fi } @@ -414,56 +414,56 @@ do_cleanup() { do_plugins() { echo "" - echo -e " ${CYAN}${BOLD}━━━ 插件管理 ━━━${NC}" + echo -e " ${CYAN}${BOLD}--- Plugins ---${NC}" echo "" - echo -e " ${GREEN}[a]${NC} 列出已安装插件" - echo -e " ${GREEN}[b]${NC} 安装插件" - echo -e " ${GREEN}[c]${NC} 卸载插件" + echo -e " ${GREEN}[a]${NC} List installed plugins" + echo -e " ${GREEN}[b]${NC} Install a plugin" + echo -e " ${GREEN}[c]${NC} Remove a plugin" echo "" - read -p " 选择 (a-c): " -n 1 PLG_CHOICE + read -p " Choose (a-c): " -n 1 PLG_CHOICE echo "" echo "" case $PLG_CHOICE in a) - echo -e " ${WHITE}已安装插件:${NC}" + echo -e " ${WHITE}Installed plugins:${NC}" echo "" - run_oc plugins list 2>&1 || echo -e " ${YELLOW}无法获取插件列表${NC}" + run_oc plugins list 2>&1 || echo -e " ${YELLOW}Could not list plugins${NC}" ;; b) - echo " 常用插件:" - echo " @icesword760/openclaw-wechat — 微信" - echo " @nicepkg/openclaw-plugin-qq — QQ(社区版)" + echo " Commonly used:" + echo " @icesword760/openclaw-wechat WeChat" + echo " @nicepkg/openclaw-plugin-qq QQ (community build)" echo "" - read -p " 输入插件名称(留空取消): " PLG_NAME + read -p " Plugin name (blank to cancel): " PLG_NAME if [ -z "$PLG_NAME" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi echo "" - echo -e " ${CYAN}正在安装 $PLG_NAME ...${NC}" + echo -e " ${CYAN}Installing $PLG_NAME…${NC}" run_oc plugins install "$PLG_NAME" 2>&1 echo "" - echo -e " ${GREEN}安装完成${NC}" + echo -e " ${GREEN}Installed${NC}" ;; c) - echo -e " ${WHITE}已安装插件:${NC}" + echo -e " ${WHITE}Installed plugins:${NC}" echo "" run_oc plugins list 2>&1 || true echo "" - read -p " 输入要卸载的插件名称(留空取消): " PLG_NAME + read -p " Plugin to remove (blank to cancel): " PLG_NAME if [ -z "$PLG_NAME" ]; then - echo -e " ${YELLOW}已取消${NC}" + echo -e " ${YELLOW}Cancelled${NC}" return fi echo "" - echo -e " ${CYAN}正在卸载 $PLG_NAME ...${NC}" + echo -e " ${CYAN}Removing $PLG_NAME…${NC}" run_oc plugins remove "$PLG_NAME" 2>&1 echo "" - echo -e " ${GREEN}卸载完成${NC}" + echo -e " ${GREEN}Removed${NC}" ;; *) - echo -e " ${RED}无效选择${NC}" + echo -e " ${RED}Not a valid choice${NC}" ;; esac } diff --git a/portable/lib/messages/en.json b/portable/lib/messages/en.json new file mode 100644 index 0000000..abbe898 --- /dev/null +++ b/portable/lib/messages/en.json @@ -0,0 +1,279 @@ +{ + "start.banner": "U-Claw · Portable AI Agent", + "start.node_version": "Node.js {version}", + "start.quarantine_removing": "Clearing the macOS security flag…", + "start.cache_local": "Cache on local disk: {path}", + "start.config_migrating": "Bringing your old settings across…", + "start.config_migrated": "Settings moved over.", + "start.config_creating": "First run — setting things up…", + "start.config_created": "Ready.", + "start.deps_preparing": "Getting things ready — about 20 seconds.", + "start.deps_slow_drive": "This drive is slow, so it may take a few minutes. You can leave it running.", + "start.deps_done": "Ready.", + "start.no_proxy": "Connecting directly to your model host: {hosts}", + "start.wechat_installing": "Installing the WeChat plugin…", + "start.wechat_installed": "WeChat plugin installed.", + "start.config_center_starting": "Starting the Control Panel…", + "start.config_center_port": "Control Panel is on port {port}.", + "start.port_in_use": "Port {port} is busy, trying the next one…", + "start.gateway_starting": "Starting U-Claw on port {port}…", + "start.opening_screen": "Opening the start screen…", + "start.opening_config": "Opening the Control Panel…", + "start.running_title": "U-Claw is running", + "start.running_dashboard": "Dashboard: {url}", + "start.running_config": "Control Panel: {url}", + "start.running_hint": "Keep this window open while you use U-Claw. Press Ctrl+C to stop.", + "start.first_run_wait": "First run from a USB drive takes 30–90 seconds while components unpack. The Control Panel is already open so you can pick a model and paste a key.", + "start.stopped": "U-Claw stopped.", + "start.exited_unexpectedly": "U-Claw closed on its own (code {code}).", + "error.node_missing.what": "A file U-Claw needs is missing from the drive.", + "error.node_missing.why": "This usually means the copy onto the USB drive did not finish.", + "error.node_missing.action": "Copy the U-Claw folder onto the drive again, or run setup.sh to rebuild it.", + "error.unsupported_arch.what": "This Mac's processor is not supported ({arch}).", + "error.unsupported_arch.why": "U-Claw ships builds for Apple Silicon and Intel Macs only.", + "error.unsupported_arch.action": "Try U-Claw on a different computer.", + "error.no_port.what": "U-Claw could not find a free port to start on.", + "error.no_port.why": "Ports {from}–{to} are all in use — U-Claw may already be running.", + "error.no_port.action": "Close any window already running U-Claw and start it again.", + "error.deps_failed.what": "U-Claw could not finish getting ready.", + "error.deps_failed.why": "The download did not complete — usually a dropped network connection.", + "error.deps_failed.action": "Check your Wi-Fi and start U-Claw again.", + "error.press_enter": "Press Enter to close this window.", + "loading.title": "Starting U-Claw", + "loading.starting": "Starting U-Claw…", + "loading.first_run": "First run from a USB drive unpacks the bundled components. Give it a moment — you will be told when it is ready.", + "loading.waiting_gateway": "Waiting for U-Claw to come up…", + "loading.ready": "U-Claw is ready", + "loading.choose_next": "Pick what to do next — start chatting, or set up your model and channels first.", + "loading.open_dashboard": "🚀 Start chatting", + "loading.open_settings": "⚙️ Settings", + "loading.settings_hint": "Add or change your API key, and connect chat apps.", + "loading.no_model_hint": "No model set up yet? Open Settings first to add a key.", + "loading.slow_drive_note": "A slow drive usually takes 30–90 seconds. If nothing happens for a long time, open Settings:", + "loading.elapsed": "Waited {seconds}s", + "loading.taking_long": "This is taking longer than usual. You can open Settings while you wait:", + "welcome.title": "U-Claw — Getting Started", + "welcome.subtitle": "Your AI assistant on a USB drive · three steps", + "welcome.quickstart": "Quick start", + "welcome.step1_title": "1. Start U-Claw", + "welcome.step1_desc": "Double-click the file for your computer:", + "welcome.step2_title": "2. Add a key", + "welcome.step2_desc": "Settings opens on its own the first time. You need one API key to get going — Google Gemini is the easiest to obtain: sign in with a Google account, no card required.", + "welcome.step2_link": "Get a free Gemini key →", + "welcome.step3_title": "3. Start talking", + "welcome.step3_desc": "Once the key is saved, the chat window opens by itself. That is it.", + "welcome.portable_note": "✅ Your settings and history stay in the data/ folder on the drive, so they travel with you between Mac and Windows.", + "welcome.models_title": "Which model?", + "welcome.model_claude": "Best all-rounder", + "welcome.model_gpt": "Most widely used", + "welcome.model_gemini": "Free tier, easiest signup", + "welcome.model_local": "Offline · nothing leaves this machine", + "welcome.models_more": "More options, including SEA-LION for Malay, Tamil and Singlish, are in Settings.", + "welcome.trouble_title": "Something not working?", + "welcome.trouble_lead": "💡 Run the check-up tool", + "welcome.trouble_desc": "If U-Claw will not start, double-click:", + "welcome.open_settings": "Open Settings", + "welcome.open_docs": "Documentation", + "nav.title": "U-Claw — Start here", + "nav.tagline": "Portable AI agent — plug in and go", + "nav.status_off": "U-Claw is not running", + "nav.open_console": "Open it →", + "nav.quickstart": "Quick start", + "nav.doubleclick": "Double-click", + "nav.step2": "Settings opens by itself the first time — pick a model and paste your key.", + "nav.mac_gatekeeper": "⚠️ If macOS says the developer cannot be verified: right-click the file, then choose Open.", + "nav.config_shortcut": "📝 You can also double-click Config.html — it takes you to the settings page.", + "nav.win_smartscreen": "⚠️ If Windows shows a security warning: click More info, then Run anyway.", + "nav.everything": "Everything else", + "nav.menu_opens": "for the full menu:", + "nav.g_settings": "Settings", + "nav.g_settings_d": "Model, key and chat apps", + "nav.g_checkup": "Check-up", + "nav.g_checkup_d": "Finds and fixes common problems", + "nav.g_backup": "Backup", + "nav.g_backup_d": "Save settings and memory in one click", + "nav.g_skills": "Skills", + "nav.g_skills_d": "Browse what U-Claw can do", + "nav.g_system": "System info", + "nav.g_system_d": "Version, port, running state", + "nav.g_cli": "Command line", + "nav.g_cli_d": "For advanced use", + "nav.models_title": "Models you can use", + "nav.model_sealion": "Malay, Tamil and Singlish", + "nav.model_local": "Local model", + "nav.model_more": "More", + "nav.model_more_d": "Others are listed in Settings", + "nav.more_title": "More", + "nav.link_guide": "Getting started", + "nav.link_guide_d": "The three-step walkthrough", + "nav.link_skills": "Skills", + "nav.link_skills_d": "Browse what U-Claw can do", + "nav.link_contact": "Contact", + "nav.link_site": "Website", + "nav.status_on": "U-Claw is running on port {port}", + "nav.status_off_hint": "U-Claw is not running — double-click the start file first", + "key.page_title": "U-Claw Settings", + "key.page_subtitle": "Paste an API key and you are done.", + "key.checking": "Checking…", + "key.step_key": "Your key", + "key.step_done": "Done", + "key.heading": "Paste your API key", + "key.desc": "U-Claw works out the rest by itself. Your key is saved on this drive only — it is never uploaded anywhere.", + "key.placeholder": "sk-…", + "key.show": "Show", + "key.hide": "Hide", + "key.continue": "Continue →", + "key.checking_key": "Checking this key…", + "key.ok": "✓ {provider} · connected in {ms}ms", + "key.custom_provider": "Your endpoint", + "key.no_key_title": "Do not have a key yet?", + "key.no_key_desc": "Google Gemini is the quickest to get: sign in with a Google account, no card needed, and there is a free tier.", + "key.get_gemini": "🔑 Get a free Gemini key", + "key.get_openrouter": "🔑 OpenRouter — one key for many models", + "key.advanced": "Advanced — set the endpoint manually", + "key.base_url": "API endpoint", + "key.model_name": "Model name", + "key.advanced_hint": "Only needed for a self-hosted or unlisted provider. Leave blank to let U-Claw decide.", + "key.saved": "Saved.", + "key.err_empty": "Paste a key to continue.", + "key.err_not_checked": "Hold on — still checking that key.", + "key.err_rejected": "That key was not accepted. Check you copied all of it — keys are long and easy to cut short.", + "key.err_quota": "This key has run out of credit. Top it up with your provider, or paste a different key.", + "key.err_offline": "Cannot reach the internet. Check your Wi-Fi and try again.", + "key.err_timeout": "The provider did not answer in time. Try again in a moment.", + "key.err_model": "That key works, but the model it points to was not found. Set the model name under Advanced.", + "key.err_provider_down": "The provider is having trouble right now. Try again shortly.", + "key.err_unrecognised": "This key is not one U-Claw recognises. Fill in the endpoint and model under Advanced.", + "key.err_unknown": "Could not check that key. Try again, or use Advanced to set the endpoint yourself.", + "key.err_save": "Could not save. Make sure the drive is still plugged in, then try again.", + "hub.title": "U-Claw Skills", + "done.title": "You are set up", + "done.subtitle": "Your model and key are saved on this drive.", + "done.open": "🚀 Start chatting", + "done.restart_note": "Chat app settings are saved now and take effect after U-Claw restarts.", + "done.change_key": "Change model or key", + "done.view_config": "View config file", + "ch.title": "📱 Connect a chat app (optional)", + "ch.desc": "Click a card to fill it in, or skip this entirely.", + "ch.whatsapp_d": "Talk to U-Claw from WhatsApp", + "ch.whatsapp_warning": "⚠️ This uses an unofficial protocol. Your WhatsApp account can be banned for it. Do not connect a number you rely on.", + "ch.whatsapp_number": "Phone number", + "ch.telegram_d": "Talk to U-Claw from Telegram", + "ch.telegram_get": "→ Get one from @BotFather", + "ch.slack_d": "Talk to U-Claw from your workspace", + "ch.slack_get": "→ Create an app at api.slack.com", + "ch.discord_d": "Talk to U-Claw from Discord", + "ch.discord_get": "→ Create an app in the Discord developer portal", + "ch.china_group": "Chat apps used mainly in China", + "ch.wechat_d": "Scan a QR code to link a personal WeChat account", + "ch.wechat_start": "Click this card to show the QR code", + "ch.saved": "Chat app settings saved.", + "ch.err_save": "Could not save the chat app settings. Check the drive is still plugged in.", + "info.layout_title": "What is on the drive", + "info.layout_desc": "How the folders are organised", + "info.skills": "Skills", + "info.skills_d": "Drop a SKILL.md in here and it is picked up automatically", + "info.app": "Runtime", + "info.app_d": "Node.js and the OpenClaw core", + "info.data": "Your data", + "info.data_d": "Your key and chat history. Stays on this drive.", + "info.feedback_title": "Found a problem?", + "info.feedback_desc": "U-Claw is open source. Report anything that breaks on GitHub — nothing is collected or uploaded from your machine automatically.", + "info.feedback_link": "→ Open an issue on GitHub", + "wx.getting_qr": "Fetching the QR code…", + "wx.scan": "Scan the code above with WeChat", + "wx.qr_failed": "Could not fetch the QR code", + "wx.connected": "✅ WeChat connected", + "wx.account": "Account", + "wx.restart_needed": "One more thing: restart U-Claw (close it and open it again) before WeChat will work.", + "wx.connected_toast": "WeChat connected. It works after U-Claw restarts.", + "wx.qr_refreshed": "The code refreshed — scan it again", + "wx.confirm_on_phone": "Scanned. Confirm on your phone…", + "wx.qr_expired": "That code expired.", + "wx.qr_retry": "Get a new one", + "wx.failed": "Could not connect", + "info.read_config_failed": "Could not read the config file:", + "status.running": "U-Claw is running on port {port}", + "status.open_dashboard": "Open it →", + "status.not_running": "U-Claw is not running — start it with Windows-Start.bat or Mac-Start.command", + "key.which_model": "Which model?", + "start.opening_language": "Asking which language to use…", + "persona.title": "What will you mostly use this for?", + "persona.subtitle": "This sets up the right tools for you. You can change it later, and picking more than one is fine.", + "persona.continue": "Continue →", + "persona.skip": "Skip this", + "persona.saving": "Setting things up…", + "persona.err_offline": "U-Claw is not running yet. Start it, then open this page again.", + "persona.err_save": "Could not save that. Check the drive is still plugged in, then try again.", + "persona.developer": "Writing code", + "persona.admin": "Documents and email", + "persona.sales": "Talking to customers", + "persona.marketing": "Content and social", + "persona.finance": "Numbers and spreadsheets", + "persona.boss": "Running a business", + "persona.general": "Just having a look", + "start.opening_persona": "Asking what you will use it for…", + "tier.label": "How much do you want to see?", + "tier.simple": "Just the essentials", + "tier.standard": "A bit more control", + "tier.expert": "Everything", + "tier.changed_simple": "Switched to the simple view — advanced options are hidden.", + "tier.changed_standard": "Switched to the standard view — you can now change models and connect more chat apps.", + "tier.changed_expert": "Switched to the full view — everything is visible, including the config file.", + "start.checking": "Something went wrong — checking…", + "start.repaired": "Fixed. Trying again.", + "start.diagnostics_written": "A report of what happened was saved to: {path}", + "start.diagnostics_hint": "API keys have been removed from it. Send it to help@u-claw.org if you want a hand.", + "skill.excel-helper.name": "Spreadsheets", + "skill.excel-helper.desc": "Formulas, pivot tables, charts, cleaning messy data", + "skill.word-writer.name": "Documents", + "skill.word-writer.desc": "Reports, proposals, CVs — drafting and formatting", + "skill.ppt-designer.name": "Slide decks", + "skill.ppt-designer.desc": "Structure, layout and speaker notes", + "skill.pdf-toolkit.name": "PDF tools", + "skill.pdf-toolkit.desc": "Merge, split, extract text — all on this machine", + "skill.image-compress.name": "Images", + "skill.image-compress.desc": "Shrink, resize and convert — nothing is uploaded", + "skill.qrcode-maker.name": "QR codes", + "skill.qrcode-maker.desc": "Links, text and WiFi details, generated offline", + "skill.web-to-markdown.name": "Save a web page", + "skill.web-to-markdown.desc": "Turn any article into clean Markdown", + "skill.linkedin-post.name": "LinkedIn posts", + "skill.linkedin-post.desc": "Hooks and structure, without the LinkedIn voice", + "skill.x-poster.name": "Posts for X", + "skill.x-poster.desc": "Short posts and threads that stand on their own", + "skill.tiktok-script.name": "TikTok scripts", + "skill.tiktok-script.desc": "Hooks that survive the first second", + "skill.youtube-script.name": "YouTube scripts", + "skill.youtube-script.desc": "Titles, the first 30 seconds, and chapters", + "skill.medium-writer.name": "Articles", + "skill.medium-writer.desc": "Long-form structure, and cutting the padding", + "skill.email-campaign.name": "Email campaigns", + "skill.email-campaign.desc": "Subject lines, one clear ask, PDPA-safe", + "skill.web-search.name": "Web search", + "skill.web-search.desc": "Find current information and read the sources", + "skill.sg-weather.name": "Singapore weather", + "skill.sg-weather.desc": "Forecast by area and air quality, from NEA", + "skill.sea-translate.name": "SEA translation", + "skill.sea-translate.desc": "English, Chinese, Malay, Tamil — and register", + "skill.claude-helper.name": "Better answers", + "skill.claude-helper.desc": "How to ask, and when to check the answer", + "skill.sg-transport.name": "Singapore transport", + "skill.sg-transport.desc": "Bus arrivals, MRT alerts, carpark lots", + "skill.meeting-notes.name": "Meeting notes", + "skill.meeting-notes.desc": "Decisions and owners, ready to send", + "cat.office": "Office", + "cat.data": "Data", + "cat.writing": "Writing", + "cat.files": "Files", + "cat.research": "Research", + "cat.social": "Social", + "cat.video": "Video", + "cat.language": "Language", + "cat.local": "Singapore", + "cat.ai": "Using AI", + "hub.lede": "These are on this drive already. Just ask for what you want — you do not have to name the skill.", + "hub.all": "All", + "hub.none": "Nothing in this category.", + "hub.add_note": "Skills live in the skills/ folder on this drive. Dropping a SKILL.md in there adds one." +} diff --git a/portable/lib/messages/zh-CN.json b/portable/lib/messages/zh-CN.json new file mode 100644 index 0000000..1344dfe --- /dev/null +++ b/portable/lib/messages/zh-CN.json @@ -0,0 +1,279 @@ +{ + "start.banner": "U-Claw · 便携 AI 助手", + "start.node_version": "Node.js {version}", + "start.quarantine_removing": "正在解除 macOS 安全限制…", + "start.cache_local": "缓存已放在本机硬盘:{path}", + "start.config_migrating": "正在迁移你原来的设置…", + "start.config_migrated": "设置已迁移。", + "start.config_creating": "第一次使用,正在准备…", + "start.config_created": "准备好了。", + "start.deps_preparing": "正在准备,约 20 秒。", + "start.deps_slow_drive": "这个 U 盘比较慢,可能要几分钟,放着就行。", + "start.deps_done": "准备好了。", + "start.no_proxy": "将直连你的模型地址:{hosts}", + "start.wechat_installing": "正在安装微信插件…", + "start.wechat_installed": "微信插件已安装。", + "start.config_center_starting": "正在启动控制台…", + "start.config_center_port": "控制台端口:{port}", + "start.port_in_use": "端口 {port} 被占用,换下一个…", + "start.gateway_starting": "正在启动 U-Claw,端口 {port}…", + "start.opening_screen": "正在打开启动页…", + "start.opening_config": "正在打开控制台…", + "start.running_title": "U-Claw 已启动", + "start.running_dashboard": "对话界面:{url}", + "start.running_config": "控制台: {url}", + "start.running_hint": "使用期间请不要关闭这个窗口。按 Ctrl+C 停止。", + "start.first_run_wait": "第一次从 U 盘启动需要 30–90 秒解压组件。控制台已经打开,可以先选模型、填密钥。", + "start.stopped": "U-Claw 已停止。", + "start.exited_unexpectedly": "U-Claw 自己退出了(代码 {code})。", + "error.node_missing.what": "U 盘里少了一个 U-Claw 需要的文件。", + "error.node_missing.why": "通常是拷贝到 U 盘时没有复制完整。", + "error.node_missing.action": "把 U-Claw 文件夹重新拷贝一遍,或运行 setup.sh 重建。", + "error.unsupported_arch.what": "这台 Mac 的处理器不受支持({arch})。", + "error.unsupported_arch.why": "U-Claw 只提供 Apple Silicon 和 Intel Mac 的版本。", + "error.unsupported_arch.action": "换一台电脑试试。", + "error.no_port.what": "U-Claw 找不到可用的端口来启动。", + "error.no_port.why": "{from}–{to} 都被占用了 —— 可能已经有一个 U-Claw 在运行。", + "error.no_port.action": "关掉已经在运行的那个窗口,再启动一次。", + "error.deps_failed.what": "U-Claw 没能准备完成。", + "error.deps_failed.why": "下载没有完成,通常是网络中断了。", + "error.deps_failed.action": "检查一下 Wi-Fi,然后重新启动 U-Claw。", + "error.press_enter": "按回车关闭这个窗口。", + "loading.title": "正在启动 U-Claw", + "loading.starting": "U-Claw 正在启动…", + "loading.first_run": "第一次从 U 盘启动需要展开内置组件,稍等片刻,就绪后会提示你下一步。", + "loading.waiting_gateway": "正在等待 U-Claw 启动…", + "loading.ready": "U-Claw 已就绪", + "loading.choose_next": "选择下一步 —— 直接开始聊天,或先去配置模型和渠道。", + "loading.open_dashboard": "🚀 开始聊天", + "loading.open_settings": "⚙️ 设置", + "loading.settings_hint": "填写或更换 API 密钥,连接聊天软件。", + "loading.no_model_hint": "还没配过模型?先打开设置填一个密钥。", + "loading.slow_drive_note": "慢 U 盘首次启动通常 30–90 秒。如果迟迟没反应,可以先打开设置:", + "loading.elapsed": "已等待 {seconds} 秒", + "loading.taking_long": "启动比平时慢,可以先打开设置:", + "welcome.title": "U-Claw 使用指南", + "welcome.subtitle": "装在 U 盘里的 AI 助手 · 三步开始", + "welcome.quickstart": "快速开始", + "welcome.step1_title": "1. 启动 U-Claw", + "welcome.step1_desc": "双击你电脑对应的那个文件:", + "welcome.step2_title": "2. 填一个密钥", + "welcome.step2_desc": "第一次启动会自动打开设置页。你需要一个 API 密钥才能开始 —— Google Gemini 最容易拿到:用 Google 账号登录即可,不用绑卡。", + "welcome.step2_link": "去领取免费的 Gemini 密钥 →", + "welcome.step3_title": "3. 开始对话", + "welcome.step3_desc": "密钥保存后,对话窗口会自己打开。就这样。", + "welcome.portable_note": "✅ 你的设置和聊天记录都存在盘上的 data/ 目录里,跟着盘走,Mac 和 Windows 通用。", + "welcome.models_title": "用哪个模型?", + "welcome.model_claude": "综合最强", + "welcome.model_gpt": "用的人最多", + "welcome.model_gemini": "有免费额度,注册最简单", + "welcome.model_local": "离线 · 数据不出本机", + "welcome.models_more": "更多选择在设置里,包括适合马来语、泰米尔语和 Singlish 的 SEA-LION。", + "welcome.trouble_title": "遇到问题?", + "welcome.trouble_lead": "💡 运行检查工具", + "welcome.trouble_desc": "如果 U-Claw 启动不了,双击:", + "welcome.open_settings": "打开设置", + "welcome.open_docs": "查看文档", + "nav.title": "U-Claw 启动导航", + "nav.tagline": "便携 AI 助手 — 插上就能用", + "nav.status_off": "U-Claw 尚未运行", + "nav.open_console": "打开它 →", + "nav.quickstart": "快速启动", + "nav.doubleclick": "双击", + "nav.step2": "第一次启动会自动打开设置页 —— 选一个模型,把密钥粘进去。", + "nav.mac_gatekeeper": "⚠️ 如果 macOS 提示「无法验证开发者」:右键点这个文件,选「打开」。", + "nav.config_shortcut": "📝 也可以双击 Config.html,它会带你到设置页。", + "nav.win_smartscreen": "⚠️ 如果 Windows 弹安全警告:点「更多信息」,再点「仍要运行」。", + "nav.everything": "其他功能", + "nav.menu_opens": "打开完整菜单:", + "nav.g_settings": "设置", + "nav.g_settings_d": "模型、密钥和聊天软件", + "nav.g_checkup": "检查修复", + "nav.g_checkup_d": "找出并修复常见问题", + "nav.g_backup": "备份", + "nav.g_backup_d": "一键保存设置和记忆", + "nav.g_skills": "技能", + "nav.g_skills_d": "看看 U-Claw 能做什么", + "nav.g_system": "系统信息", + "nav.g_system_d": "版本、端口、运行状态", + "nav.g_cli": "命令行", + "nav.g_cli_d": "给进阶用户", + "nav.models_title": "可以用的模型", + "nav.model_sealion": "马来语、泰米尔语和 Singlish", + "nav.model_local": "本地模型", + "nav.model_more": "更多", + "nav.model_more_d": "其他模型在设置里", + "nav.more_title": "更多", + "nav.link_guide": "使用指南", + "nav.link_guide_d": "三步上手", + "nav.link_skills": "技能", + "nav.link_skills_d": "看看 U-Claw 能做什么", + "nav.link_contact": "联系我们", + "nav.link_site": "官网", + "nav.status_on": "U-Claw 正在运行(端口 {port})", + "nav.status_off_hint": "U-Claw 尚未运行 —— 请先双击启动文件", + "key.page_title": "U-Claw 设置", + "key.page_subtitle": "粘贴一个 API 密钥就可以了。", + "key.checking": "检测中…", + "key.step_key": "填密钥", + "key.step_done": "完成", + "key.heading": "粘贴你的 API 密钥", + "key.desc": "剩下的 U-Claw 自己搞定。密钥只保存在这个 U 盘上,不会上传到任何地方。", + "key.placeholder": "sk-…", + "key.show": "显示", + "key.hide": "隐藏", + "key.continue": "继续 →", + "key.checking_key": "正在检查这个密钥…", + "key.ok": "✓ {provider} · 连接成功,用时 {ms} 毫秒", + "key.custom_provider": "你的地址", + "key.no_key_title": "还没有密钥?", + "key.no_key_desc": "Google Gemini 最容易拿到:用 Google 账号登录即可,不用绑卡,还有免费额度。", + "key.get_gemini": "🔑 领取免费的 Gemini 密钥", + "key.get_openrouter": "🔑 OpenRouter —— 一个密钥用多种模型", + "key.advanced": "高级 —— 手动填写接口地址", + "key.base_url": "接口地址", + "key.model_name": "模型名称", + "key.advanced_hint": "只有自建或未收录的服务才需要填。留空则由 U-Claw 自动判断。", + "key.saved": "已保存。", + "key.err_empty": "先粘贴一个密钥。", + "key.err_not_checked": "稍等,密钥还在检查中。", + "key.err_rejected": "这个密钥没被接受。检查一下是不是没复制全 —— 密钥很长,容易少一截。", + "key.err_quota": "这个密钥的额度用完了。去服务商那边充值,或者换一个密钥。", + "key.err_offline": "连不上网络。检查一下 Wi-Fi 再试。", + "key.err_timeout": "服务商没有及时响应。过一会儿再试。", + "key.err_model": "密钥是好的,但它指向的模型没找到。在「高级」里填写模型名称。", + "key.err_provider_down": "服务商那边现在有问题。稍后再试。", + "key.err_unrecognised": "U-Claw 认不出这个密钥。请在「高级」里填写接口地址和模型名称。", + "key.err_unknown": "没能检查这个密钥。再试一次,或者在「高级」里自己填接口地址。", + "key.err_save": "保存失败。确认 U 盘还插着,然后再试一次。", + "hub.title": "U-Claw 技能", + "done.title": "配置完成", + "done.subtitle": "模型和密钥已保存在这个 U 盘上。", + "done.open": "🚀 开始聊天", + "done.restart_note": "聊天软件的设置已保存,重启 U-Claw 后生效。", + "done.change_key": "换模型或密钥", + "done.view_config": "查看配置文件", + "ch.title": "📱 连接聊天软件(可选)", + "ch.desc": "点卡片展开填写,也可以直接跳过。", + "ch.whatsapp_d": "用 WhatsApp 和 U-Claw 对话", + "ch.whatsapp_warning": "⚠️ 这里用的是非官方协议,你的 WhatsApp 账号可能因此被封。不要接入你离不开的号码。", + "ch.whatsapp_number": "手机号", + "ch.telegram_d": "用 Telegram 和 U-Claw 对话", + "ch.telegram_get": "→ 从 @BotFather 获取", + "ch.slack_d": "在工作区里和 U-Claw 对话", + "ch.slack_get": "→ 在 api.slack.com 创建应用", + "ch.discord_d": "用 Discord 和 U-Claw 对话", + "ch.discord_get": "→ 在 Discord 开发者后台创建应用", + "ch.china_group": "主要在中国使用的聊天软件", + "ch.wechat_d": "扫码接入个人微信", + "ch.wechat_start": "点这张卡片开始扫码", + "ch.saved": "聊天软件设置已保存。", + "ch.err_save": "聊天软件设置没能保存。确认 U 盘还插着。", + "info.layout_title": "U 盘里有什么", + "info.layout_desc": "文件夹是怎么组织的", + "info.skills": "技能", + "info.skills_d": "把 SKILL.md 放进来就会自动加载", + "info.app": "运行时", + "info.app_d": "Node.js 和 OpenClaw 核心", + "info.data": "你的数据", + "info.data_d": "密钥和聊天记录,只留在这个盘上。", + "info.feedback_title": "遇到问题?", + "info.feedback_desc": "U-Claw 是开源项目。出问题欢迎去 GitHub 提 Issue —— 我们不会自动收集或上传你机器上的任何东西。", + "info.feedback_link": "→ 去 GitHub 提 Issue", + "wx.getting_qr": "正在获取二维码…", + "wx.scan": "请用微信扫描上方二维码", + "wx.qr_failed": "获取二维码失败", + "wx.connected": "✅ 微信已连接", + "wx.account": "账号", + "wx.restart_needed": "还差一步:重启 U-Claw(关掉再打开),微信才能用。", + "wx.connected_toast": "微信已连接,重启 U-Claw 后生效。", + "wx.qr_refreshed": "二维码已刷新,请重新扫码", + "wx.confirm_on_phone": "已扫码,请在手机上确认…", + "wx.qr_expired": "二维码已过期。", + "wx.qr_retry": "重新获取", + "wx.failed": "连接失败", + "info.read_config_failed": "读取配置文件失败:", + "status.running": "U-Claw 正在运行,端口 {port}", + "status.open_dashboard": "打开它 →", + "status.not_running": "U-Claw 尚未运行 —— 请先运行 Windows-Start.bat 或 Mac-Start.command", + "key.which_model": "用哪个模型?", + "start.opening_language": "正在询问使用哪种语言…", + "persona.title": "你主要用它做什么?", + "persona.subtitle": "这会帮你把合适的工具装好。以后可以改,也可以多选。", + "persona.continue": "继续 →", + "persona.skip": "跳过", + "persona.saving": "正在准备…", + "persona.err_offline": "U-Claw 还没启动。先启动它,再打开这个页面。", + "persona.err_save": "没能保存。确认 U 盘还插着,然后再试一次。", + "persona.developer": "写代码", + "persona.admin": "写文档、发邮件", + "persona.sales": "跟客户打交道", + "persona.marketing": "做内容、发社交媒体", + "persona.finance": "算数、做表格", + "persona.boss": "管公司", + "persona.general": "先随便看看", + "start.opening_persona": "正在询问你主要用它做什么…", + "tier.label": "想看到多少?", + "tier.simple": "只要最基本的", + "tier.standard": "多一点控制", + "tier.expert": "全部", + "tier.changed_simple": "已切换到简洁模式 —— 高级选项已隐藏。", + "tier.changed_standard": "已切换到标准模式 —— 现在可以换模型、接更多聊天软件了。", + "tier.changed_expert": "已切换到完整模式 —— 所有东西都可见,包括配置文件。", + "start.checking": "出了点问题,正在检查…", + "start.repaired": "已修复,重试一次。", + "start.diagnostics_written": "已把情况记录到:{path}", + "start.diagnostics_hint": "里面的密钥已被去掉。需要帮忙的话,把它发到 help@u-claw.org。", + "skill.excel-helper.name": "表格", + "skill.excel-helper.desc": "公式、透视表、图表、清洗乱数据", + "skill.word-writer.name": "文档", + "skill.word-writer.desc": "报告、方案、简历 —— 起草和排版", + "skill.ppt-designer.name": "幻灯片", + "skill.ppt-designer.desc": "结构、版式和演讲要点", + "skill.pdf-toolkit.name": "PDF 工具", + "skill.pdf-toolkit.desc": "合并、拆分、提取文字 —— 全在本机", + "skill.image-compress.name": "图片", + "skill.image-compress.desc": "压缩、改尺寸、转格式 —— 不上传", + "skill.qrcode-maker.name": "二维码", + "skill.qrcode-maker.desc": "网址、文本、WiFi,离线生成", + "skill.web-to-markdown.name": "保存网页", + "skill.web-to-markdown.desc": "把文章转成干净的 Markdown", + "skill.linkedin-post.name": "LinkedIn 帖子", + "skill.linkedin-post.desc": "钩子和结构,不要那股 LinkedIn 腔", + "skill.x-poster.name": "X 帖子", + "skill.x-poster.desc": "能独立成立的短帖和 thread", + "skill.tiktok-script.name": "TikTok 脚本", + "skill.tiktok-script.desc": "扛得住第一秒的钩子", + "skill.youtube-script.name": "YouTube 脚本", + "skill.youtube-script.desc": "标题、前 30 秒、章节", + "skill.medium-writer.name": "长文", + "skill.medium-writer.desc": "长文结构,以及怎么删水分", + "skill.email-campaign.name": "邮件营销", + "skill.email-campaign.desc": "标题、一个明确的 ask、符合 PDPA", + "skill.web-search.name": "网页搜索", + "skill.web-search.desc": "找当前信息并真的读来源", + "skill.sg-weather.name": "新加坡天气", + "skill.sg-weather.desc": "按区预报和空气质量,来自 NEA", + "skill.sea-translate.name": "东南亚翻译", + "skill.sea-translate.desc": "英 / 中 / 马来 / 泰米尔 —— 以及语域", + "skill.claude-helper.name": "问得更好", + "skill.claude-helper.desc": "怎么问,以及什么时候该核对答案", + "skill.sg-transport.name": "新加坡交通", + "skill.sg-transport.desc": "巴士到站、地铁故障、停车位", + "skill.meeting-notes.name": "会议纪要", + "skill.meeting-notes.desc": "决定和负责人,写完就能发", + "cat.office": "办公", + "cat.data": "数据", + "cat.writing": "写作", + "cat.files": "文件", + "cat.research": "资料", + "cat.social": "社交媒体", + "cat.video": "视频", + "cat.language": "语言", + "cat.local": "新加坡", + "cat.ai": "用好 AI", + "hub.lede": "这些已经在盘上了。直接说你想做什么就行,不用记技能名。", + "hub.all": "全部", + "hub.none": "这个分类下暂时没有。", + "hub.add_note": "技能放在盘上的 skills/ 目录里。丢一个 SKILL.md 进去就多一个。" +} diff --git a/portable/lib/persona.html b/portable/lib/persona.html new file mode 100644 index 0000000..14be555 --- /dev/null +++ b/portable/lib/persona.html @@ -0,0 +1,153 @@ + + + + + +U-Claw + + + + + + + +

What will you mostly use this for?

+

This sets up the right tools for you. You can change it later, and picking more than one is fine.

+ +
+ +
+ + +
+

+ + + + diff --git a/portable/lib/provider-detect.mjs b/portable/lib/provider-detect.mjs new file mode 100644 index 0000000..de656e6 --- /dev/null +++ b/portable/lib/provider-detect.mjs @@ -0,0 +1,87 @@ +// Works out which provider an API key belongs to, so users never have to know +// what a Base URL is. +// +// The old flow asked for three things — Base URL, model name and key — on the +// first screen a non-technical user ever saw. Every key in practice announces +// its own provider through its prefix, so ask for the key and derive the rest. + +// Order matters: the longest, most specific prefixes are checked first, because +// several providers issue keys that also start with "sk-". +const PROVIDERS = [ + { + id: 'anthropic', + label: 'Anthropic Claude', + prefixes: ['sk-ant-'], + baseUrl: 'https://api.anthropic.com/v1', + model: 'claude-sonnet-4-20250514', + models: ['claude-sonnet-4-20250514', 'claude-opus-4-20250514', 'claude-haiku-4-5-20251001'], + }, + { + id: 'openrouter', + label: 'OpenRouter', + prefixes: ['sk-or-v1-', 'sk-or-'], + baseUrl: 'https://openrouter.ai/api/v1', + model: 'anthropic/claude-sonnet-4', + models: ['anthropic/claude-sonnet-4', 'openai/gpt-4o', 'google/gemini-2.5-flash'], + }, + { + id: 'google', + label: 'Google Gemini', + prefixes: ['AIza'], + baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai', + model: 'gemini-2.5-flash', + models: ['gemini-2.5-flash', 'gemini-2.5-pro'], + }, + { + id: 'groq', + label: 'Groq', + prefixes: ['gsk_'], + baseUrl: 'https://api.groq.com/openai/v1', + model: 'llama-3.3-70b-versatile', + models: ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant'], + }, + { + id: 'sealion', + label: 'SEA-LION', + prefixes: ['sk-sealion-'], + baseUrl: 'https://api.sea-lion.ai/v1', + model: 'aisingapore/Qwen-SEA-LION-v4.5-27B-IT', + models: ['aisingapore/Qwen-SEA-LION-v4.5-27B-IT', 'aisingapore/Llama-SEA-LION-v3.5-70B-R'], + }, + { + id: 'openai', + label: 'OpenAI', + prefixes: ['sk-proj-', 'sk-svcacct-', 'sk-'], + baseUrl: 'https://api.openai.com/v1', + model: 'gpt-4o', + models: ['gpt-4o', 'gpt-4o-mini', 'o3-mini'], + }, +]; + +export function detectProvider(rawKey) { + const key = String(rawKey ?? '').trim(); + if (!key) return null; + for (const provider of PROVIDERS) { + if (provider.prefixes.some((prefix) => key.startsWith(prefix))) { + return { id: provider.id, label: provider.label, baseUrl: provider.baseUrl, model: provider.model, models: provider.models }; + } + } + return null; +} + +// Maps a failed request to a message key the UI can translate. Every branch has +// to name something the user can actually do next — "401 Unauthorized" on its +// own tells a non-technical user nothing. +export function classifyFailure({ status, code } = {}) { + if (code === 'ENOTFOUND' || code === 'EAI_AGAIN' || code === 'ECONNREFUSED') return 'key.err_offline'; + if (code === 'ETIMEDOUT' || code === 'UND_ERR_CONNECT_TIMEOUT' || code === 'ABORT_ERR') return 'key.err_timeout'; + if (status === 401 || status === 403) return 'key.err_rejected'; + if (status === 429) return 'key.err_quota'; + if (status === 404) return 'key.err_model'; + if (typeof status === 'number' && status >= 500) return 'key.err_provider_down'; + return 'key.err_unknown'; +} + +export function listProviders() { + return PROVIDERS.map(({ id, label, baseUrl, model, models }) => ({ id, label, baseUrl, model, models })); +} diff --git a/portable/lib/publish-latest.mjs b/portable/lib/publish-latest.mjs index 0fc6c34..47d7a5b 100644 --- a/portable/lib/publish-latest.mjs +++ b/portable/lib/publish-latest.mjs @@ -21,7 +21,7 @@ const REPO_ROOT = resolve(__dirname, '../..'); // 默认 OSS 路径前缀(你可以改成自己的 bucket / domain) const DEFAULT_OSS_BASE = 'https://u-claw-oss.56chat.cn/u-claw-open'; -const GH_RELEASES_BASE = 'https://github.com/dongsheng123132/u-claw/releases'; +const GH_RELEASES_BASE = 'https://gitea.fanghe.it.com/zhenghy/u-claw/releases'; function parseArgs(argv) { const args = { notes: '', ossBase: DEFAULT_OSS_BASE }; diff --git a/portable/lib/self-heal.mjs b/portable/lib/self-heal.mjs new file mode 100644 index 0000000..ae9fe0c --- /dev/null +++ b/portable/lib/self-heal.mjs @@ -0,0 +1,203 @@ +// Checks and repairs that run when startup fails, before bothering the user. +// +// Diagnose used to be a tool people had to know existed: when startup broke, you +// were expected to work out that Windows-Diagnose.bat was the answer. Anyone who +// did not know that had already given up. These checks now run by themselves, +// and the user sees "checking…" rather than a stack trace. +// +// Two rules for anything added here: +// 1. A repair must be safe to run when nothing is wrong. Startup can fail for +// reasons none of these explain, and every check will run anyway. +// 2. Nothing here may destroy user data. Files that look wrong get moved +// aside with a timestamp, never deleted. + +import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, rmSync, readdirSync, statSync, copyFileSync } from 'node:fs'; +import { createServer } from 'node:net'; +import { join, dirname } from 'node:path'; + +function portBusy(port) { + return new Promise((done) => { + const probe = createServer(); + probe.once('error', () => done(true)); + probe.once('listening', () => probe.close(() => done(false))); + probe.listen(port, '127.0.0.1'); + }); +} + +// Moving aside beats deleting: if the diagnosis was wrong, the user still has +// their file. The stamp comes from the caller so this stays deterministic. +function setAside(path, stamp) { + const target = `${path}.broken-${stamp}`; + try { renameSync(path, target); return target; } catch { return null; } +} + +export function buildChecks({ paths, defaultConfigPath, portRange, stamp }) { + return [ + { + id: 'data-dirs', + repair() { + const wanted = [paths.state, join(paths.data, 'memory'), join(paths.data, 'backups'), join(paths.data, 'logs')]; + const missing = wanted.filter((dir) => !existsSync(dir)); + if (missing.length === 0) return null; + missing.forEach((dir) => mkdirSync(dir, { recursive: true })); + return `created ${missing.length} missing folder(s)`; + }, + }, + { + id: 'config-readable', + repair() { + if (!existsSync(paths.config)) return null; + try { + JSON.parse(readFileSync(paths.config, 'utf8')); + return null; + } catch { + // A half-written openclaw.json stops the gateway dead, and the message + // it produces means nothing to a non-technical user. + const moved = setAside(paths.config, stamp); + if (defaultConfigPath && existsSync(defaultConfigPath)) copyFileSync(defaultConfigPath, paths.config); + else writeFileSync(paths.config, `${JSON.stringify({ gateway: { mode: 'local', auth: { token: 'uclaw' } } }, null, 2)}\n`, 'utf8'); + return moved ? `settings file was damaged, kept a copy at ${moved}` : 'rebuilt the settings file'; + } + }, + }, + { + id: 'stale-runtime', + async repair() { + if (!existsSync(paths.runtimeJson)) return null; + let port = null; + try { port = JSON.parse(readFileSync(paths.runtimeJson, 'utf8'))?.configServerPort; } catch { /* unreadable */ } + // Left behind by a crash or an unplugged drive; it makes the launcher + // wait on a port nothing is listening on. + if (port && (await portBusy(port))) return null; + try { rmSync(paths.runtimeJson, { force: true }); } catch { return null; } + return 'cleared a leftover port record'; + }, + }, + { + id: 'openclaw-present', + repair() { + const modules = join(paths.core, 'node_modules'); + if (!existsSync(modules)) return null; + // node_modules exists but the entry point does not: a copy onto the + // drive that stopped part-way. Removing it makes startup reinstall. + if (existsSync(join(modules, 'openclaw', 'openclaw.mjs'))) return null; + const moved = setAside(modules, stamp); + return moved ? 'the copy on this drive was incomplete, will fetch it again' : null; + }, + }, + { + id: 'broken-cache-link', + repair() { + const browser = join(paths.state, 'browser'); + if (!existsSync(browser)) return null; + try { + statSync(browser); // follows the link; throws when the target is gone + return null; + } catch { + // portable-cache points this at local disk. Plug the drive into a + // different machine and the link dangles, which breaks the browser. + try { rmSync(browser, { force: true, recursive: true }); } catch { return null; } + return 'cleared a cache link left by another computer'; + } + }, + }, + { + id: 'ports-free', + async repair() { + const busy = []; + for (let port = portRange.from; port <= portRange.to; port++) { + if (await portBusy(port)) busy.push(port); + } + // Not repairable — killing a process we did not start is not ours to do. + // Reported so the message can say "it may already be running". + if (busy.length <= portRange.to - portRange.from) return null; + return null; + }, + report: async () => { + const busy = []; + for (let port = portRange.from; port <= portRange.to; port++) { + if (await portBusy(port)) busy.push(port); + } + return busy.length ? `ports in use: ${busy.join(', ')}` : 'all ports free'; + }, + }, + ]; +} + +export async function runRepairs(checks) { + const applied = []; + for (const check of checks) { + try { + const result = await check.repair(); + if (result) applied.push({ id: check.id, result }); + } catch (error) { + // A failing check must never be the reason startup stops. + applied.push({ id: check.id, result: `check failed: ${error.message}` }); + } + } + return applied; +} + +// Written when the repairs did not help. Everything a support conversation would +// ask for, with the secrets taken out — the user should be able to read the file +// themselves before deciding to send it. +export async function writeDiagnostics({ paths, checks, applied, versions, stamp, extra = {} }) { + const redact = (value) => (typeof value === 'string' && value.length > 8 ? `${value.slice(0, 6)}…redacted` : '***'); + + let config = 'not readable'; + try { + const parsed = JSON.parse(readFileSync(paths.config, 'utf8')); + const walk = (node) => { + if (!node || typeof node !== 'object') return node; + if (Array.isArray(node)) return node.map(walk); + return Object.fromEntries(Object.entries(node).map(([key, value]) => + /key|token|secret|password/i.test(key) ? [key, redact(value)] : [key, walk(value)])); + }; + config = JSON.stringify(walk(parsed), null, 2); + } catch (error) { + config = `not readable: ${error.message}`; + } + + const listing = (dir) => { + try { return readdirSync(dir).sort().join(', ') || '(empty)'; } catch { return '(missing)'; } + }; + + const reports = []; + for (const check of checks) { + if (typeof check.report !== 'function') continue; + try { reports.push(`${check.id}: ${await check.report()}`); } catch { /* skip */ } + } + + const lines = [ + 'U-Claw diagnostics', + `Written: ${stamp}`, + '', + 'API keys and tokens have been replaced with "redacted" — you can read this', + 'file before you send it anywhere.', + '', + '## System', + `platform: ${process.platform} ${process.arch}`, + `node: ${process.version}`, + ...Object.entries(versions).map(([key, value]) => `${key}: ${value ?? 'unknown'}`), + ...Object.entries(extra).map(([key, value]) => `${key}: ${value}`), + '', + '## Repairs attempted', + applied.length ? applied.map((a) => `- ${a.id}: ${a.result}`).join('\n') : '- none needed', + '', + '## Checks', + reports.length ? reports.map((r) => `- ${r}`).join('\n') : '- none', + '', + '## Folders', + `drive root: ${listing(dirname(paths.data))}`, + `data/.openclaw: ${listing(paths.state)}`, + `app/core/node_modules: ${listing(join(paths.core, 'node_modules'))}`, + '', + '## Settings (redacted)', + config, + '', + ]; + + const target = join(paths.state, 'diagnostics.txt'); + writeFileSync(target, lines.join('\n'), 'utf8'); + return target; +} diff --git a/portable/lib/setup-local-model.mjs b/portable/lib/setup-local-model.mjs index 59658dd..ce35abf 100644 --- a/portable/lib/setup-local-model.mjs +++ b/portable/lib/setup-local-model.mjs @@ -1,14 +1,21 @@ -// setup-local-model.mjs — 内网/本地模型一键配置(不碰 Control UI) +// setup-local-model.mjs — set up a local or self-hosted model from the command line. // -// 给"内网/离线"场景:用纯命令行问几个问题,直接写好 openclaw.json, -// 再当场实测能不能连上、能不能回话。全程不依赖会挂的 dashboard 网页。 -// 支持两类本地/内网模型: -// 1) Ollama(本机,http://127.0.0.1:11434) -// 2) newapi / 任意 OpenAI 兼容中转(内网 IP + token) +// For offline and corporate-network situations: ask a few questions, write +// openclaw.json directly, then actually test that the model answers. Deliberately +// does not depend on the dashboard, which is the thing that tends to be broken +// when someone reaches for this tool. // -// 写入只 merge 模型相关字段,保留 gateway 等原有配置;写前自动备份。 +// Two kinds of endpoint: +// 1) Ollama on this machine (http://127.0.0.1:11434) +// 2) Any OpenAI-compatible endpoint — a company server, a relay (URL + token) // -// 用法:node setup-local-model.mjs +// Only the model-related fields are merged in; gateway and other settings are +// left alone, and the previous file is backed up first. +// +// Usage: node setup-local-model.mjs +// +// Input: a real terminal gets interactive readline; piped input (tests, scripts) +// is read once and dequeued line by line. import { readFileSync, writeFileSync, existsSync, copyFileSync, mkdirSync } from 'node:fs'; import { dirname } from 'node:path'; @@ -17,7 +24,6 @@ import { stdin as input, stdout as output } from 'node:process'; import http from 'node:http'; import https from 'node:https'; -// 输入抽象:真控制台(TTY)走交互式 readline;被管道喂入(测试/脚本)则一次读完按行出队。 function makePrompter() { if (input.isTTY) { const rl = createInterface({ input, output }); @@ -69,7 +75,7 @@ async function chatTest(baseUrl, apiKey, modelId) { const res = await requestText(url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}) }, - body: JSON.stringify({ model: modelId, messages: [{ role: 'user', content: '请回复四个字:连接成功' }], max_tokens: 64, stream: false }), + body: JSON.stringify({ model: modelId, messages: [{ role: 'user', content: 'Reply with exactly: connection ok' }], max_tokens: 64, stream: false }), timeoutMs: CHAT_TIMEOUT_MS, }); const ms = Date.now() - started; @@ -111,10 +117,10 @@ function requestText(rawUrl, { method = 'GET', headers = {}, body, timeoutMs }) async function main() { const configPath = process.argv[2] || process.env.OPENCLAW_CONFIG_PATH; - if (!configPath) { line('用法: node setup-local-model.mjs '); process.exitCode = 2; return; } + if (!configPath) { line('Usage: node setup-local-model.mjs '); process.exitCode = 2; return; } line('========================================'); - line(' U-Claw 内网/本地模型 一键配置'); + line(' U-Claw — set up a local or self-hosted model'); line('========================================'); line(''); @@ -122,32 +128,32 @@ async function main() { const ask = rl.ask; try { - line('选择模型类型:'); - line(' 1) Ollama(本机部署,http://127.0.0.1:11434)'); - line(' 2) newapi / 其它 OpenAI 兼容中转(内网 IP + token)'); - const kind = await ask('输入 1 或 2', '1'); + line('Which kind of model?'); + line(' 1) Ollama running on this machine (http://127.0.0.1:11434)'); + line(' 2) A self-hosted or company endpoint (any OpenAI-compatible URL + token)'); + const kind = await ask('Enter 1 or 2', '1'); let providerKey, baseUrl, apiKey, modelId; if (kind === '2') { providerKey = 'newapi'; line(''); - line('提示:baseUrl 通常形如 http://192.168.1.50:3000/v1(注意大多要带 /v1)'); - baseUrl = await ask('newapi 地址 baseUrl', 'http://192.168.1.50:3000/v1'); + line('The endpoint usually looks like http://192.168.1.50:3000/v1 — most need the /v1 on the end.'); + baseUrl = await ask('Endpoint URL', 'http://192.168.1.50:3000/v1'); apiKey = await ask('token / API Key', ''); - modelId = await ask('模型 ID(管理员给的,如 deepseek-v3)', ''); + modelId = await ask('Model ID — your admin will have given you this, e.g. deepseek-v3', ''); } else { providerKey = 'ollama'; line(''); - baseUrl = await ask('Ollama 地址(一般本机默认即可)', 'http://127.0.0.1:11434/v1'); - // Ollama 的 OpenAI 兼容端点在 /v1;自动补上 + baseUrl = await ask('Ollama URL — the default is right unless you changed it', 'http://127.0.0.1:11434/v1'); + // Ollama's OpenAI-compatible endpoint lives at /v1; add it if missing if (!/\/v1\/?$/.test(baseUrl)) baseUrl = baseUrl.replace(/\/+$/, '') + '/v1'; - apiKey = 'ollama'; // 本地占位 key,任意值即可 - modelId = await ask('模型名(先用 ollama list 查,如 qwen2.5 / llama3.1)', 'qwen2.5'); + apiKey = 'ollama'; // Ollama ignores auth; any placeholder works + modelId = await ask('Model name — run `ollama list` to see yours, e.g. qwen2.5', 'qwen2.5'); } - if (!baseUrl || !modelId) { line(''); line('地址或模型 ID 为空,已取消。'); process.exitCode = 2; return; } + if (!baseUrl || !modelId) { line(''); line('No endpoint or model ID given — nothing was changed.'); process.exitCode = 2; return; } - // 读取并合并现有配置(保留 gateway 等),写前备份 + // Merge into the existing config so gateway and other settings survive; back up first let config = {}; if (existsSync(configPath)) { try { config = JSON.parse(readFileSync(configPath, 'utf8')); } @@ -174,39 +180,39 @@ async function main() { writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8'); line(''); - line(`✓ 已写入配置:${configPath}`); + line(`✓ Saved to ${configPath}`); line(` provider=${providerKey} baseUrl=${baseUrl} model=${modelId}`); - if (existsSync(configPath + '.bak')) line(` (原配置已备份为 openclaw.json.bak)`); + if (existsSync(configPath + '.bak')) line(' Your previous settings were kept as openclaw.json.bak'); line(''); - // 当场实测 - line('正在实测:发一条对话给模型...'); + // Prove it actually works rather than just claiming it was saved + line('Testing it — sending one message to the model…'); const r = await chatTest(baseUrl, apiKey, modelId); line(''); if (r.ok) { - line(`✓✓ 跑通了!模型回复 (${r.ms}ms):${r.reply.slice(0, 120) || '(空回复但请求成功)'}`); + line(`✓ It works. The model replied in ${r.ms}ms: ${r.reply.slice(0, 120) || '(empty reply, but the request succeeded)'}`); line(''); - line('配置完成。现在双击 Windows-Start.bat 即可正常使用(对话可走 CLI 或 Dashboard)。'); + line('You are set. Start U-Claw normally and it will use this model.'); } else if (r.status) { - line(`✗ 服务端 HTTP ${r.status} (${r.ms}ms):${r.body}`); + line(`✗ The server answered with HTTP ${r.status} in ${r.ms}ms: ${r.body}`); line(''); - if (r.status === 401 || r.status === 403) line('→ 网络通,但 token / key 不对(Ollama 可忽略鉴权,newapi 请核对 token)。'); - else if (r.status === 404) line('→ 网络通,但路径或模型 ID 不对(检查 baseUrl 是否要带 /v1、模型名是否正确)。'); - else line('→ 网络通,服务端报错,把上面内容发管理员。'); + if (r.status === 401 || r.status === 403) line(' The network is fine but the token was rejected. Ollama ignores auth entirely; for a company endpoint, check the token with whoever issued it.'); + else if (r.status === 404) line(' The network is fine but the path or model ID is wrong. Check whether the endpoint needs /v1 on the end, and that the model name matches exactly.'); + else line(' The network is fine; the server itself errored. Send the text above to whoever runs it.'); } else { const host = (() => { try { return new URL(withScheme(baseUrl)).hostname; } catch { return baseUrl; } })(); - line(`✗ 连不上:${r.error} (${r.ms}ms)`); + line(`✗ Could not reach it: ${r.error} (${r.ms}ms)`); line(''); if (providerKey === 'ollama') { - line('→ 本机 Ollama 没连上,多半是 Ollama 没启动或模型没拉。请在本机执行:'); - line(' ollama serve (启动服务,若已是后台服务可跳过)'); - line(` ollama pull ${modelId} (把模型拉到本地,离线需提前准备好)`); - line(' 然后重新运行本工具。'); + line(' Ollama is not answering. It is usually not running, or the model was never pulled. On this machine, run:'); + line(' ollama serve starts it, skip if it already runs in the background'); + line(` ollama pull ${modelId} downloads the model — do this while you still have internet`); + line(' Then run this tool again.'); } else { - line('→ 是地址错 / 内网不通 / 防火墙 / 模型服务没起。'); - line(' 在这台机器上自测:'); + line(' Either the address is wrong, the network cannot reach it, a firewall is blocking it, or the service is down.'); + line(' Test it from this machine with:'); line(` ping ${host}`); - line(' 让机房管理员确认 IP、端口、防火墙放行。'); + line(' If that also fails, ask whoever runs the server to confirm the address, port and firewall rules.'); } } } finally { diff --git a/portable/lib/start.mjs b/portable/lib/start.mjs new file mode 100644 index 0000000..a13b426 --- /dev/null +++ b/portable/lib/start.mjs @@ -0,0 +1,553 @@ +#!/usr/bin/env node +// U-Claw portable launcher. +// +// Everything the old START HERE - Windows.bat and START HERE - Mac.command did lives here, so +// the two platforms cannot drift apart again and so every user-facing string can +// be translated. The launchers are now thin shells that locate node and hand off. +// +// Two constraints drove this: +// 1. tests/windows-launchers.test.mjs requires customer-facing .bat files to be +// pure ASCII — Chinese Windows cmd.exe reads non-ASCII bytes as GBK and +// mis-parses the script. Localised text therefore cannot live in a .bat. +// 2. cmd.exe treats an unescaped ) as a block terminator, which produced a +// class of flash-exit regressions. Moving the logic out removes the hazard. +// +// Errors follow the house rule: what happened, why, and one thing to do next. + +import { spawn, spawnSync, execFileSync } from 'node:child_process'; +import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, cpSync, rmSync, renameSync } from 'node:fs'; +import { createServer } from 'node:net'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import process from 'node:process'; + +import { resolveLocale, createTranslator } from './i18n.mjs'; +import { buildChecks, runRepairs, writeDiagnostics } from './self-heal.mjs'; + +const GATEWAY_PORT_FROM = 18789; +const GATEWAY_PORT_TO = 18799; +const CONFIG_SERVER_DEFAULT_PORT = 18788; +const CONFIG_SERVER_WAIT_MS = 6000; +const GATEWAY_TOKEN = 'uclaw'; + +const libDir = dirname(fileURLToPath(import.meta.url)); +const uclawDir = resolve(libDir, '..'); + +const paths = { + app: join(uclawDir, 'app'), + data: join(uclawDir, 'data'), + get core() { return join(this.app, 'core'); }, + get state() { return join(this.data, '.openclaw'); }, + get config() { return join(this.state, 'openclaw.json'); }, + get runtimeJson() { return join(this.state, 'runtime.json'); }, +}; + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +// ---------------------------------------------------------------- output + +const dim = (s) => `${s}`; +const green = (s) => `${s}`; +const yellow = (s) => `${s}`; + +function say(message) { process.stdout.write(` ${message}\n`); } +function ok(message) { say(green(message)); } +function note(message) { say(dim(message)); } + +// Every user-facing failure gets the same three parts. Never print only a symptom. +function bail(t, key, vars = {}) { + process.stdout.write('\n'); + say(yellow(t(`${key}.what`, vars))); + say(t(`${key}.why`, vars)); + process.stdout.write('\n'); + say(`→ ${t(`${key}.action`, vars)}`); + process.stdout.write('\n'); + process.exitCode = 1; +} + +// ---------------------------------------------------------------- platform + +function runtimeDirName() { + if (process.platform === 'win32') return 'node-win-x64'; + if (process.platform === 'darwin') return process.arch === 'arm64' ? 'node-mac-arm64' : 'node-mac-x64'; + return process.arch === 'arm64' ? 'node-linux-arm64' : 'node-linux-x64'; +} + +function nodeBinary(runtimeDir) { + return process.platform === 'win32' + ? join(runtimeDir, 'node.exe') + : join(runtimeDir, 'bin', 'node'); +} + +function npmEntry(runtimeDir) { + return process.platform === 'win32' + ? join(runtimeDir, 'node_modules', 'npm', 'bin', 'npm-cli.js') + : join(runtimeDir, 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'); +} + +function openUrl(url) { + try { + if (process.platform === 'win32') { + // The empty "" is the window title; without it cmd treats a quoted URL as one. + spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore', windowsHide: true }).unref(); + } else if (process.platform === 'darwin') { + spawn('open', [url], { detached: true, stdio: 'ignore' }).unref(); + } else { + spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref(); + } + } catch { + // Opening a browser is a convenience, never a reason to fail startup. + } +} + +// ---------------------------------------------------------------- steps + +// Older drives shipped core-win / core-mac. Rename in place so one code path works. +function migrateLegacyCoreDir() { + for (const legacy of ['core-win', 'core-mac']) { + const from = join(paths.app, legacy); + if (existsSync(from) && !existsSync(paths.core)) { + try { renameSync(from, paths.core); } catch { /* keep going with the old name */ } + } + } +} + +function clearMacQuarantine(t, nodeBin) { + if (process.platform !== 'darwin') return; + try { + const attrs = execFileSync('xattr', ['-l', nodeBin], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }); + if (!attrs.includes('com.apple.quarantine')) return; + note(t('start.quarantine_removing')); + spawnSync('xattr', ['-rd', 'com.apple.quarantine', uclawDir], { stdio: 'ignore' }); + } catch { + // No xattr, or nothing quarantined — either way there is nothing to clear. + } +} + +function ensureDataDirs() { + for (const dir of [paths.state, join(paths.data, 'memory'), join(paths.data, 'backups'), join(paths.data, 'logs')]) { + mkdirSync(dir, { recursive: true }); + } +} + +// Moves the heavy, rebuildable caches (browser profile, V8 compile cache) off the +// USB drive and onto local disk. Failing here only costs speed, so stay silent. +function applyPortableCache(t, nodeBin) { + try { + const out = execFileSync(nodeBin, [join(libDir, 'portable-cache.mjs'), paths.state, uclawDir], { + encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], + }); + let cacheRoot = null; + for (const line of out.split(/\r?\n/)) { + const [key, ...rest] = line.split('='); + const value = rest.join('='); + if (key === 'UCLAW_COMPILE_CACHE_DIR') process.env.NODE_COMPILE_CACHE = value; + if (key === 'UCLAW_CACHE_ROOT') cacheRoot = value; + } + if (process.env.NODE_COMPILE_CACHE && cacheRoot) note(t('start.cache_local', { path: cacheRoot })); + } catch { /* cache stays on the drive */ } +} + +function ensureConfig(t) { + if (existsSync(paths.config)) return; + const legacy = join(paths.data, 'config.json'); + if (existsSync(legacy)) { + note(t('start.config_migrating')); + copyFileSync(legacy, paths.config); + ok(t('start.config_migrated')); + return; + } + note(t('start.config_creating')); + writeFileSync( + paths.config, + `${JSON.stringify({ gateway: { mode: 'local', auth: { token: GATEWAY_TOKEN } } }, null, 2)}\n`, + 'utf8' + ); + ok(t('start.config_created')); +} + +function installDependencies(t, nodeBin, runtimeDir) { + if (existsSync(join(paths.core, 'node_modules'))) return true; + + // The shipped zip has deps pre-installed; reaching here means an incomplete + // copy or a source checkout. Say "getting ready", not "node_modules not found". + note(t('start.deps_preparing')); + note(t('start.deps_slow_drive')); + + const result = spawnSync( + nodeBin, + [npmEntry(runtimeDir), 'install', '--registry=https://registry.npmjs.org', + '--ignore-scripts', '--no-audit', '--no-fund', '--omit=dev'], + { + cwd: paths.core, + stdio: ['ignore', 'ignore', 'inherit'], + // Keep npm's cache inside the app so nothing is left on the host machine. + env: { ...process.env, npm_config_cache: join(paths.app, '.npm-cache') }, + } + ); + + if (result.status !== 0 || !existsSync(join(paths.core, 'node_modules'))) return false; + ok(t('start.deps_done')); + return true; +} + +// Diagnose used to be something the user had to know to run. By the time +// startup had visibly failed, anyone who did not know that had already given up. +// Now it runs by itself, and only speaks up when it cannot fix the problem. +async function healAndRetry(t, attempt) { + note(t('start.checking')); + + const stamp = new Date().toISOString().replace(/[:.]/g, '-'); + const checks = buildChecks({ + paths, + defaultConfigPath: join(uclawDir, 'default-config.json'), + portRange: { from: GATEWAY_PORT_FROM, to: GATEWAY_PORT_TO }, + stamp, + }); + + const applied = await runRepairs(checks); + if (applied.length > 0) { + for (const { result } of applied) note(` ${result}`); + note(t('start.repaired')); + // Silence on success is the point: a user who never learns something was + // wrong had a working product. + if (await attempt()) return { healed: true }; + } + + const report = await writeDiagnostics({ + paths, + checks, + applied, + stamp, + versions: { + openclaw: readVersionFile('OPENCLAW_VERSION'), + node_pinned: readVersionFile('NODE_VERSION'), + }, + }); + return { healed: false, report }; +} + +function readVersionFile(name) { + for (const dir of [uclawDir, join(uclawDir, '..')]) { + try { return readFileSync(join(dir, name), 'utf8').trim(); } catch { /* try next */ } + } + return null; +} + +// OpenClaw routes every fetch through HTTP_PROXY when it is set, which breaks +// self-hosted model endpoints on a corporate network. Put those hosts in NO_PROXY. +function applyNoProxy(t, nodeBin) { + try { + const out = execFileSync(nodeBin, [join(libDir, 'resolve-no-proxy.mjs'), paths.config], { + encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], + }).trim(); + if (!out.startsWith('UCLAW_NO_PROXY=')) return; + const hosts = out.slice('UCLAW_NO_PROXY='.length); + if (!hosts) return; + process.env.NO_PROXY = hosts; + process.env.no_proxy = hosts; + note(t('start.no_proxy', { hosts })); + } catch { /* no proxy configured */ } +} + +// Hands the resolved locale to the HTML pages. They are opened from file://, +// where fetching the drive's own openclaw.json is blocked, so they cannot work +// out the locale themselves — and falling back to navigator.language would make +// the language follow the machine instead of the drive, which is exactly the +// behaviour we do not want. A generated + + +
-

🦞 U-Claw Pro

-

便携版 — 选择模型,填入 API Key,一键启动

+

🦞 U-Claw Settings

+

Paste an API key and you are done.

+ + +
+
+
Checking…
+
-
1选模型
-
2填 Key
-
3启动
+
1Your key
+
2Done
- +
-

选择 AI 模型

-

最省心:用「虾盘云」一个 Key 调用国内外全部大模型(中转站)。也可用下面各家自己的官方 Key。

+

Paste your API key

+

U-Claw works out the rest by itself. Your key is saved on this drive only — it is never uploaded anywhere.

-
-
- -

虾盘云 首选中转站

-

一个 Key 用 DeepSeek / Claude / GPT / 通义 等国内外全部大模型,无需翻墙

- → 注册并获取 API Key -
-
- -

DeepSeek 国内便宜

-

deepseek-v4-flash / deepseek-v4-pro,超低价格

- → 获取 API Key -
-
- -

MiniMax 国内

-

MiniMax-M2,速度快,性价比高

- → 获取 API Key -
-
- -

Kimi (月之暗面) 国内

-

kimi-k2,长上下文强

- → 获取 API Key -
-
- -

智谱 GLM 国内有免费

-

glm-5(zai provider),免费额度可用

- → 获取 API Key -
-
- -

通义千问 国内有免费

-

qwen-plus / qwen3-max,阿里云出品

- → 获取 API Key -
-
- -

豆包 (字节) 国内

-

doubao-seed-1.6,字节跳动

- → 获取 API Key -
-
- -

OpenAI

-

GPT-5.4,需翻墙或中转

- → 获取 API Key -
-
- -

Claude

-

Claude Opus 4.6 / Sonnet 4.6,需翻墙或中转

- → 获取 API Key -
-
- -

Groq 极快有免费

-

Llama 3.3 70B,超高速推理

- → 获取 API Key -
-
- -

硅基流动 国内便宜

-

多模型聚合,价格低

- → 获取 API Key -
-
- -

自定义 OpenAI 兼容

-

填写任意 OpenAI 兼容 API 地址

+
+
+ +
+
+
+ + +
- -
-
- - -
-

填写 API Key

-

请填写对应模型的 API Key

- -
-

📌 如何获取 API Key?

- +
- -
🦞
-

配置完成!

-

模型和 API Key 已保存,准备好后点击下方按钮启动

+

You are set up

+

Your model and key are saved on this drive.

http://127.0.0.1:18789
-

📱 接入更多渠道(可选)

-

点击展开卡片填写配置,启动时自动写入。不填也可以直接启动:

+

📱 Connect a chat app (optional)

+

Click a card to fill it in, or skip this entirely.

+
+

💬 WhatsApp

+

Talk to U-Claw from WhatsApp

+
+

⚠️ This uses an unofficial protocol. Your WhatsApp account can be banned for it. Do not connect a number you rely on.

+
+ + +
+
+

✈️ Telegram

-

接入 Telegram Bot

+

Talk to U-Claw from Telegram

-
-

🐧 QQ Bot

-

接入 QQ 群/私聊机器人

-
+
+

💼 Slack

+

Talk to U-Claw from your workspace

+
- - -
-
-
-

📘 飞书

-

接入飞书机器人

-
+
+

🎮 Discord

+

Talk to U-Claw from Discord

+
- - -
-
- - -

→ 从飞书开放平台获取

-
-
-
-
-

🏢 企业微信

-

接入企业微信机器人

-
+ + +
+ Chat apps used mainly in China +
+
+

🐧 QQ Bot

+
+
+ + +
+
+ + +

→ q.qq.com

+
+
+
+
+

📘 Feishu / Lark

+
+
+ + +
+
+ + +

→ open.feishu.cn

+
+
+
+
+

🏢 WeCom

+
+
+ + +
+
+ + +

→ work.weixin.qq.com

+
+
+
+
+

💬 WeChat

+

Scan a QR code to link a personal WeChat account

+
+
+

Click this card to show the QR code

+
+
+
+
+
+
- -

启动后会自动打开控制台,渠道配置会自动写入 openclaw.json

+ +

Chat app settings are saved now and take effect after U-Claw restarts.

+
+ +
+ +
- + +
- -
-

📦 技能 & 文档

-

技能存放在 skills/ 目录,文档存放在 docs/ 目录,随 U 盘携带

-
+ +
+

📦 What is on the drive

+

How the folders are organised

+
-

skills/ — 技能目录

-

放入 .md 技能文件,OpenClaw 会自动加载

+

skills/ — Skills

+

Drop a SKILL.md in here and it is picked up automatically

📁
-

docs/ — 文档目录

-

存放使用说明、帮助文档等

+

app/ — Runtime

+

Node.js and the OpenClaw core

- 📁 + ⚙️
-

data/ — 配置和聊天记录

-

API Key、聊天历史等保存在此

+

data/ — Your data

+

Your key and chat history. Stays on this drive.

🔒
+ +
+

🐛 Found a problem?

+

U-Claw is open source. Report anything that breaks on GitHub — nothing is collected or uploaded from your machine automatically.

+ +
diff --git a/u-claw-app/scripts/sync-lib.js b/u-claw-app/scripts/sync-lib.js index ec5d680..93ff3d1 100644 --- a/u-claw-app/scripts/sync-lib.js +++ b/u-claw-app/scripts/sync-lib.js @@ -10,7 +10,9 @@ const APP_DIR = path.resolve(__dirname, '..'); const PORTABLE_DIR = path.resolve(APP_DIR, '..', 'portable'); const COPIES = [ - { from: path.join(PORTABLE_DIR, 'Config.html'), to: path.join(APP_DIR, 'resources', 'Config.html') }, + // The settings UI has one implementation: config-server/public/index.html. + // portable/Config.html is only a redirect shim for the old file:// entry point. + { from: path.join(PORTABLE_DIR, 'config-server', 'public', 'index.html'), to: path.join(APP_DIR, 'resources', 'Config.html') }, ]; for (const { from, to } of COPIES) { diff --git a/u-claw-app/setup.bat b/u-claw-app/setup.bat index a57fd27..39d8f04 100644 --- a/u-claw-app/setup.bat +++ b/u-claw-app/setup.bat @@ -10,9 +10,9 @@ echo ======================================== echo. set "APP_DIR=%~dp0" -set "NODE_VER=v22.14.0" -set "MIRROR=https://registry.npmmirror.com" -set "NODE_MIRROR=https://npmmirror.com/mirrors/node" +set "NODE_VER=v22.22.1" +set "MIRROR=https://registry.npmjs.org" +set "NODE_MIRROR=https://nodejs.org/dist" REM ---- 1. Check Node.js ---- echo [1/4] 检查 Node.js... @@ -36,7 +36,7 @@ if "%NODE_OK%"=="0" ( echo https://nodejs.org/ echo. echo 方法2 - 国内镜像(推荐): - echo https://npmmirror.com/mirrors/node/%NODE_VER%/ + echo https://nodejs.org/dist/%NODE_VER%/ echo 下载 node-%NODE_VER%-win-x64.zip,解压后加到 PATH echo. echo 方法3 - Scoop(包管理器): @@ -57,8 +57,8 @@ echo. cd /d "%APP_DIR%" -set "ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/" -set "ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/" +set "ELECTRON_MIRROR=https://github.com/electron/electron/releases/download/" +set "ELECTRON_BUILDER_BINARIES_MIRROR=https://github.com/electron/electron-builder-binaries/releases/download/" call npm install --registry=%MIRROR% echo. diff --git a/u-claw-app/setup.sh b/u-claw-app/setup.sh index ee56e02..0009330 100755 --- a/u-claw-app/setup.sh +++ b/u-claw-app/setup.sh @@ -14,9 +14,9 @@ NC='\033[0m' BOLD='\033[1m' APP_DIR="$(cd "$(dirname "$0")" && pwd)" -NODE_VER="v22.16.0" -MIRROR="https://registry.npmmirror.com" -NODE_MIRROR="https://npmmirror.com/mirrors/node" +NODE_VER="$(tr -d "[:space:]" < "$(dirname "$0")/../NODE_VERSION" 2>/dev/null || echo v22.22.1)" +MIRROR="https://registry.npmjs.org" +NODE_MIRROR="https://nodejs.org/dist" clear echo "" @@ -67,7 +67,7 @@ if [ -z "$NODE_BIN" ]; then NODE_BIN="$NODE_BIN_PATH" else echo -e " ${YELLOW}下载 Node.js $NODE_VER ($PLATFORM)...${NC}" - echo -e " ${CYAN}镜像: npmmirror.com${NC}" + echo -e " ${CYAN}Source: nodejs.org${NC}" TARBALL="node-${NODE_VER}-${PLATFORM}.tar.gz" URL="${NODE_MIRROR}/${NODE_VER}/${TARBALL}" @@ -96,8 +96,8 @@ echo "" cd "$APP_DIR" # Set electron mirror for China -export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" -export ELECTRON_BUILDER_BINARIES_MIRROR="https://npmmirror.com/mirrors/electron-builder-binaries/" +export ELECTRON_MIRROR="https://github.com/electron/electron/releases/download/" +export ELECTRON_BUILDER_BINARIES_MIRROR="https://github.com/electron/electron-builder-binaries/releases/download/" npm install --registry="$MIRROR" 2>&1 | tail -5 echo "" diff --git a/u-claw-app/src/loading.html b/u-claw-app/src/loading.html index f08c351..aa3798d 100644 --- a/u-claw-app/src/loading.html +++ b/u-claw-app/src/loading.html @@ -1,5 +1,5 @@ - +