🛸 Sync 2026-07-10 20:47:34

This commit is contained in:
github-actions[bot] committed 2026-07-10 20:47:34 +08:00
1 parent bc43e5009d
commit bdfb23c9ce
25 files changed
+3111 -2838

No files matched your search

+2 -2
View File
@@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_BAIDUDRIVE:=$(ARCH)
PKG_NAME:=baidudrive
PKG_VERSION:=1.0.1
PKG_RELEASE:=3
PKG_VERSION:=1.0.2
PKG_RELEASE:=4
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
PKG_HASH:=skip
-1
View File
@@ -7,7 +7,6 @@ config baidudrive
option 'sdk_host' '127.0.0.1'
option 'sdk_port' '8001'
option 'macid' ''
option 'device_type' ''
option 'usb_path' ''
option 'download_path' '/'
option 'quota_path' ''
+32 -4
View File
@@ -2,8 +2,10 @@
START=93
USE_PROCD=1
DEVICE_TYPE="202604101148240791"
get_config() {
config_section="$1"
config_get_bool enabled "$1" enabled 1
config_get data_dir "$1" data_dir ""
config_get host "$1" host "0.0.0.0"
@@ -12,7 +14,6 @@ get_config() {
config_get sdk_host "$1" sdk_host "127.0.0.1"
config_get sdk_port "$1" sdk_port "8001"
config_get macid "$1" macid ""
config_get device_type "$1" device_type ""
config_get usb_path "$1" usb_path ""
config_get download_path "$1" download_path "/"
config_get quota_path "$1" quota_path ""
@@ -53,6 +54,33 @@ storage_root_from_data_dir() {
df -P "$path" 2>/dev/null | awk 'NR == 2 { print $6 }'
}
default_macid() {
local netdev mac
for netdev in br-lan eth0 lan0; do
if [ -r "/sys/class/net/$netdev/address" ]; then
mac="$(tr -d ':' <"/sys/class/net/$netdev/address")"
if [ -n "$mac" ]; then
printf '%s\n' "$mac"
return 0
fi
fi
done
return 1
}
ensure_macid() {
if [ -n "$macid" ]; then
return 0
fi
macid="$(default_macid)"
if [ -n "$macid" ] && [ -n "$config_section" ]; then
uci set "baidudrive.$config_section.macid=$macid"
uci commit baidudrive
logger -t baidudrive "generated macid from network interface: $macid"
fi
}
start_service() {
config_load baidudrive
config_foreach get_config baidudrive
@@ -61,8 +89,8 @@ start_service() {
fi
require_start_value data_dir "$data_dir" || return 1
ensure_macid
require_start_value macid "$macid" || return 1
require_start_value device_type "$device_type" || return 1
require_executable /usr/sbin/baidudrive || return 1
require_executable "$sdk_dir/baiduNas" || return 1
require_executable "$sdk_dir/P2PClient" || return 1
@@ -91,7 +119,7 @@ start_service() {
-ip "$sdk_host" \
-port "$sdk_port" \
-macid "$macid" \
-type "$device_type" \
-type "$DEVICE_TYPE" \
-tmppath "$tmp_path" \
-usbpath "$usb_path" \
-downloadpath "$download_path" \
@@ -122,7 +150,7 @@ start_service() {
procd_open_instance baidudrive
procd_set_param env \
BAIDU_NAS_MACID="$macid" \
BAIDU_NAS_DEVICE_TYPE="$device_type" \
BAIDU_NAS_DEVICE_TYPE="$DEVICE_TYPE" \
BAIDU_NAS_USB_PATH="$usb_path" \
BAIDU_NAS_QUOTA_PATH="$quota_path"
procd_set_param command /usr/sbin/baidudrive --host "$host" --port "$port" --data "$data_dir"
@@ -1541,25 +1541,13 @@ function loadLabelValues(uciconfig, sectiontype, options = {}) {
case 'rematch-name': {
const names = new Set();
for (const type of ['rules', 'subrules']) {
uci.sections(uciconfig, type, (res) => {
if (res.enabled === '0')
return;
try {
const payload =
JSON.parse(res?.entry?.trim() || '{}').payload || [];
for (const p of payload)
if (p.type === 'REMATCH-NAME')
names.add(p.factor);
} catch {}
});
}
uci.sections(uciconfig, 'node', (res) => {
if (res.enabled !== '0' && res.target_rematch_name)
names.add(res.target_rematch_name);
});
for (const name of names)
values.push([name, name]);
break;
}
default:
@@ -461,6 +461,9 @@ function renderListeners(s, uciconfig, isClient) {
o.modalonly = true;
o = s.taboption('field_general', form.ListValue, 'snell_version', _('Version'));
o.value('1', _('v1'));
o.value('2', _('v2'));
o.value('3', _('v3'));
o.value('4', _('v4'));
o.value('5', _('v5'));
o.default = '4';
@@ -558,6 +561,7 @@ function renderListeners(s, uciconfig, isClient) {
o.value('', _('none'));
o.value('obfs', _('obfs-simple'));
o.value('shadow-tls', _('shadow-tls'));
o.value('restls', _('restls'));
//o.value('kcp-tun', _('kcp-tun'));
o.validate = function(section_id, value) {
const type = this.section.getOption('type').formvalue(section_id);
@@ -591,13 +595,13 @@ function renderListeners(s, uciconfig, isClient) {
o.datatype = 'hostport';
o.placeholder = 'cloud.tencent.com:443';
o.rmempty = false;
o.depends({plugin: 'shadow-tls'});
o.depends({plugin: /^(shadow-tls|restls)$/});
o.modalonly = true;
o = s.taboption('field_general', hm.GenValue, 'plugin_opts_thetlspassword', _('Plugin: ') + _('Password'));
o.password = true;
o.rmempty = false;
o.depends({plugin: 'shadow-tls'});
o.depends({plugin: /^(shadow-tls|restls)$/});
o.modalonly = true;
o = s.taboption('field_general', form.ListValue, 'plugin_opts_shadowtls_version', _('Plugin: ') + _('Version'));
@@ -608,6 +612,12 @@ function renderListeners(s, uciconfig, isClient) {
o.depends({plugin: 'shadow-tls'});
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'plugin_opts_restls_script', _('Plugin: ') + _('Restls script'));
o.default = '300?100<1,400~100,350~100,600~100,300~200,300~100';
o.rmempty = false;
o.depends({plugin: 'restls'});
o.modalonly = true;
/* Extra fields */
if (isClient) {
o = s.taboption('field_general', form.Value, 'routing_mark', _('Routing mark (Fwmark)'));
@@ -1134,6 +1144,8 @@ function renderListeners(s, uciconfig, isClient) {
o.depends('tls_reality', '1');
o.modalonly = true;
// @VMess-TLSmirror fields
/* Transport fields */
o = s.taboption('field_general', form.Flag, 'transport_enabled', _('Transport'));
o.default = o.disabled;
@@ -1144,6 +1156,8 @@ function renderListeners(s, uciconfig, isClient) {
o.value('grpc', _('gRPC'));
o.value('ws', _('WebSocket'));
o.value('xhttp', _('XHTTP'));
//o.value('mkcp', _('mKCP')); // VMess only
//o.value('mekya', _('Mekya')); // VMess only
o.validate = function(section_id, value) {
const type = this.section.getOption('type').formvalue(section_id);
@@ -1217,6 +1231,35 @@ function renderListeners(s, uciconfig, isClient) {
o.placeholder = '1000000';
o.depends({transport_enabled: '1', transport_type: 'xhttp'});
o.modalonly = true;
/* Multiplex fields */
o = s.taboption('field_general', form.Flag, 'smux_enabled', _('Multiplex'));
o.default = o.disabled;
o.depends({type: /^(shadowsocks|vmess|vless|trojan|tuic|hysteria2|sudoku)$/});
o.modalonly = true;
o = s.taboption('field_multiplex', form.Flag, 'smux_padding', _('Enable padding'));
o.default = o.disabled;
o.depends('smux_enabled', '1');
o.modalonly = true;
o = s.taboption('field_multiplex', form.Flag, 'smux_brutal', _('Enable TCP Brutal'),
_('Enable TCP Brutal congestion control algorithm'));
o.default = o.disabled;
o.depends('smux_enabled', '1');
o.modalonly = true;
o = s.taboption('field_multiplex', form.Value, 'smux_brutal_up', _('Upload bandwidth'),
_('Upload bandwidth in Mbps.'));
o.datatype = 'uinteger';
o.depends('smux_brutal', '1');
o.modalonly = true;
o = s.taboption('field_multiplex', form.Value, 'smux_brutal_down', _('Download bandwidth'),
_('Download bandwidth in Mbps.'));
o.datatype = 'uinteger';
o.depends('smux_brutal', '1');
o.modalonly = true;
}
return baseclass.extend({
@@ -13,7 +13,7 @@ const parseProxyGroupYaml = hm.parseYaml.extend({
if (!cfg.type)
return null;
// key mapping // 2026/07/05
// key mapping // 2026/07/08
let config = hm.removeBlankAttrs({
id: this.id,
label: this.label,
@@ -259,7 +259,7 @@ const parseDNSYaml = hm.parseYaml.extend({
if (detour)
addr.setParam('detour', hm.preset_outbound.dns.map(([key, label]) => key).includes(detour) ? detour : detour === 'RULES' ? '' : this.calcID(hm.glossary["proxy_group"].field, detour));
// key mapping // 2026/01/17
// key mapping // 2026/07/08
let config = {
id: this.id,
label: this.label,
@@ -291,7 +291,7 @@ const parseDNSPolicyYaml = hm.parseYaml.extend({
break;
}
// key mapping // 2026/01/17
// key mapping // 2026/07/08
let config = {
id: this.id,
label: this.label,
@@ -312,7 +312,7 @@ const parseRulesYaml = hm.parseYaml.extend({
if (!entry)
return null;
// key mapping // 2026/06/12
// key mapping // 2026/07/08
let config = {
id: this.id,
label: '%s %s'.format(this.id.slice(0,7), _('(Imported)')),
@@ -563,13 +563,19 @@ function renderPayload(s, total, uciconfig) {
o.depends(Object.fromEntries([[prefix + 'type', /\bPROCESS\b/]]));
initPayload(o, n, 'factor', uciconfig);
o = s.option(form.Value, prefix + 'rematchname', _('Factor') + ` ${n+1}`);
o.value('rematch1');
o.validate = hm.validateAuthUsername;
o = s.option(form.ListValue, prefix + 'rematchname', _('Factor') + ` ${n+1}`);
if (n === 0)
o.depends('type', 'REMATCH-NAME');
o.depends(prefix + 'type', 'REMATCH-NAME');
initPayload(o, n, 'factor', uciconfig);
o.load = L.bind(function(n, key, uciconfig, section_id) {
hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'rematch-name')
], section_id);
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key];
}, o, n, 'factor', uciconfig)
o = s.option(form.Value, prefix + 'uint', _('Factor') + ` ${n+1}`);
o.datatype = 'uinteger';
@@ -684,15 +690,13 @@ function renderPayload(s, total, uciconfig) {
})
initDynamicPayload(o, n, 'factor', uciconfig);
o.load = L.bind(function(n, key, uciconfig, section_id) {
let fusedval = [
hm.loadLabel.call(this, [
['REMATCHNAME', _('-- REMATCH-NAME --')],
...hm.loadLabelValues(this.config, 'rematch-name'),
['NETWORK', _('-- NETWORK --')],
['udp', _('UDP')],
['tcp', _('TCP')],
['RULESET', _('-- RULE-SET --')]
];
hm.loadLabel.call(this, [
...fusedval,
['RULESET', _('-- RULE-SET --')],
...hm.loadLabelValues(this.config, 'ruleset')
], section_id);
@@ -1899,7 +1903,8 @@ return view.extend({
so = ss.option(form.DynamicList, 'fallback_filter_geosite', _('Geosite'),
_('Match geosite.</br>') +
_('The matching <code>%s</code> will be deemed as poisoned.').format(_('Domain')));
_('The matching <code>%s</code> will be deemed as poisoned.').format(_('Domain')) + `</br>` +
_('Option is deprecated. Please use <code>%s</code> instead.').format(_('DNS policy')));
so = ss.option(form.DynamicList, 'fallback_filter_ipcidr', _('IP CIDR'),
_('Match response with ipcidr.</br>') +
@@ -264,14 +264,17 @@ return view.extend({
so.depends({type: /^(rematch|direct|mieru)$/, '!reverse': true});
/* Rematch fields */
so = ss.taboption('field_general', form.ListValue, 'target_rematch_name', _('REMATCH-NAME marking'));
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'rematch-name')
], section_id);
}
so.rmempty = false;
// https://github.com/MetaCubeX/mihomo/pull/2862
so = ss.taboption('field_general', form.Value, 'target_rematch_name', _('REMATCH-NAME marking'));
so.value('rematch1');
so.validate = function(section_id, value) {
const target_sub_rule = this.section.getOption('target_sub_rule').formvalue(section_id);
if (!value && !target_sub_rule)
return _('Expecting: Least one of %s or %s.').format(_('REMATCH-NAME marking'), _('Use sub rule'));
return hm.validateAuthUsername.call(this, section_id, value);
};
so.depends('type', 'rematch');
so.modalonly = true;
@@ -282,6 +285,14 @@ return view.extend({
...hm.loadLabelValues(this.config, 'subrule-group')
], section_id);
}
so.validate = function(section_id, value) {
const target_rematch_name = this.section.getOption('target_rematch_name').formvalue(section_id);
if (!value && !target_rematch_name)
return _('Expecting: Least one of %s or %s.').format(_('REMATCH-NAME marking'), _('Use sub rule'));
return true;
};
so.depends('type', 'rematch');
so.modalonly = true;
@@ -1095,7 +1106,7 @@ return view.extend({
let tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input');
// Force enabled
if (['trojan', 'anytls', 'hysteria', 'hysteria2', 'tuic', 'trusttunnel'].includes(type)) {
if (['trojan', 'anytls', 'hysteria', 'hysteria2', 'tuic', 'trusttunnel', 'masque'].includes(type)) {
tls.checked = true;
tls.disabled = true;
} else {
@@ -1104,7 +1115,7 @@ return view.extend({
return true;
}
so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel)$/});
so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel|masque)$/});
so.modalonly = true;
so = ss.taboption('field_tls', form.Flag, 'tls_disable_sni', _('Disable SNI'),
@@ -1115,7 +1126,7 @@ return view.extend({
so = ss.taboption('field_tls', form.Value, 'tls_sni', _('TLS SNI'),
_('Used to verify the hostname on the returned certificates.'));
so.depends({tls: '1', type: /^(http|vmess|vless|trojan|anytls|hysteria|hysteria2|trusttunnel)$/});
so.depends({tls: '1', type: /^(http|vmess|vless|trojan|anytls|hysteria|hysteria2|trusttunnel|masque)$/});
so.depends({tls: '1', type: /^(tuic)$/, tls_disable_sni: '0'});
so.modalonly = true;
@@ -1261,6 +1272,8 @@ return view.extend({
so.depends('tls_reality', '1');
so.modalonly = true;
// @VMess-TLSmirror fields
/* Transport fields */
so = ss.taboption('field_general', form.Flag, 'transport_enabled', _('Transport'));
so.default = so.disabled;
@@ -1274,6 +1287,8 @@ return view.extend({
so.value('grpc', _('gRPC'));
so.value('ws', _('WebSocket'));
so.value('xhttp', _('XHTTP'));
//so.value('mkcp', _('mKCP')); // VMess only
//so.value('mekya', _('Mekya')); // VMess only
so.validate = function(section_id, value) {
const type = this.section.getOption('type').formvalue(section_id);
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+21 -1
View File
@@ -363,6 +363,16 @@ export function parseListener(cfg, isClient, label) {
dest: cfg.plugin_opts_handshake_dest
}
}
} : cfg.plugin === 'restls' ? {
// restls
"res-tls": {
enable: true,
dest: cfg.plugin_opts_handshake_dest,
password: cfg.plugin_opts_thetlspassword,
"restls-script": cfg.plugin_opts_restls_script,
//"min-record-len": 0,
//proxy: ""
}
} : {}
) : {}),
@@ -405,7 +415,17 @@ export function parseListener(cfg, isClient, label) {
"sc-max-each-post-bytes": strToInt(cfg.transport_xhttp_sc_max_each_post_bytes) || null,
// @其他的配置
} : null
} : {})
} : {}),
/* Multiplex fields */
"mux-option": cfg.smux_enabled === '1' ? {
padding: strToBool(cfg.smux_padding),
brutal: cfg.smux_brutal === '1' ? {
enabled: true,
up: strToInt(cfg.smux_brutal_up) || null, // Mbps
down: strToInt(cfg.smux_brutal_down) || null // Mbps
} : null
} : null
}
};
/* String universal end */
+24 -4
View File
@@ -4,15 +4,31 @@
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
## [2.0.11] - 2026-07-10
### 修复微信扫码后 Gateway 丢失插件
- 微信安装、升级和登录前置检查改为使用官方 `plugins enable openclaw-weixin`、`plugins registry --refresh` 和 `plugins inspect` 完成闭环。
- 只有官方 npm 安装记录、SQLite 注册表和微信 channel capability 全部验证通过后,LuCI 才返回安装成功。
- 启动自愈不再删除 OpenClaw 官方生成的 `plugins.entries.openclaw-weixin`,并在 Gateway 启动前以 `openclaw` 用户刷新和验证注册表。
- 修复扫码认证已保存,但 Gateway 重启后只加载 `memory-core` 并报 `invalid channels.start channel` 的问题。
### 验证
- 增加插件启用、SQLite 注册表刷新、加载能力校验和冷启动自愈的契约断言。
---
## [2.0.10] - 2026-07-08
### 修复微信渠道配对
- 启动 OpenClaw 时自动自愈微信 npm 插件注册,补齐 `plugins.installs.openclaw-weixin`、`plugins.allow` 和 `channels.openclaw-weixin.enabled`。
- 适配 OpenClaw 2026.6.11 SQLite `installed_plugin_index`,微信安装与升级改用官方 `openclaw plugins install --pin` 写入插件索引。
- 启动时检测旧 npm 直装目录并一次性迁移到官方插件索引,同时补齐 `plugins.allow` 和 `channels.openclaw-weixin.enabled`。
- 微信安装、升级和登录流程增加 `https://ilinkai.weixin.qq.com` 连通性检查,日志直接显示 HTTP、TLS 或 timeout 结果。
- 兼容没有 `su` / `runuser` 的 OpenWrt 固件,微信安装、升级、登录和下线改用 `start-stop-daemon` 兜底以 `openclaw` 用户执行。
- 微信安装网络探测优先使用 `curl`,避免低内存/精简 musl 固件上 Node `fetch` 触发 undici Wasm OOM。
- 微信官方 CLI 安装触发 undici Wasm OOM 时,自动改用 npm 直装到 OpenClaw `npm/projects` 并继续注册插件配置。
- 不再只用 npm 直装并写入已废弃的 `plugins.installs`,避免扫码成功后配置保存导致插件注册丢失。
- 微信插件安装/升级不再预先停止 Gateway,避免反复安装触发 procd crash-loop。
- LuCI 状态页和 `status_service` 增强 procd 状态识别,能区分真实启动中、stale pidfile 和 crash-loop 抑制,不再误显示“正在启动”。
- 微信登录前补充 Node、python3、插件目录、账号状态目录和配置写权限检查,并清理残留登录进程与旧二维码状态。
@@ -24,10 +40,14 @@
- 新增统一权限修复工具 `openclaw-permissions.sh`。
- 避免把整个 `OC_DATA` 或 `OC_STATE_DIR` 递归改成 `openclaw`。
- `npm/projects` 保持 `openclaw` 可写,插件源码目录保持 `root:root 755`,避免 `EACCES` 和 `suspicious ownership` 互相打架。
- retained npm generation 目录保持可清理,修复 Gateway 清理旧 generation 的权限报错。
- `npm/projects` 及插件源码保持 `openclaw` 可写,匹配官方 managed npm generation 生命周期。
- retained npm generation 目录保持可清理,修复 Gateway 清理旧 generation 时的 `EACCES`。
- legacy `extensions` / `archived-extensions` 保持 root-owned,降低 OpenClaw 插件安全检查误报风险。
### 更新一万AI分享粉丝专享 API
- `gpt-5.5` 默认上下文声明调整为 1,000,000 tokens,单次请求的实际可用上限仍以上游 API 为准。
### 修复检测升级
- “快捷操作 → 检测升级”改为语义版本比较,只在远端版本真正高于当前版本时提示升级。
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-openclaw
PKG_VERSION:=$(strip $(shell cat $(CURDIR)/VERSION 2>/dev/null || echo "1.0.0"))
PKG_RELEASE:=22
PKG_RELEASE:=23
PKG_MAINTAINER:=10000ge10000 <10000ge10000@users.noreply.github.com>
PKG_LICENSE:=GPL-3.0
+1 -1
View File
@@ -1 +1 @@
2.0.10
2.0.11
@@ -114,51 +114,13 @@ local function find_wechat_plugin_dir(install_path)
return nil
end
local function wechat_register_plugin_cmd(install_path, node_bin, log_file, exit_file)
local function wechat_enable_plugin_config_cmd(install_path, node_bin, log_file, exit_file)
exit_file = exit_file or "/tmp/openclaw-wechat-install.exit"
local oc_data = install_path .. "/data"
local config_file = oc_data .. "/.openclaw/openclaw.json"
local npm_projects = oc_data .. "/.openclaw/npm/projects"
local legacy_ext_dir = oc_data .. "/.openclaw/extensions/openclaw-weixin"
local register_js = [[
const fs = require('fs');
const path = require('path');
const configPath = process.env.OC_CONFIG;
const npmProjects = process.env.OC_NPM_PROJECTS;
const legacyDir = process.env.OC_LEGACY_WECHAT_DIR;
const candidates = [];
function addPluginDir(dir) {
if (!dir) return;
const pluginJson = path.join(dir, 'openclaw.plugin.json');
try {
const st = fs.statSync(pluginJson);
if (st.isFile()) candidates.push({ dir, mtime: st.mtimeMs });
} catch (e) {}
}
function walk(dir) {
let entries = [];
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch (e) {
return;
}
for (const entry of entries) {
if (!entry.isDirectory()) continue;
const full = path.join(dir, entry.name);
if (full.endsWith(path.join('node_modules', '@tencent-weixin', 'openclaw-weixin'))) {
addPluginDir(full);
continue;
}
walk(full);
}
}
addPluginDir(legacyDir);
walk(npmProjects);
candidates.sort((a, b) => b.mtime - a.mtime);
if (!candidates.length) {
console.error('openclaw-weixin plugin directory not found');
process.exit(2);
}
let d = {};
try {
d = JSON.parse(fs.readFileSync(configPath, 'utf8'));
@@ -166,13 +128,11 @@ try {
d = {};
}
if (!d.plugins || typeof d.plugins !== 'object') d.plugins = {};
if (!d.plugins.installs || typeof d.plugins.installs !== 'object') d.plugins.installs = {};
if (!Array.isArray(d.plugins.allow)) d.plugins.allow = [];
d.plugins.installs['openclaw-weixin'] = {
kind: 'npm',
installPath: candidates[0].dir,
packageName: '@tencent-weixin/openclaw-weixin'
};
// OpenClaw 2026.6.11 persists install records in its SQLite plugin index.
// Remove the deprecated authored config ledger so later config writes do not
// silently discard the only registration record again.
if (d.plugins.installs) delete d.plugins.installs['openclaw-weixin'];
if (!d.plugins.allow.includes('openclaw-weixin')) d.plugins.allow.push('openclaw-weixin');
if (!d.channels || typeof d.channels !== 'object') d.channels = {};
if (!d.channels['openclaw-weixin'] || typeof d.channels['openclaw-weixin'] !== 'object') {
@@ -185,16 +145,14 @@ fs.writeFileSync(configPath, JSON.stringify(d, null, 2) + '\n');
return "if [ $RC -eq 0 ]; then " ..
"if [ -x " .. shellquote(node_bin) .. " ]; then " ..
"OC_CONFIG=" .. shellquote(config_file) .. " " ..
"OC_NPM_PROJECTS=" .. shellquote(npm_projects) .. " " ..
"OC_LEGACY_WECHAT_DIR=" .. shellquote(legacy_ext_dir) .. " " ..
shellquote(node_bin) .. " -e " .. shellquote(register_js) .. " >> " .. shellquote(log_file) .. " 2>&1; " ..
"REG_RC=$?; " ..
"if [ $REG_RC -eq 0 ]; then " ..
"chown openclaw:openclaw " .. shellquote(config_file) .. " 2>/dev/null; " ..
"[ -x /usr/libexec/openclaw-permissions.sh ] && /usr/libexec/openclaw-permissions.sh fix-state " .. shellquote(oc_data .. "/.openclaw") .. " >/dev/null 2>&1; " ..
"echo 'Registered openclaw-weixin npm plugin in OpenClaw config.' >> " .. shellquote(log_file) .. "; " ..
"else RC=$REG_RC; echo $RC > " .. shellquote(exit_file) .. "; echo 'Failed to register openclaw-weixin npm plugin in OpenClaw config.' >> " .. shellquote(log_file) .. "; fi; " ..
"else RC=127; echo $RC > " .. shellquote(exit_file) .. "; echo 'Node.js not found, cannot register openclaw-weixin plugin.' >> " .. shellquote(log_file) .. "; fi; " ..
"echo 'Enabled openclaw-weixin channel in OpenClaw config.' >> " .. shellquote(log_file) .. "; " ..
"else RC=$REG_RC; echo $RC > " .. shellquote(exit_file) .. "; echo 'Failed to enable openclaw-weixin channel in OpenClaw config.' >> " .. shellquote(log_file) .. "; fi; " ..
"else RC=127; echo $RC > " .. shellquote(exit_file) .. "; echo 'Node.js not found, cannot enable openclaw-weixin channel.' >> " .. shellquote(log_file) .. "; fi; " ..
"fi; "
end
@@ -253,44 +211,49 @@ local function openclaw_user_runner_cmd()
"}; "
end
local function wechat_npm_fallback_install_cmd(install_path, log_file, exit_file)
local package_json = "{\n \"private\": true,\n \"dependencies\": {\n \"@tencent-weixin/openclaw-weixin\": \"latest\"\n }\n}\n"
return "if [ $RC -ne 0 ]; then " ..
"echo '⚠️ 官方微信 CLI 安装失败,尝试 npm 直装兜底...' >> " .. shellquote(log_file) .. "; " ..
"OC_WECHAT_NPM_PROJECT=\"$OC_WECHAT_DATA/.openclaw/npm/projects/tencent-weixin-openclaw-weixin-7783ac86ba\"; " ..
"mkdir -p \"$OC_WECHAT_NPM_PROJECT\" \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/npm/projects\"; " ..
"chown -R openclaw:openclaw \"$OC_WECHAT_NPM_PROJECT\" \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/npm/projects\" 2>/dev/null; " ..
"cat > \"$OC_WECHAT_NPM_PROJECT/package.json\" <<'OC_WECHAT_PACKAGE_JSON'\n" ..
package_json ..
"OC_WECHAT_PACKAGE_JSON\n" ..
"chown openclaw:openclaw \"$OC_WECHAT_NPM_PROJECT/package.json\" 2>/dev/null; " ..
"cd \"$OC_WECHAT_NPM_PROJECT\" && " ..
"_oc_as_openclaw 'HOME=$OC_WECHAT_DATA OPENCLAW_HOME=$OC_WECHAT_DATA OPENCLAW_STATE_DIR=$OC_WECHAT_DATA/.openclaw OPENCLAW_CONFIG_PATH=$OC_WECHAT_DATA/.openclaw/openclaw.json " ..
"NPM_CONFIG_CACHE=$OC_WECHAT_DATA/.npm npm_config_cache=$OC_WECHAT_DATA/.npm TMPDIR=$OC_WECHAT_DATA/.tmp " ..
"PATH=" .. install_path .. "/node/bin:" .. install_path .. "/global/bin:$PATH " ..
"npm install --omit=dev --omit=peer --legacy-peer-deps --no-audit --no-fund --loglevel=error' >> " .. shellquote(log_file) .. " 2>&1; " ..
"RC=$?; echo $RC > " .. shellquote(exit_file) .. "; " ..
"if [ $RC -eq 0 ]; then echo '✅ npm 直装兜底完成' >> " .. shellquote(log_file) .. "; else echo '❌ npm 直装兜底失败 (exit: '$RC')' >> " .. shellquote(log_file) .. "; fi; " ..
"fi; "
end
local function wechat_npm_direct_install_cmd(install_path, log_file, exit_file)
local package_json = "{\n \"private\": true,\n \"dependencies\": {\n \"@tencent-weixin/openclaw-weixin\": \"latest\"\n }\n}\n"
return "echo '使用 npm 直装微信插件,避免官方安装器进入扫码等待...' >> " .. shellquote(log_file) .. "; " ..
"OC_WECHAT_NPM_PROJECT=\"$OC_WECHAT_DATA/.openclaw/npm/projects/tencent-weixin-openclaw-weixin-7783ac86ba\"; " ..
"mkdir -p \"$OC_WECHAT_NPM_PROJECT\" \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/npm/projects\"; " ..
"chown -R openclaw:openclaw \"$OC_WECHAT_NPM_PROJECT\" \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/npm/projects\" 2>/dev/null; " ..
"cat > \"$OC_WECHAT_NPM_PROJECT/package.json\" <<'OC_WECHAT_PACKAGE_JSON'\n" ..
package_json ..
"OC_WECHAT_PACKAGE_JSON\n" ..
"chown openclaw:openclaw \"$OC_WECHAT_NPM_PROJECT/package.json\" 2>/dev/null; " ..
"cd \"$OC_WECHAT_NPM_PROJECT\" && " ..
local function wechat_openclaw_plugin_install_cmd(install_path, oc_entry, log_file, exit_file)
return "OC_WECHAT_NODE=" .. shellquote(install_path .. "/node/bin/node") .. "; " ..
"OC_WECHAT_ENTRY=" .. shellquote(oc_entry) .. "; export OC_WECHAT_NODE OC_WECHAT_ENTRY; " ..
"echo '使用 OpenClaw 官方插件安装器写入 SQLite 插件索引...' >> " .. shellquote(log_file) .. "; " ..
"_oc_as_openclaw 'HOME=$OC_WECHAT_DATA OPENCLAW_HOME=$OC_WECHAT_DATA OPENCLAW_STATE_DIR=$OC_WECHAT_DATA/.openclaw OPENCLAW_CONFIG_PATH=$OC_WECHAT_DATA/.openclaw/openclaw.json " ..
"NODE_ICU_DATA=" .. install_path .. "/node/share/icu NPM_CONFIG_CACHE=$OC_WECHAT_DATA/.npm npm_config_cache=$OC_WECHAT_DATA/.npm TMPDIR=$OC_WECHAT_DATA/.tmp " ..
"PATH=" .. install_path .. "/node/bin:" .. install_path .. "/global/bin:$PATH " ..
"npm install --omit=dev --omit=peer --legacy-peer-deps --no-audit --no-fund --loglevel=error' >> " .. shellquote(log_file) .. " 2>&1; " ..
"\"$OC_WECHAT_NODE\" \"$OC_WECHAT_ENTRY\" plugins install --force --pin @tencent-weixin/openclaw-weixin@2.4.6' >> " .. shellquote(log_file) .. " 2>&1; " ..
"RC=$?; echo $RC > " .. shellquote(exit_file) .. "; " ..
"if [ $RC -eq 0 ]; then echo '✅ npm 直装微信插件完成' >> " .. shellquote(log_file) .. "; else echo '❌ npm 直装微信插件失败 (exit: '$RC')' >> " .. shellquote(log_file) .. "; fi; "
"if [ $RC -eq 0 ]; then echo '✅ OpenClaw 插件索引注册完成' >> " .. shellquote(log_file) .. "; else echo '❌ OpenClaw 插件安装失败 (exit: '$RC')' >> " .. shellquote(log_file) .. "; fi; "
end
local function wechat_finalize_plugin_registry_cmd(install_path, oc_entry, log_file, exit_file)
exit_file = exit_file or "/tmp/openclaw-wechat-install.exit"
local oc_data = install_path .. "/data"
local node_bin = install_path .. "/node/bin/node"
local cli_env = "HOME=" .. oc_data .. " OPENCLAW_HOME=" .. oc_data ..
" OPENCLAW_STATE_DIR=" .. oc_data .. "/.openclaw" ..
" OPENCLAW_CONFIG_PATH=" .. oc_data .. "/.openclaw/openclaw.json" ..
" NODE_ICU_DATA=" .. install_path .. "/node/share/icu" ..
" NPM_CONFIG_CACHE=" .. oc_data .. "/.npm TMPDIR=" .. oc_data .. "/.tmp" ..
" PATH=" .. install_path .. "/node/bin:" .. install_path .. "/global/bin:$PATH "
local cli = cli_env .. node_bin .. " " .. oc_entry
return "if [ $RC -eq 0 ]; then " ..
"echo '正在写入微信插件启用状态...' >> " .. shellquote(log_file) .. "; " ..
"_oc_as_openclaw '" .. cli .. " plugins enable openclaw-weixin' >> " .. shellquote(log_file) .. " 2>&1; " ..
"FINAL_RC=$?; " ..
"if [ $FINAL_RC -eq 0 ]; then " ..
"echo '正在刷新 SQLite 插件注册表...' >> " .. shellquote(log_file) .. "; " ..
"_oc_as_openclaw '" .. cli .. " plugins registry --refresh' >> " .. shellquote(log_file) .. " 2>&1; " ..
"FINAL_RC=$?; fi; " ..
"if [ $FINAL_RC -eq 0 ]; then " ..
"_OC_WECHAT_INSPECT=/tmp/openclaw-wechat-inspect-$$.log; " ..
"_oc_as_openclaw '" .. cli .. " plugins inspect openclaw-weixin' > \"$_OC_WECHAT_INSPECT\" 2>&1; " ..
"VERIFY_RC=$?; cat \"$_OC_WECHAT_INSPECT\" >> " .. shellquote(log_file) .. "; " ..
"if [ $VERIFY_RC -ne 0 ] || ! grep -q '^Status: loaded$' \"$_OC_WECHAT_INSPECT\" || ! grep -q '^channel: openclaw-weixin$' \"$_OC_WECHAT_INSPECT\"; then FINAL_RC=1; fi; " ..
"rm -f \"$_OC_WECHAT_INSPECT\"; fi; " ..
"if [ $FINAL_RC -eq 0 ]; then " ..
"echo '✅ 微信插件已启用,SQLite 注册表已刷新并通过加载验证' >> " .. shellquote(log_file) .. "; " ..
"else RC=$FINAL_RC; echo $RC > " .. shellquote(exit_file) .. "; " ..
"echo '❌ 微信插件启用或注册表验证失败' >> " .. shellquote(log_file) .. "; fi; " ..
"fi; "
end
local function wechat_tail_detail(text, max_lines)
@@ -1556,16 +1519,29 @@ function action_wechat_install()
local node_bin = install_path .. "/node/bin/node"
local npx_bin = install_path .. "/node/bin/npx"
local oc_data = install_path .. "/data"
local oc_entry = ""
for _, d in ipairs({
install_path .. "/global/lib/node_modules/openclaw",
install_path .. "/global/node_modules/openclaw",
install_path .. "/node/lib/node_modules/openclaw",
}) do
if nixio.fs.stat(d .. "/openclaw.mjs", "type") then
oc_entry = d .. "/openclaw.mjs"
break
elseif nixio.fs.stat(d .. "/dist/cli.js", "type") then
oc_entry = d .. "/dist/cli.js"
break
end
end
-- 清理旧日志和状态
sys.exec("rm -f /tmp/openclaw-wechat-install.log /tmp/openclaw-wechat-install.pid /tmp/openclaw-wechat-install.exit")
-- 校验: 确保 npx 存在 (运行环境已安装)
if not nixio.fs.stat(npx_bin, "type") then
-- npx 不存在,运行环境未安装或路径配置错误
-- 官方插件安装器必须通过当前 OpenClaw CLI 写入 SQLite 安装索引。
if not nixio.fs.stat(node_bin, "type") or oc_entry == "" then
local log_content = "开始安装微信插件...\n" ..
"安装路径: " .. install_path .. "\n" ..
"❌ 错误: npx 命令不存在 (" .. npx_bin .. ")\n" ..
"❌ 错误: Node.js 或 OpenClaw CLI 不存在。\n" ..
"请先在「基本设置」页面安装运行环境。\n" ..
"UCI install_path=" .. (uci:get("openclaw", "main", "install_path") or "未设置")
local f = io.open("/tmp/openclaw-wechat-install.log", "w")
@@ -1611,11 +1587,12 @@ function action_wechat_install()
"else mkdir -p \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/extensions\"; chown -R openclaw:openclaw \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" 2>/dev/null; chown openclaw:openclaw \"$OC_WECHAT_DATA/.openclaw\" 2>/dev/null; fi; " ..
"if [ ! -w %s/.npm ] || [ ! -w %s/.tmp ]; then echo '❌ npm cache/tmp 目录不可写' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; fi; " ..
"_oc_as_openclaw 'test -w %s/.npm && test -w %s/.tmp && test -w %s/.openclaw' || { echo '❌ openclaw 用户无法写入 npm cache/tmp/data 目录' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; }; " ..
wechat_npm_direct_install_cmd(install_path, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
wechat_register_plugin_cmd(install_path, node_bin, "/tmp/openclaw-wechat-install.log") ..
wechat_openclaw_plugin_install_cmd(install_path, oc_entry, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
wechat_enable_plugin_config_cmd(install_path, node_bin, "/tmp/openclaw-wechat-install.log") ..
wechat_finalize_plugin_registry_cmd(install_path, oc_entry, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
-- 关键修复: 安装完成后强制修复插件目录权限 (确保 Gateway 可读取插件)
-- 原因: npx/npm 以 root 身份创建目录,默认权限 700 导致其他用户无法读取
-- 注意: 保持 root:root 属主 (OpenClaw v2026.4.9+ 安全要求),仅修复权限模式
-- 官方 npm generation 由 openclaw 用户维护,必须允许后续升级清理。
"[ -x /usr/libexec/openclaw-permissions.sh ] && /usr/libexec/openclaw-permissions.sh fix-state %s/.openclaw >/dev/null 2>&1; " ..
"if [ $RC -eq 0 ]; then echo '✅ 微信插件安装成功!' >> /tmp/openclaw-wechat-install.log; " ..
"else echo '❌ 安装失败 (exit: '$RC')' >> /tmp/openclaw-wechat-install.log; fi " ..
@@ -1761,7 +1738,8 @@ function action_wechat_login()
"chown openclaw:openclaw %s/.openclaw %s/.openclaw/openclaw.json 2>/dev/null; " ..
"_oc_as_openclaw 'test -w %s/.npm && test -w %s/.tmp && test -w %s/.openclaw && test -w %s/.openclaw/openclaw-weixin && test -w %s/.openclaw/openclaw.json' || { echo '❌ openclaw 用户无法写入微信登录目录,请检查数据目录权限' >> /tmp/openclaw-wechat-qrcode.txt; echo 1 > /tmp/openclaw-wechat-login.exit; exit 0; }; " ..
"RC=0; " ..
wechat_register_plugin_cmd(install_path, node_bin, "/tmp/openclaw-wechat-qrcode.txt", "/tmp/openclaw-wechat-login.exit") ..
wechat_enable_plugin_config_cmd(install_path, node_bin, "/tmp/openclaw-wechat-qrcode.txt", "/tmp/openclaw-wechat-login.exit") ..
wechat_finalize_plugin_registry_cmd(install_path, oc_entry, "/tmp/openclaw-wechat-qrcode.txt", "/tmp/openclaw-wechat-login.exit") ..
"if [ $RC -ne 0 ]; then echo '❌ 微信插件注册失败,无法登录' >> /tmp/openclaw-wechat-qrcode.txt; exit 0; fi; " ..
"cd %s && " ..
"_oc_as_openclaw 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json " ..
@@ -2026,15 +2004,29 @@ function action_wechat_upgrade_plugin()
local node_bin = install_path .. "/node/bin/node"
local npx_bin = install_path .. "/node/bin/npx"
local oc_data = install_path .. "/data"
local oc_entry = ""
for _, d in ipairs({
install_path .. "/global/lib/node_modules/openclaw",
install_path .. "/global/node_modules/openclaw",
install_path .. "/node/lib/node_modules/openclaw",
}) do
if nixio.fs.stat(d .. "/openclaw.mjs", "type") then
oc_entry = d .. "/openclaw.mjs"
break
elseif nixio.fs.stat(d .. "/dist/cli.js", "type") then
oc_entry = d .. "/dist/cli.js"
break
end
end
-- 清理旧日志和状态
sys.exec("rm -f /tmp/openclaw-wechat-install.log /tmp/openclaw-wechat-install.pid /tmp/openclaw-wechat-install.exit")
-- 校验: 确保 npx 存在 (运行环境已安装)
if not nixio.fs.stat(npx_bin, "type") then
-- 升级也必须由官方 CLI 更新 SQLite 插件索引。
if not nixio.fs.stat(node_bin, "type") or oc_entry == "" then
local log_content = "正在升级微信插件...\n" ..
"安装路径: " .. install_path .. "\n" ..
"❌ 错误: npx 命令不存在 (" .. npx_bin .. ")\n" ..
"❌ 错误: Node.js 或 OpenClaw CLI 不存在。\n" ..
"请先检查运行环境是否正常安装。\n" ..
"UCI install_path=" .. (uci:get("openclaw", "main", "install_path") or "未设置")
local f = io.open("/tmp/openclaw-wechat-install.log", "w")
@@ -2080,10 +2072,11 @@ function action_wechat_upgrade_plugin()
"else mkdir -p \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" \"$OC_WECHAT_DATA/.openclaw/extensions\"; chown -R openclaw:openclaw \"$OC_WECHAT_DATA/.npm\" \"$OC_WECHAT_DATA/.tmp\" 2>/dev/null; chown openclaw:openclaw \"$OC_WECHAT_DATA/.openclaw\" 2>/dev/null; fi; " ..
"if [ ! -w %s/.npm ] || [ ! -w %s/.tmp ]; then echo '❌ npm cache/tmp 目录不可写' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; fi; " ..
"_oc_as_openclaw 'test -w %s/.npm && test -w %s/.tmp && test -w %s/.openclaw' || { echo '❌ openclaw 用户无法写入 npm cache/tmp/data 目录' >> /tmp/openclaw-wechat-install.log; echo 1 > /tmp/openclaw-wechat-install.exit; exit 0; }; " ..
wechat_npm_direct_install_cmd(install_path, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
wechat_register_plugin_cmd(install_path, node_bin, "/tmp/openclaw-wechat-install.log") ..
wechat_openclaw_plugin_install_cmd(install_path, oc_entry, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
wechat_enable_plugin_config_cmd(install_path, node_bin, "/tmp/openclaw-wechat-install.log") ..
wechat_finalize_plugin_registry_cmd(install_path, oc_entry, "/tmp/openclaw-wechat-install.log", "/tmp/openclaw-wechat-install.exit") ..
-- 关键修复: 升级完成后强制修复插件目录权限 (确保 Gateway 可读取插件)
-- 注意: 保持 root:root 属主 (OpenClaw v2026.4.9+ 安全要求),仅修复权限模式
-- 官方 npm generation 由 openclaw 用户维护,必须允许后续升级清理。
"[ -x /usr/libexec/openclaw-permissions.sh ] && /usr/libexec/openclaw-permissions.sh fix-state %s/.openclaw >/dev/null 2>&1; " ..
"if [ $RC -eq 0 ]; then echo '✅ 微信插件升级成功!' >> /tmp/openclaw-wechat-install.log; " ..
"else echo '❌ 升级失败 (exit: '$RC')' >> /tmp/openclaw-wechat-install.log; fi " ..
+91 -20
View File
@@ -61,6 +61,29 @@ _oc_fix_opt
NODE_BIN="${NODE_BASE}/bin/node"
CONFIG_FILE="${OC_DATA}/.openclaw/openclaw.json"
run_openclaw_cli_as_user() {
local oc_entry="$1"
shift
local pid_file="/tmp/openclaw-cli-$$.pid"
local rc
[ -x "$NODE_BIN" ] || return 127
id -u openclaw >/dev/null 2>&1 || return 127
rm -f "$pid_file"
ulimit -v unlimited 2>/dev/null || true
ulimit -m unlimited 2>/dev/null || true
ulimit -d unlimited 2>/dev/null || true
HOME="$OC_DATA" OPENCLAW_HOME="$OC_DATA" OPENCLAW_STATE_DIR="${OC_DATA}/.openclaw" \
OPENCLAW_CONFIG_PATH="$CONFIG_FILE" NODE_ICU_DATA="${NODE_BASE}/share/icu" \
NPM_CONFIG_CACHE="${OC_DATA}/.npm" npm_config_cache="${OC_DATA}/.npm" TMPDIR="${OC_DATA}/.tmp" \
PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:$PATH" \
start-stop-daemon -S -m -p "$pid_file" -c openclaw:openclaw -d "$OC_INSTALL_PATH" \
-x "$NODE_BIN" -- "$oc_entry" "$@"
rc=$?
rm -f "$pid_file"
return "$rc"
}
get_oc_entry() {
local search_dirs="${OC_GLOBAL}/lib/node_modules/openclaw
${OC_GLOBAL}/node_modules/openclaw
@@ -333,9 +356,6 @@ if(Array.isArray(d.plugins.allow)){
delete d.plugins[ns].weixin;
}
});
if(d.plugins.entries&&d.plugins.entries['openclaw-weixin']){
delete d.plugins.entries['openclaw-weixin'];
}
['channel','channels'].forEach(ns=>{
if(d[ns]&&d[ns].weixin){
if(!d[ns]['openclaw-weixin'])d[ns]['openclaw-weixin']=d[ns].weixin;
@@ -392,34 +412,67 @@ fi
# 同步 UCI 到 JSON
sync_uci_to_json
# 微信 npm 插件自愈注册:
# 有些环境里 npm projects 已安装 @tencent-weixin/openclaw-weixin,
# 但 openclaw.json 缺少 plugins.installs / plugins.allow / channels 配置,
# 会导致页面显示“已安装”而 Gateway 或登录流程无法稳定加载插件。
# 微信 npm 插件自愈注册:OpenClaw 2026.6.11 已把安装记录从
# openclaw.json 的 plugins.installs 迁移到 SQLite installed_plugin_index。
# 所有官方 CLI 和 SQLite 注册表操作都以 openclaw 用户执行;完成配置写入后
# 强制 refresh 并检查 channel capability,避免重启后只加载 memory-core。
self_heal_wechat_npm_plugin_config() {
[ -x "$NODE_BIN" ] || return 0
[ -f "$CONFIG_FILE" ] || return 0
local npm_projects_dir="${OC_DATA}/.openclaw/npm/projects"
[ -d "$npm_projects_dir" ] || return 0
local wechat_plugin_json wechat_plugin_dir heal_out
local wechat_plugin_json heal_out index_ok inspect_ok config_ok inspect_file
wechat_plugin_json=$(find "$npm_projects_dir" -path "*/node_modules/@tencent-weixin/openclaw-weixin/openclaw.plugin.json" -type f 2>/dev/null | head -n 1)
[ -n "$wechat_plugin_json" ] || return 0
wechat_plugin_dir="${wechat_plugin_json%/openclaw.plugin.json}"
heal_out=$(OC_CONFIG="$CONFIG_FILE" OC_WECHAT_PLUGIN_DIR="$wechat_plugin_dir" "$NODE_BIN" -e "
inspect_file="/tmp/openclaw-wechat-self-heal.inspect"
rm -f "$inspect_file"
: > /tmp/openclaw-wechat-self-heal.log
index_ok=0
inspect_ok=0
config_ok=0
if run_openclaw_cli_as_user "$oc_entry" plugins inspect openclaw-weixin >"$inspect_file" 2>&1; then
grep -q '^Install:$' "$inspect_file" && grep -q '^Source: npm$' "$inspect_file" && index_ok=1
grep -q '^Status: loaded$' "$inspect_file" && grep -q '^channel: openclaw-weixin$' "$inspect_file" && inspect_ok=1
fi
OC_CONFIG="$CONFIG_FILE" "$NODE_BIN" -e "
try {
const d=JSON.parse(require('fs').readFileSync(process.env.OC_CONFIG,'utf8'));
const ok=d.plugins&&Array.isArray(d.plugins.allow)&&d.plugins.allow.includes('openclaw-weixin')&&
d.plugins.entries&&d.plugins.entries['openclaw-weixin']&&d.plugins.entries['openclaw-weixin'].enabled===true&&
d.channels&&d.channels['openclaw-weixin']&&d.channels['openclaw-weixin'].enabled===true&&
!(d.plugins.installs&&d.plugins.installs['openclaw-weixin']);
process.exit(ok?0:1);
} catch(e) { process.exit(1); }
" >/dev/null 2>&1 && config_ok=1
if [ "$index_ok" = "1" ] && [ "$inspect_ok" = "1" ] && [ "$config_ok" = "1" ]; then
cat "$inspect_file" >> /tmp/openclaw-wechat-self-heal.log
logger -t openclaw "微信插件注册状态已有效,跳过重复刷新"
rm -f "$inspect_file"
return 0
fi
if [ "$index_ok" != "1" ]; then
logger -t openclaw "检测到旧微信直装目录,正在迁移到 SQLite 插件索引"
mkdir -p "${OC_DATA}/.npm" "${OC_DATA}/.tmp" 2>/dev/null || true
if run_openclaw_cli_as_user "$oc_entry" plugins install --force --pin '@tencent-weixin/openclaw-weixin@2.4.6' \
>>/tmp/openclaw-wechat-self-heal.log 2>&1; then
logger -t openclaw "微信插件已迁移到 SQLite installed_plugin_index"
else
logger -t openclaw "微信插件 SQLite 索引迁移失败,请查看 /tmp/openclaw-wechat-self-heal.log"
rm -f "$inspect_file"
return 0
fi
fi
heal_out=$(OC_CONFIG="$CONFIG_FILE" "$NODE_BIN" -e "
const fs=require('fs');
const p=process.env.OC_CONFIG;
const pluginDir=process.env.OC_WECHAT_PLUGIN_DIR;
let d={};
try{d=JSON.parse(fs.readFileSync(p,'utf8'));}catch(e){}
if(!d.plugins||typeof d.plugins!=='object')d.plugins={};
if(!d.plugins.installs||typeof d.plugins.installs!=='object')d.plugins.installs={};
if(!Array.isArray(d.plugins.allow))d.plugins.allow=[];
if(!d.channels||typeof d.channels!=='object')d.channels={};
let changed=false;
const want={kind:'npm',installPath:pluginDir,packageName:'@tencent-weixin/openclaw-weixin'};
const cur=d.plugins.installs['openclaw-weixin'];
if(!cur||cur.kind!==want.kind||cur.installPath!==want.installPath||cur.packageName!==want.packageName){
d.plugins.installs['openclaw-weixin']=want; changed=true;
if(d.plugins.installs&&d.plugins.installs['openclaw-weixin']){
delete d.plugins.installs['openclaw-weixin']; changed=true;
}
if(!d.plugins.allow.includes('openclaw-weixin')){
d.plugins.allow.push('openclaw-weixin'); changed=true;
@@ -430,9 +483,6 @@ if(!d.channels['openclaw-weixin']||typeof d.channels['openclaw-weixin']!=='objec
if(d.channels['openclaw-weixin'].enabled!==true){
d.channels['openclaw-weixin'].enabled=true; changed=true;
}
if(d.plugins.entries&&d.plugins.entries['openclaw-weixin']){
delete d.plugins.entries['openclaw-weixin']; changed=true;
}
if(changed){
fs.writeFileSync(p,JSON.stringify(d,null,2)+'\n');
console.log('FIXED');
@@ -440,8 +490,29 @@ if(changed){
" 2>/dev/null)
if echo "$heal_out" | grep -q "FIXED"; then
chown openclaw:openclaw "$CONFIG_FILE" 2>/dev/null || true
logger -t openclaw "已自愈注册 openclaw-weixin npm plugin: $wechat_plugin_dir"
logger -t openclaw "已自愈启用 openclaw-weixin channel"
fi
if ! run_openclaw_cli_as_user "$oc_entry" plugins enable openclaw-weixin \
>>/tmp/openclaw-wechat-self-heal.log 2>&1; then
logger -t openclaw "微信插件启用失败,请查看 /tmp/openclaw-wechat-self-heal.log"
rm -f "$inspect_file"
return 0
fi
if ! run_openclaw_cli_as_user "$oc_entry" plugins registry --refresh \
>>/tmp/openclaw-wechat-self-heal.log 2>&1; then
logger -t openclaw "微信插件注册表刷新失败,请查看 /tmp/openclaw-wechat-self-heal.log"
rm -f "$inspect_file"
return 0
fi
if run_openclaw_cli_as_user "$oc_entry" plugins inspect openclaw-weixin >"$inspect_file" 2>&1 && \
grep -q '^Status: loaded$' "$inspect_file" && grep -q '^channel: openclaw-weixin$' "$inspect_file"; then
cat "$inspect_file" >> /tmp/openclaw-wechat-self-heal.log
logger -t openclaw "微信插件 SQLite 注册表已刷新并通过加载验证"
else
cat "$inspect_file" >> /tmp/openclaw-wechat-self-heal.log 2>/dev/null || true
logger -t openclaw "微信插件加载验证失败,请查看 /tmp/openclaw-wechat-self-heal.log"
fi
rm -f "$inspect_file"
}
self_heal_wechat_npm_plugin_config
@@ -1,7 +1,8 @@
#!/bin/sh
# OpenClaw state permission helper.
# Keep runtime state writable by the openclaw user, while keeping plugin source
# directories root-owned for OpenClaw's official ownership checks.
# Keep runtime state and managed npm plugin generations writable by the
# openclaw user. OpenClaw 2026.6.11 installs and retires these generations
# itself, so root-owned files under npm/projects break later cleanup.
oc_perm_state_dir() {
if [ -n "${1:-}" ]; then
@@ -24,33 +25,16 @@ oc_perm_data_dir_from_state() {
}
oc_fix_npm_projects_permissions() {
local state_dir npm_projects plugin_json plugin_dir
local state_dir npm_projects
state_dir="$(oc_perm_state_dir "${1:-}")"
npm_projects="${state_dir}/npm/projects"
[ -d "$npm_projects" ] || return 0
# Gateway must be able to clean npm project generations.
# The official plugin installer runs as openclaw and the Gateway removes
# retired generations asynchronously. Keep the complete tree writable by
# that user, including plugin source files.
chown -R openclaw:openclaw "$npm_projects" 2>/dev/null || true
chmod u+rwx,go+rx "$npm_projects" 2>/dev/null || true
# Actual OpenClaw plugin roots must stay root-owned, otherwise OpenClaw refuses
# to load them with "suspicious ownership".
find "$npm_projects" -name openclaw.plugin.json -type f 2>/dev/null | while IFS= read -r plugin_json; do
plugin_dir="${plugin_json%/openclaw.plugin.json}"
case "$plugin_dir" in
*__openclaw-generation__*)
# Retained generation dirs are temporary and must remain removable by openclaw.
;;
"$npm_projects"/*/node_modules/*)
chown -R root:root "$plugin_dir" 2>/dev/null || true
chmod -R 755 "$plugin_dir" 2>/dev/null || true
;;
esac
done
# Compatibility for the WeChat plugin path even if its manifest scan fails.
find "$npm_projects" -path '*/node_modules/@tencent-weixin/openclaw-weixin' -type d -prune \
-exec chown -R root:root {} \; -exec chmod -R 755 {} \; 2>/dev/null || true
chmod -R u+rwX,go+rX "$npm_projects" 2>/dev/null || true
}
oc_fix_state_permissions() {
@@ -106,8 +90,7 @@ oc_prepare_openclaw_workdirs() {
chown openclaw:openclaw "$data_dir" "$state_dir" "${state_dir}/npm" "$npm_dir" 2>/dev/null || true
chmod u+rwx,go+rx "${data_dir}/.npm" "${data_dir}/.tmp" "$state_dir" "${state_dir}/npm" "$npm_dir" 2>/dev/null || true
# During install/upgrade, allow openclaw to update npm generations. Call
# fix-state after the install to restore plugin roots to root:root.
# During install/upgrade, allow openclaw to update npm generations.
[ -d "$npm_dir" ] && chown -R openclaw:openclaw "$npm_dir" 2>/dev/null || true
}
@@ -1277,7 +1277,7 @@ async function configureYiwanAIFanAPI() {
if (!apiKey) { console.log(`${C.yellow}已取消${C.reset}`); return false; }
authSetApikey(providerName, apiKey, `${providerName}:fan`);
registerCustomProvider(providerName, baseUrl, apiKey, modelName, modelName);
registerCustomProvider(providerName, baseUrl, apiKey, modelName, modelName, 1000000, 32000);
const config = readConfig();
const provider = config.models?.providers?.[providerName];
if (provider?.models?.[0]) {
@@ -1448,7 +1448,7 @@ configure_model() {
prompt_with_default "API Key" "" api_key
if [ -n "$api_key" ]; then
auth_set_apikey yiwanai "$api_key" "yiwanai:fan"
register_custom_provider yiwanai "https://api.910501.xyz/v1" "$api_key" "gpt-5.5" "gpt-5.5"
register_custom_provider yiwanai "https://api.910501.xyz/v1" "$api_key" "gpt-5.5" "gpt-5.5" 1000000 32000
_YW_PROV="yiwanai" "$NODE_BIN" -e "
const fs=require('fs');
let d={};
+3 -3
View File
@@ -189,9 +189,9 @@ cat > "$CTRL_DIR/postinst" << 'EOF'
[ -e "$p" ] && chown -R root:root "$p" 2>/dev/null || true
done
# 升级/重装后修复已存在的 OpenClaw 运行数据权限。尤其是 npm 外部插件:
# npm 安装阶段需要 openclaw 可写,运行阶段插件源码目录必须 root:root,
# 否则 OpenClaw 会因为 suspicious ownership 拒绝加载微信插件。
# 升级/重装后修复已存在的 OpenClaw 运行数据权限。OpenClaw 2026.6.11
# 会以 openclaw 用户安装和清理 managed npm generations,因此 npm/projects
# 内的插件源码也必须保持 openclaw 可写。
OPENCLAW_INSTALL_BASE="$(uci -q get openclaw.main.install_path 2>/dev/null || echo /opt)"
if [ -r /usr/libexec/openclaw-paths.sh ]; then
. /usr/libexec/openclaw-paths.sh
@@ -51,16 +51,22 @@ grep -q "openclaw 用户无法写入微信登录目录" luasrc/controller/opencl
grep -q "node_modules/@tencent-weixin/openclaw-weixin" luasrc/controller/openclaw.lua || fail "wechat uninstall must remove npm project plugin"
grep -q "dropChannel(d.plugins.installs)" luasrc/controller/openclaw.lua || fail "wechat uninstall must clean plugin installs"
grep -q "openclaw-weixin" root/etc/init.d/openclaw || fail "weixin channel migration missing"
grep -q "delete d.plugins.entries\\['openclaw-weixin'\\]" root/etc/init.d/openclaw || fail "weixin duplicate entries cleanup missing"
if grep -q "delete d.plugins.entries\\['openclaw-weixin'\\]" root/etc/init.d/openclaw; then
fail "init must preserve the official plugins.entries enable record"
fi
grep -q "npm/projects" root/etc/init.d/openclaw || fail "npm plugin project ownership fix missing"
grep -q "! -path.*npm/projects" root/usr/libexec/openclaw-permissions.sh || fail "npm plugin projects should be excluded from generic ownership reset"
grep -q "archived-extensions" root/etc/init.d/openclaw || fail "legacy weixin extension archive missing"
grep -q "find_wechat_plugin_dir" luasrc/controller/openclaw.lua || fail "wechat npm plugin detection missing"
grep -q "wechat_register_plugin_cmd" luasrc/controller/openclaw.lua || fail "wechat install must register npm plugin config"
grep -q "plugins.installs\\['openclaw-weixin'\\]" luasrc/controller/openclaw.lua || fail "wechat plugin installPath registration missing"
grep -q "packageName: '@tencent-weixin/openclaw-weixin'" luasrc/controller/openclaw.lua || fail "wechat plugin packageName registration missing"
grep -q "wechat_openclaw_plugin_install_cmd" luasrc/controller/openclaw.lua || fail "wechat install must use OpenClaw plugin installer"
grep -q "delete d.plugins.installs\\['openclaw-weixin'\\]" luasrc/controller/openclaw.lua || fail "wechat config must remove deprecated authored install records"
grep -q "plugins install --force --pin @tencent-weixin/openclaw-weixin@2.4.6" luasrc/controller/openclaw.lua || fail "wechat install must write the official plugin index"
grep -q "channels\\['openclaw-weixin'\\].enabled = true" luasrc/controller/openclaw.lua || fail "wechat channel enable registration missing"
grep -q "Registered openclaw-weixin npm plugin" luasrc/controller/openclaw.lua || fail "wechat install log must confirm config registration"
grep -q "OpenClaw 插件索引注册完成" luasrc/controller/openclaw.lua || fail "wechat install log must confirm index registration"
grep -q "plugins enable openclaw-weixin" luasrc/controller/openclaw.lua || fail "wechat lifecycle must persist the official plugin enable entry"
grep -q "plugins registry --refresh" luasrc/controller/openclaw.lua || fail "wechat lifecycle must refresh the SQLite plugin registry after config changes"
grep -q "plugins inspect openclaw-weixin" luasrc/controller/openclaw.lua || fail "wechat lifecycle must verify the loaded plugin capability"
grep -q "SQLite 注册表已刷新并通过加载验证" luasrc/controller/openclaw.lua || fail "wechat success log must require registry verification"
grep -q "wechat_network_probe_cmd" luasrc/controller/openclaw.lua || fail "wechat network probe helper missing"
grep -q "NODE_ICU_DATA=%s/node/share/icu" luasrc/controller/openclaw.lua || fail "wechat LuCI CLI commands must export NODE_ICU_DATA"
grep -q "openclaw_user_runner_cmd" luasrc/controller/openclaw.lua || fail "wechat commands need user runner compatibility helper"
@@ -68,16 +74,13 @@ grep -q "ulimit -v unlimited" luasrc/controller/openclaw.lua || fail "wechat com
grep -q "start-stop-daemon -S -m -p" luasrc/controller/openclaw.lua || fail "wechat commands must support OpenWrt without su"
grep -q "command -v curl" luasrc/controller/openclaw.lua || fail "wechat network probe should prefer curl"
grep -q "%%{http_code}" luasrc/controller/openclaw.lua || fail "wechat curl probe percent must be escaped for string.format"
grep -q "wechat_npm_fallback_install_cmd" luasrc/controller/openclaw.lua || fail "wechat install needs npm fallback for OpenWrt Node undici OOM"
if awk '/function action_wechat_install\(\)/,/function action_wechat_install_log\(\)/' luasrc/controller/openclaw.lua | grep -q "ensure_port_free"; then
fail "wechat install must not stop gateway before plugin installation"
fi
if awk '/function action_wechat_upgrade_plugin\(\)/,/function action_wechat_uninstall_plugin\(\)/' luasrc/controller/openclaw.lua | grep -q "ensure_port_free"; then
fail "wechat upgrade must not stop gateway before plugin upgrade"
fi
grep -q "npm install --omit=dev --omit=peer" luasrc/controller/openclaw.lua || fail "wechat npm fallback install command missing"
grep -q "tencent-weixin-openclaw-weixin-7783ac86ba" luasrc/controller/openclaw.lua || fail "wechat npm fallback project dir missing"
grep -q "export OC_WECHAT_DATA" luasrc/controller/openclaw.lua || fail "wechat npm fallback must export data dir into openclaw user shell"
grep -q "export OC_WECHAT_DATA" luasrc/controller/openclaw.lua || fail "wechat installer must export data dir into openclaw user shell"
grep -q "compare_versions" luasrc/controller/openclaw.lua || fail "semantic version compare helper missing"
grep -q "is_newer_version(plugin_latest, plugin_current)" luasrc/controller/openclaw.lua || fail "plugin update check must not treat newer local versions as upgradeable"
grep -q "is_newer_version(latest_version, current_version)" luasrc/controller/openclaw.lua || fail "wechat update check must use semantic version compare"
@@ -88,8 +91,18 @@ grep -q "已将此 OpenClaw 连接到微信" luasrc/controller/openclaw.lua || f
grep -q "Local login saved auth for openclaw%-weixin" luasrc/controller/openclaw.lua || fail "wechat login status must tolerate channels.start restart warning"
grep -q "/etc/init.d/openclaw restart_gateway >/dev/null 2>&1 &" luasrc/controller/openclaw.lua || fail "wechat login success should use lightweight gateway restart"
grep -q "self_heal_wechat_npm_plugin_config" root/etc/init.d/openclaw || fail "init.d wechat npm plugin self-heal missing"
grep -q "已自愈注册 openclaw-weixin npm plugin" root/etc/init.d/openclaw || fail "init.d wechat self-heal log missing"
grep -q "OC_WECHAT_PLUGIN_DIR" root/etc/init.d/openclaw || fail "init.d wechat self-heal plugin dir env missing"
grep -q "installed_plugin_index" root/etc/init.d/openclaw || fail "init.d wechat self-heal must support the SQLite plugin index"
grep -q "微信插件已迁移到 SQLite installed_plugin_index" root/etc/init.d/openclaw || fail "init.d wechat SQLite self-heal log missing"
grep -q "run_openclaw_cli_as_user" root/etc/init.d/openclaw || fail "init.d plugin registry operations must run as openclaw"
if grep -q "DatabaseSync" root/etc/init.d/openclaw; then
fail "init.d must not access the SQLite plugin index as root"
fi
grep -q "plugins enable openclaw-weixin" root/etc/init.d/openclaw || fail "init.d must restore the official plugin enable entry"
grep -q "plugins registry --refresh" root/etc/init.d/openclaw || fail "init.d must refresh the plugin registry before gateway start"
grep -q "plugins inspect openclaw-weixin" root/etc/init.d/openclaw || fail "init.d must verify the wechat plugin before gateway start"
grep -q "微信插件 SQLite 注册表已刷新并通过加载验证" root/etc/init.d/openclaw || fail "init.d registry verification success log missing"
grep -q "微信插件注册状态已有效,跳过重复刷新" root/etc/init.d/openclaw || fail "init.d must avoid repeated registry rebuilds after successful repair"
grep -q "d.plugins.entries\['openclaw-weixin'\].enabled===true" root/etc/init.d/openclaw || fail "init.d fast path must require the official enable entry"
grep -q "openclaw-permissions.sh" root/etc/init.d/openclaw || fail "init.d must use permission helper"
grep -q "fix_openclaw_state_permissions" root/etc/init.d/openclaw || fail "init.d final permission helper call missing"
grep -q 'NODE_ICU_DATA="${NODE_BASE}/share/icu" PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:$PATH"' root/etc/init.d/openclaw || fail "doctor migration must run with Node ICU data"
@@ -111,11 +124,10 @@ grep -q 'NODE_COMPILE_CACHE="$node_compile_cache"' root/etc/init.d/openclaw || f
grep -q "通常 20~40 秒" root/etc/init.d/openclaw luasrc/view/openclaw/status.htm luasrc/view/openclaw/console.htm || fail "startup hint must match measured OpenWrt timing"
grep -q "restart_gateway >/dev/null 2>&1 &" luasrc/controller/openclaw.lua || fail "LuCI restart action should use lightweight gateway restart"
grep -q "oc_fix_npm_projects_permissions" root/usr/libexec/openclaw-permissions.sh || fail "npm projects permission helper missing"
grep -q "openclaw.plugin.json" root/usr/libexec/openclaw-permissions.sh || fail "npm plugin root detection must use plugin manifest"
grep -q "node_modules/@tencent-weixin/openclaw-weixin" root/usr/libexec/openclaw-permissions.sh || fail "wechat npm plugin compatibility permission fix missing"
grep -q "__openclaw-generation__" root/usr/libexec/openclaw-permissions.sh || fail "retained npm generations must remain removable by openclaw"
grep -q 'chown -R root:root "$plugin_dir"' root/usr/libexec/openclaw-permissions.sh || fail "npm plugin roots must keep root ownership"
grep -q 'chown -R openclaw:openclaw "$npm_projects"' root/usr/libexec/openclaw-permissions.sh || fail "npm projects generation must be writable by openclaw"
if grep -q 'chown -R root:root.*npm_projects' root/usr/libexec/openclaw-permissions.sh; then
fail "managed npm plugin generations must not be made root-owned"
fi
if grep -q 'chown -R openclaw:openclaw "$OC_DATA"' root/etc/init.d/openclaw root/usr/share/openclaw/oc-config.sh root/usr/share/openclaw/web-pty.js; then
fail "must not recursively chown the whole OC_DATA to openclaw"
fi
@@ -143,8 +155,8 @@ grep -q "gpt-5.5" root/usr/share/openclaw/oc-config-interactive.js || fail "inte
grep -q "gpt-5.5" root/usr/share/openclaw/oc-config.sh || fail "shell Yiwan AI model missing"
grep -q "authSetApikey(providerName, apiKey,.*fan" root/usr/share/openclaw/oc-config-interactive.js || fail "interactive Yiwan AI auth profile missing"
grep -q 'auth_set_apikey yiwanai "$api_key" "yiwanai:fan"' root/usr/share/openclaw/oc-config.sh || fail "shell Yiwan AI auth profile missing"
grep -q "registerCustomProvider(providerName, baseUrl, apiKey, modelName, modelName)" root/usr/share/openclaw/oc-config-interactive.js || fail "interactive Yiwan AI custom provider registration missing"
grep -q 'register_custom_provider yiwanai "https://api.910501.xyz/v1" "$api_key" "gpt-5.5" "gpt-5.5"' root/usr/share/openclaw/oc-config.sh || fail "shell Yiwan AI custom provider registration missing"
grep -q "registerCustomProvider(providerName, baseUrl, apiKey, modelName, modelName, 1000000, 32000)" root/usr/share/openclaw/oc-config-interactive.js || fail "interactive Yiwan AI 1M context registration missing"
grep -q 'register_custom_provider yiwanai "https://api.910501.xyz/v1" "$api_key" "gpt-5.5" "gpt-5.5" 1000000 32000' root/usr/share/openclaw/oc-config.sh || fail "shell Yiwan AI 1M context registration missing"
grep -q 'registerAndSetModel(`${providerName}/${modelName}`)' root/usr/share/openclaw/oc-config-interactive.js || fail "interactive Yiwan AI active model missing"
grep -q "provider.models\[0\].reasoning = true" root/usr/share/openclaw/oc-config-interactive.js || fail "interactive Yiwan AI reasoning flag missing"
grep -q "p.models\[0\].reasoning=true" root/usr/share/openclaw/oc-config.sh || fail "shell Yiwan AI reasoning flag missing"
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=mihomo
PKG_VERSION:=1.19.27
PKG_RELEASE:=29
PKG_VERSION:=1.19.28
PKG_RELEASE:=30
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/metacubex/mihomo/tar.gz/v$(PKG_VERSION)?
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow
PKG_VERSION:=20260531
PKG_RELEASE:=39
PKG_RELEASE:=40
PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=5ba6726ce0a54bf198c470e4b7fc0c3387f85537
PKG_SOURCE_VERSION:=43fce72a110d72386e65bc49c7c8574592267af3
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fastfetch
PKG_VERSION:=2.65.2
PKG_RELEASE:=11
PKG_VERSION:=2.66.0
PKG_RELEASE:=12
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)?
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=opera-proxy
PKG_VERSION:=1.26.0
PKG_RELEASE:=7
PKG_VERSION:=1.27.0
PKG_RELEASE:=8
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
PKG_LICENSE:=MIT