diff --git a/.github/workflows/build-node-musl.yml b/.github/workflows/build-node-musl.yml new file mode 100644 index 0000000..8cedbaf --- /dev/null +++ b/.github/workflows/build-node-musl.yml @@ -0,0 +1,70 @@ +name: Build Node.js ARM64 musl + +on: + workflow_dispatch: + inputs: + node_version: + description: 'Node.js 版本 (如 22.16.0)' + required: true + default: '22.16.0' + +jobs: + build: + name: Build Node.js ${{ github.event.inputs.node_version }} ARM64 musl + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: linux/arm64 + + - name: Build Node.js ARM64 musl portable + run: | + NODE_VER="${{ github.event.inputs.node_version }}" + mkdir -p dist + echo "=== Building Node.js v${NODE_VER} ARM64 musl portable tarball ===" + docker run --rm --platform linux/arm64 \ + -v "$PWD/dist:/output" \ + -v "$PWD/scripts/build-node-musl.sh:/build-node-musl.sh:ro" \ + -e "NODE_VER=${NODE_VER}" \ + alpine:3.21 sh /build-node-musl.sh + + - name: Verify tarball + run: | + echo "=== Output files ===" + ls -lh dist/ + echo "" + echo "=== Tarball contents (first 20 entries) ===" + tar tJf dist/*.tar.xz | head -20 + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: node-arm64-musl + path: dist/*.tar.xz + + - name: Create/Update Release + uses: softprops/action-gh-release@v2 + with: + tag_name: node-bins + name: "Node.js Prebuilt Binaries (musl)" + files: dist/*.tar.xz + draft: false + prerelease: false + make_latest: false + body: | + 预编译的 Node.js ARM64 musl 二进制文件,供 ARM64 OpenWrt/iStoreOS 设备使用。 + + Node.js 官方 [unofficial-builds](https://unofficial-builds.nodejs.org/) 仅提供 x64 musl 构建,不提供 ARM64 musl。 + 此 Release 使用 Alpine Linux ARM64 (musl libc) 环境打包。 + + **注意**: 实际 Node.js 版本可能与文件名中的版本略有差异(取决于 Alpine 仓库提供的版本), + 但主版本号 (v22.x) 保证兼容。 + + `openclaw-env setup` 会在 ARM64 musl 设备上自动从此处下载。 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f0c7666..b9ab84f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,6 +58,22 @@ jobs: - name: List outputs run: ls -lh dist/ + - name: Extract changelog + id: changelog + run: | + VER="${{ steps.version.outputs.version }}" + # 提取当前版本的 CHANGELOG 内容 (从 ## [version] 到下一个 ## [ 之间) + CHANGELOG=$(awk "/^## \\[${VER}\\]/{found=1; next} /^## \\[/{if(found) exit} found{print}" CHANGELOG.md) + if [ -z "$CHANGELOG" ]; then + CHANGELOG="暂无更新日志" + fi + # 写入多行输出 + { + echo "content<> "$GITHUB_OUTPUT" + - name: Upload artifacts uses: actions/upload-artifact@v4 with: @@ -78,6 +94,10 @@ jobs: OpenClaw AI 网关的 OpenWrt LuCI 管理插件。 + ### 更新日志 + + ${{ steps.changelog.outputs.content }} + ### 下载说明 | 文件 | 说明 | diff --git a/CHANGELOG.md b/CHANGELOG.md index a038523..d874fcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。 +## [1.0.1] - 2026-03-02 + +### 修复 +- **P0** web-pty.js `loadAuthToken` 读取错误的 UCI key `luci_token` → `pty_token` +- **P0** init.d `get_oc_entry()` 管道子 shell 导致返回值丢失,改用临时文件重定向 +- **P1** Gateway procd respawn 无限重试 (`3600 5 0`) → 限制最多 5 次 (`3600 5 5`) +- **P1** Telegram 配对流程管道子 shell 变量丢失,改用临时文件避免子 shell +- **P1** `openclaw.lua` PID 提取 `sed` 正则不可靠,改用 `awk` + `split` +- **P2** init.d 和 uci-defaults 弱 token fallback (`echo "auto_$(date +%s)"`) → `dd if=/dev/urandom` +- **P2** `oc-config.sh` 恢复出厂 `timeout` 命令可能不存在,添加 `command -v` 检查和降级方案 +- **P2** web-pty.js SIGTERM 不清理 HTTPS server,统一 `shutdown()` 函数 + +### 新增 +- GitHub Copilot 配置新增 OAuth 授权登录方式 (通过 `copilot-proxy` 插件) +- `uci-defaults` 首次安装时自动生成 `pty_token` +- Web 控制台和状态面板显示当前活跃模型名称 + +### 改进 +- Qwen 使用 `models.dashscope` 键名、SiliconFlow 使用 `models.siliconflow`,避免 `models.custom` 键冲突 +- `get_openclaw_version()` 从 `package.json` 读取版本号,不再每次启动 Node.js 进程 +- PTY 终端 WebSocket 重连策略改为无限重连 (`MAX_RETRY=Infinity`) +- Makefile `PKG_VERSION` 从 `VERSION` 文件动态读取 + ## [1.0.0] - 2026-03-02 ### 新增 diff --git a/Makefile b/Makefile index 0450e7d..9542dff 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-openclaw -PKG_VERSION:=1.0.0 +PKG_VERSION:=$(strip $(shell cat $(CURDIR)/VERSION 2>/dev/null || echo "1.0.0")) PKG_RELEASE:=1 PKG_MAINTAINER:=10000ge10000 <10000ge10000@users.noreply.github.com> diff --git a/README.md b/README.md index b9c5e1d..9c07a62 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,23 @@ sh /etc/uci-defaults/99-openclaw rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* ``` -## 🔰 首次使用 +## � 一键部署下载 + +OpenClaw 支持全平台一键部署,请根据你的设备选择对应方式。 + +> **💡 提示**:OpenWrt 路由器请直接使用下方 [📦 安装](#-安装) 章节的命令,无需使用本节下载包。 + +| 平台 | 下载链接 | 说明 | +|------|----------|------| +| 🐧 Linux (Ubuntu/Debian) | [夸克网盘](https://pan.quark.cn/s/c25bb5c20db1) | 或直接 `curl -fsSL "https://alist.910501.xyz/d/openclaw/install.sh?sign=RUSBfm1vy35Z-2S86e-Hr0s1bR2u_rATHXEpY888zi8=:0" \| bash` | +| 🪟 Windows (Win10/Win11) | [夸克网盘](https://pan.quark.cn/s/af01a152dad7) | 解压后右键「一键安装.bat」以管理员身份运行 | +| 🍎 macOS (Intel & Apple Silicon) | [夸克网盘](https://pan.quark.cn/s/99bad2c03e5c) | 解压后 `bash setup.sh` 授权,再双击「一键安装.command」 | +| 🐂 飞牛 NAS (FnOS) | [夸克网盘](https://pan.quark.cn/s/fea2552a1b73) | 离线 FPK 包,在应用商店「手动安装」 | +| 📡 OpenWrt 路由器 | [GitHub Releases](https://github.com/10000ge10000/luci-app-openclaw/releases/latest) | 见下方安装章节 | + +--- + +## �🔰 首次使用 1. 打开 LuCI → 服务 → OpenClaw,点击「安装运行环境」 2. 安装完成后服务会自动启动,点击「刷新页面」查看状态 @@ -118,6 +134,64 @@ luci-app-openclaw/ └── .github/workflows/build.yml # GitHub Actions ``` +## 📡 OpenWrt 路由器专属说明 + +### 为什么选择路由器部署? + +路由器 24 小时在线,天然适合作为 AI 网关的宿主——家里所有设备共享同一个 AI 服务,Telegram / Discord 消息也能全天候响应,无需常开电脑。 + +### 支持的设备 + +| 架构 | 典型设备 | 支持状态 | +|------|----------|----------| +| x86_64 | N100 / N5105 软路由、iStoreOS 小主机 | ✅ 完全支持 | +| aarch64 | Raspberry Pi 4/5、R4S、部分 ARM64 路由器 | ✅ 完全支持 | +| 32 位 ARM | 老款 MT7620 / MT7621 路由器 | ❌ 不支持(Node.js 22 无 32 位包) | + +### 安装步骤(OpenWrt / iStoreOS) + +**第一步:安装 LuCI 插件** + +```bash +# 推荐:.run 自解压包,一行搞定 +wget https://github.com/10000ge10000/luci-app-openclaw/releases/latest/download/luci-app-openclaw.run +sh luci-app-openclaw.run +``` + +**第二步:安装 OpenClaw 运行环境** + +打开 LuCI → **服务** → **OpenClaw** → 点击「📦 安装运行环境」,脚本会自动完成: +- 检测 CPU 架构(x86_64 / aarch64) +- 检测 C 库类型(glibc / musl,绝大多数 OpenWrt 为 musl) +- 下载对应 Node.js 22 预编译包 +- 安装 pnpm 和 OpenClaw 本体 + +> **网络慢?** 可在路由器 SSH 中指定国内镜像加速 Node.js 下载: +> ```bash +> NODE_MIRROR=https://npmmirror.com/mirrors/node openclaw-env setup +> ``` + +**第三步:配置 AI 模型和消息渠道** + +进入「**配置管理**」页面,在内嵌 Web 终端中使用交互式向导,选数字即可完成配置,支持: +- OpenAI / Anthropic Claude / Google Gemini / DeepSeek / GitHub Copilot / OpenRouter / 通义千问 / Grok / Groq / 硅基流动 等 12+ 家提供商 +- Telegram / Discord / 飞书 / Slack 消息渠道 + +**第四步:用 Telegram 与 AI 对话** + +配置完 Telegram Bot Token 后,重启网关即可在 Telegram 直接给 Bot 发消息,路由器全天候在线响应。 + +### 与其他平台脚本的区别 + +| 对比项 | Linux/Mac/Win 脚本 | OpenWrt 插件 | +|--------|-------------------|--------------| +| 管理界面 | 命令行菜单 | LuCI 可视化界面 | +| 开机自启 | 系统服务 / 守护进程 | procd 托管,崩溃自动重启 | +| 安装包格式 | .sh / .bat / .command | .run / .ipk | +| Node.js 来源 | 官方 + npm 镜像 | 自动检测 musl/glibc,按需拉取 | + +--- + ## ❓ 常见问题 **安装后 LuCI 菜单没有出现** diff --git a/VERSION b/VERSION index 3eefcb9..7dea76e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 diff --git a/luasrc/controller/openclaw.lua b/luasrc/controller/openclaw.lua index efcea54..b09e80c 100644 --- a/luasrc/controller/openclaw.lua +++ b/luasrc/controller/openclaw.lua @@ -4,8 +4,27 @@ module("luci.controller.openclaw", package.seeall) -- 公共辅助: 获取 OpenClaw 版本号 local function get_openclaw_version() local sys = require "luci.sys" - local ver = sys.exec("[ -x /opt/openclaw/node/bin/node ] && for d in /opt/openclaw/global/lib/node_modules/openclaw /opt/openclaw/global/node_modules/openclaw /opt/openclaw/global/*/node_modules/openclaw; do [ -f \"$d/openclaw.mjs\" ] && /opt/openclaw/node/bin/node \"$d/openclaw.mjs\" --version 2>/dev/null && break; [ -f \"$d/dist/cli.js\" ] && /opt/openclaw/node/bin/node \"$d/dist/cli.js\" --version 2>/dev/null && break; done"):gsub("%s+", "") - return ver + -- 优先从 package.json 读取版本号 (轻量),避免每次启动 node 进程 + local dirs = { + "/opt/openclaw/global/lib/node_modules/openclaw", + "/opt/openclaw/global/node_modules/openclaw", + } + -- pnpm 版本目录 + local pnpm_glob = sys.exec("ls -d /opt/openclaw/global/*/node_modules/openclaw 2>/dev/null"):gsub("%s+$", "") + for d in pnpm_glob:gmatch("[^\n]+") do + dirs[#dirs + 1] = d + end + for _, d in ipairs(dirs) do + local pkg = d .. "/package.json" + local f = io.open(pkg, "r") + if f then + local content = f:read("*a") + f:close() + local ver = content:match('"version"%s*:%s*"([^"]+)"') + if ver and ver ~= "" then return ver end + end + end + return "" end function index() @@ -99,9 +118,22 @@ function action_status() local pty_check = sys.exec("netstat -tlnp 2>/dev/null | grep -c ':" .. pty_port .. " ' || echo 0"):gsub("%s+", "") result.pty_running = (tonumber(pty_check) or 0) > 0 + -- 读取当前活跃模型 + local config_file = "/opt/openclaw/data/.openclaw/openclaw.json" + local cf = io.open(config_file, "r") + if cf then + local content = cf:read("*a") + cf:close() + -- 简单正则提取 "primary": "xxx" + local model = content:match('"primary"%s*:%s*"([^"]+)"') + if model and model ~= "" then + result.active_model = model + end + end + -- PID 和内存 if result.gateway_running then - local pid = sys.exec("netstat -tlnp 2>/dev/null | grep ':" .. port .. " ' | head -1 | sed 's|.* \\([0-9]*\\)/.*|\\1|'"):gsub("%s+", "") + local pid = sys.exec("netstat -tlnp 2>/dev/null | awk '/:" .. port .. " /{split($NF,a,\"/\");print a[1];exit}'"):gsub("%s+", "") if pid and pid ~= "" then result.pid = pid -- 内存 (VmRSS from /proc) diff --git a/luasrc/view/openclaw/console.htm b/luasrc/view/openclaw/console.htm index da796b1..ccde507 100644 --- a/luasrc/view/openclaw/console.htm +++ b/luasrc/view/openclaw/console.htm @@ -73,6 +73,9 @@ local port = uci:get("openclaw", "main", "port") or "18789" 网关地址: - | + 活跃模型: + - + | 状态: 检查中...