惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Schneier on Security
Cisco Talos Blog
Cisco Talos Blog
T
ThreatConnect
J
Java Code Geeks
博客园 - 司徒正美
A
Arctic Wolf
T
True Tiger Recordings
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
Know Your Adversary
Know Your Adversary
T
Threat Research - Cisco Blogs
V
Vulnerabilities – Threatpost
Recorded Future
Recorded Future
P
Palo Alto Networks Blog
The Hacker News
The Hacker News
The Register - Security
The Register - Security
S
Securelist
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Application and Cybersecurity Blog
Application and Cybersecurity Blog
I
Intezer
P
Privacy & Cybersecurity Law Blog
Scott Helme
Scott Helme
K
Kaspersky official blog
博客园 - 聂微东
Last Week in AI
Last Week in AI
V
V2EX
小众软件
小众软件
F
Fox-IT International blog
Martin Fowler
Martin Fowler
Apple Machine Learning Research
Apple Machine Learning Research
T
Tenable Blog
F
Future of Privacy Forum
Microsoft Security Blog
Microsoft Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
C
Check Point Blog
阮一峰的网络日志
阮一峰的网络日志
GbyAI
GbyAI
T
Threatpost
I
InfoQ
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
Tor Project blog
G
GRAHAM CLULEY
D
DataBreaches.Net

Recent Commits to openclaw:main

fix(crabbox): bootstrap macos shell js commands · openclaw/openclaw@7cd15d2 fix: preflight malformed openshell exec commands fix: tighten openshell exec preflight · openclaw/openclaw@822ee62 docs: clarify unshipped compat policy · openclaw/openclaw@f87aa0f fix(update): allow package-manager hardlinks in swaps docs: ban repo-hosted proof artifacts · openclaw/openclaw@17954a4 fix(discord): restore bare numeric channel sends (#86571) · openclaw/openclaw@c5b9872 fix(security): audit Claude permission overrides under YOLO (#86557) · openclaw/openclaw@bd65b42 fix: speed up Discord voice wake consults · openclaw/openclaw@5ae91f0 fix(qa): harden restart inflight Windows scenario · openclaw/openclaw@3eb06e3 Recover Codex context overflow prompt errors (#85542) · openclaw/openclaw@5cfa577 docs: update changelog for #70473 · openclaw/openclaw@d967760 fix(agents): derive overflow budgets from provider errors · openclaw/openclaw@d5b0174 fix(plugins): only memoize complete metadata snapshots · openclaw/openclaw@3137622 docs: update changelog for media wake fallback (#85489) · openclaw/openclaw@a11d4e6 fix: fallback after active media wake failure (#85489) · openclaw/openclaw@1b64ccb perf(plugins): reuse derived metadata snapshots · openclaw/openclaw@159e440 docs: require maintainer-editable PR branches · openclaw/openclaw@f271f00 fix: scan OpenClaw sessions in agent transcript finder · openclaw/openclaw@4012ae4 docs: note agent transcript OpenClaw session scan · openclaw/openclaw@dd375f9 docs: require generic local fixes · openclaw/openclaw@fc93af5 fix: broaden leading voice wake fuzzing · openclaw/openclaw@a9c91ca test(agents): preserve provider hook mock exports (#86523) · openclaw/openclaw@657b246 Policy: add agent-scoped policy overlays (#85817) · openclaw/openclaw@fbb6340 fix(kilocode): normalize string stop param to array in stream wrapper… · openclaw/openclaw@abe9923 Doctor: expose shell completion health findings (#85566) · openclaw/openclaw@dc17412 fix(agents): honor effective exec policy for Claude live Bash (#86330) fix(test): stabilize e2e runtime imports fix(test): clean plugin gauntlet temp roots · openclaw/openclaw@633e4b8 perf: cache plugin package realpaths (#86517) · openclaw/openclaw@69d728a fix(qa): settle restart races with live budget · openclaw/openclaw@2cac9e5 fix(crabbox): sync full sparse lease runs · openclaw/openclaw@e97e831 fix(qa): extend config mutation Windows budget fix(qa): extend config cleanup Windows budget · openclaw/openclaw@8a93851 test(crabbox): tolerate Windows shell capture · openclaw/openclaw@50d6611 fix(sessions): stop doctor OOM on large session stores and reclaim st… · openclaw/openclaw@89aea9b fix(ollama): strip inline kimi cloud reasoning leak (#86515) fix(discord): merge media captions into one message (#86487) · openclaw/openclaw@bc10fad fix(utils): clamp fetch timeout timers (#85985) fix(ui): preserve user code block rendering (#85942) fix(memory): prevent silent vector index degradation when embedding p… docs: clarify agent transcript placeholders · openclaw/openclaw@8da8bc4 test(qa): annotate live transport RTT measurements · openclaw/openclaw@bb6f37e fix(qqbot): derive outbound watchdog from configured timeouts (#85267… · openclaw/openclaw@aa702cf fix(test): clean kitchen sink rpc temp state · openclaw/openclaw@6f695c1 fix: quiet missing daily memory reads fix: tighten empty plugin registry reuse · openclaw/openclaw@026cfb6 perf: speed up agent transcript lookup · openclaw/openclaw@e7ad116 fix: guard QMD session stem fallback (#86482) · openclaw/openclaw@2e3b59b Guard OpenAI chat payload turns (#86497) · openclaw/openclaw@489e415 fix(gateway): keep session tool mirrors under pressure · openclaw/openclaw@459e89a docs: route github creation through agent transcript test(tools): add unmocked image custom-provider auth regression (#85733) · openclaw/openclaw@f0bfb3f refactor(plugin-sdk): rename plain text tool-call compat wrapper docs(skills): defer private release locators · openclaw/openclaw@23d38e4 Replace Sharp image backend with Photon (#86437) · openclaw/openclaw@b9f975b fix(agents): release embedded-attempt session lock on every exit path… · openclaw/openclaw@32ddfc2 fix: accept OpenClaw voice wake confusions (#86507) fix(crabbox): bootstrap macos js toolchain chore: add agent transcript skill · openclaw/openclaw@d63e8d4 fix(gateway): dedupe session tool fanout · openclaw/openclaw@89a21db fix: Hook ingress token unlocks password-mode gateway auth (#86453) · openclaw/openclaw@d51f268 fix #86077: keep fallback errors candidate scoped (#86134) · openclaw/openclaw@d6b7fe8 fix(diagnostics): reclaim wedged session lanes with a stale leaked ac… · openclaw/openclaw@6f76d9f fix: derive plugin media trust from metadata (#86410) · openclaw/openclaw@e761eb8 fix(media-understanding): normalize HEIC before image descriptions (#… · openclaw/openclaw@75c7236 fix: accept leading fuzzy Discord voice wake names (#86484) · openclaw/openclaw@8fe4f34 feat: promote provider tool call stream wrapper (#86489) fix(test): dedupe kitchen sink command assertions test: derive deprecated sdk usage guard (#86403) fix(qa): extend memory fallback Windows budget fix(ui): move control ui chunking helper out of runtime source · openclaw/openclaw@968c87d fix: quiet retained lost task noise (#86475) fix(build): keep control ui chunking out of deadcode · openclaw/openclaw@dc26069 fix: rotate realtime voice sessions on max duration · openclaw/openclaw@dc2c4aa fix(test): stream bundled plugin sweep logs · openclaw/openclaw@fc3cd49 docs: add bugfix changelog credits · openclaw/openclaw@2e7e4bc fix(models): show oauth marker auth status (#86378) · openclaw/openclaw@a6df39d fix: seed cron task progress summaries (#86313) · openclaw/openclaw@92afd8b fix(update): exclude prerelease tags from stable git channel (#86260) · openclaw/openclaw@28f169b fix(doctor): warn and continue when cron job store is unreadable (#86… fix(gateway): clear runtime config snapshot before in-process restart… · openclaw/openclaw@90caa3b fix(scripts): restore sparse crabbox changed gates · openclaw/openclaw@d270879 fix(build): support Windows UI builds · openclaw/openclaw@0bb9b42 Fix local embedding worker safety (#85348) · openclaw/openclaw@7ff29a9 fix(ui): scope chat session picker to active agent (#85965) · openclaw/openclaw@70c7d6f [codex] improve iOS realtime talk mode (#86355) · openclaw/openclaw@9ca52ce fix(scripts): dedupe docker lane resources · openclaw/openclaw@5e94469 docs: add code size guidance · openclaw/openclaw@9a60fcf fix(test): avoid source gateway import in rpc walk · openclaw/openclaw@e9b8a6e docs: add bugfix changelog entries · openclaw/openclaw@f950132 Fix heartbeat response loop guard (#86324) (#86357) · openclaw/openclaw@e2c174e fix(memory-core): filter REM dreaming candidates to light-staged entr… · openclaw/openclaw@8b42771 fix(telegram): propagate forum topic names into agent context (#86299) fix(slack): keep downloaded files out of reply media (#86318) · openclaw/openclaw@2fcd481 fix(cron): accept plus durations for one-shot jobs (#86341) · openclaw/openclaw@9239f94 fix(plugins): clear metadata memo at lifecycle boundaries · openclaw/openclaw@e7c696a chore(skills): normalize release skill routing · openclaw/openclaw@4737e19 docs(release): require early performance regression check · openclaw/openclaw@0336938 fix(qa): capture Windows gateway metrics · openclaw/openclaw@9afbfc1
fix(installer): handle alpine apk runtime floors · openclaw/openclaw@b83dfcb
vincentkoc · 2026-05-26 · via Recent Commits to openclaw:main

@@ -109,14 +109,17 @@ describe("install.sh", () => {

109109110110

it("installs Node.js with apk on Alpine before falling back to NodeSource", () => {

111111

expect(script).toContain("finish_linux_node_install()");

112+

expect(script).toContain("is_alpine_linux()");

113+

expect(script).toContain("install_node_with_apk()");

112114

expect(script).toContain('ui_info "Installing Node.js via apk (Alpine Linux detected)"');

113115

expect(script).toContain('run_quiet_step "Installing Node.js" apk add --no-cache nodejs npm');

114116

expect(script).toContain(

115117

'run_quiet_step "Installing Node.js" sudo apk add --no-cache nodejs npm',

116118

);

119+

expect(script).toContain('run_quiet_step "Installing nodejs-current" apk add --no-cache nodejs-current npm');

117120

expect(script).toContain("if ! node_is_at_least_required; then");

118121119-

const apkIndex = script.indexOf("if command -v apk &> /dev/null; then");

122+

const apkIndex = script.indexOf("if command -v apk &> /dev/null && is_alpine_linux; then");

120123

const nodeSourceIndex = script.indexOf('ui_info "Installing Node.js via NodeSource"');

121124

expect(apkIndex).toBeGreaterThan(-1);

122125

expect(nodeSourceIndex).toBeGreaterThan(apkIndex);

@@ -130,10 +133,12 @@ describe("install.sh", () => {

130133

require_sudo() { :; }

131134

install_build_tools_linux() { return 0; }

132135

is_root() { return 0; }

136+

is_alpine_linux() { return 0; }

133137

ui_info() { printf 'info:%s\\n' "$*"; }

134138

ui_success() { printf 'success:%s\\n' "$*"; }

135139

run_quiet_step() { printf 'step:%s|%s\\n' "$1" "\${*:2}"; }

136140

apk() { :; }

141+

node_is_at_least_required() { return 0; }

137142

finish_linux_node_install() { printf 'finish-linux-node\\n'; }

138143

install_node

139144

`);

@@ -145,6 +150,182 @@ describe("install.sh", () => {

145150

expect(result.stdout).not.toContain("Installing Node.js via NodeSource");

146151

});

147152153+

it("tries nodejs-current when Alpine nodejs is below the runtime floor", () => {

154+

const result = runInstallShell(`

155+

set -euo pipefail

156+

source "${SCRIPT_PATH}"

157+

OS=linux

158+

NODE_FAKE_VERSION=v20.15.1

159+

require_sudo() { :; }

160+

install_build_tools_linux() { return 0; }

161+

is_root() { return 0; }

162+

is_alpine_linux() { return 0; }

163+

ui_info() { printf 'info:%s\\n' "$*"; }

164+

ui_success() { printf 'success:%s\\n' "$*"; }

165+

ui_warn() { printf 'warn:%s\\n' "$*"; }

166+

run_quiet_step() {

167+

printf 'step:%s|%s\\n' "$1" "\${*:2}"

168+

"\${@:2}"

169+

}

170+

apk() {

171+

printf 'apk:%s\\n' "$*"

172+

if [[ "$*" == *"nodejs-current"* ]]; then

173+

NODE_FAKE_VERSION=v22.22.2

174+

fi

175+

}

176+

node() {

177+

if [[ "\${1:-}" == "-v" ]]; then

178+

printf '%s\\n' "$NODE_FAKE_VERSION"

179+

fi

180+

}

181+

activate_supported_node_on_path() { :; }

182+

finish_linux_node_install() { printf 'finish-linux-node\\n'; }

183+

install_node

184+

`);

185+186+

expect(result.status).toBe(0);

187+

expect(result.stdout).toContain("step:Installing Node.js|apk add --no-cache nodejs npm");

188+

expect(result.stdout).toContain("warn:Alpine nodejs package installed v20.15.1");

189+

expect(result.stdout).toContain("step:Installing nodejs-current|apk add --no-cache nodejs-current npm");

190+

expect(result.stdout).toContain("finish-linux-node");

191+

});

192+193+

it("fails with Alpine version guidance when apk cannot provide the runtime floor", () => {

194+

const result = runInstallShell(`

195+

set -euo pipefail

196+

source "${SCRIPT_PATH}"

197+

OS=linux

198+

NODE_FAKE_VERSION=v20.15.1

199+

require_sudo() { :; }

200+

install_build_tools_linux() { return 0; }

201+

is_root() { return 0; }

202+

is_alpine_linux() { return 0; }

203+

ui_info() { printf 'info:%s\\n' "$*"; }

204+

ui_success() { printf 'success:%s\\n' "$*"; }

205+

ui_warn() { printf 'warn:%s\\n' "$*"; }

206+

ui_error() { printf 'error:%s\\n' "$*"; }

207+

run_quiet_step() {

208+

printf 'step:%s|%s\\n' "$1" "\${*:2}"

209+

"\${@:2}"

210+

}

211+

apk() {

212+

printf 'apk:%s\\n' "$*"

213+

if [[ "$*" == *"nodejs-current"* ]]; then

214+

NODE_FAKE_VERSION=v21.7.3

215+

fi

216+

}

217+

node() {

218+

if [[ "\${1:-}" == "-v" ]]; then

219+

printf '%s\\n' "$NODE_FAKE_VERSION"

220+

fi

221+

}

222+

activate_supported_node_on_path() { :; }

223+

install_node

224+

`);

225+226+

expect(result.status).toBe(1);

227+

expect(result.stdout).toContain("warn:Alpine nodejs package installed v20.15.1");

228+

expect(result.stdout).toContain("step:Installing nodejs-current|apk add --no-cache nodejs-current npm");

229+

expect(result.stdout).toContain("error:Alpine apk repositories did not provide Node.js v22.19+");

230+

expect(result.stdout).toContain("Use Alpine 3.21+ or install Node.js 24 manually");

231+

});

232+233+

it("installs Git with apk on Alpine", () => {

234+

const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-git-apk-"));

235+

const bin = join(tmp, "bin");

236+

const apkLog = join(tmp, "apk-args.txt");

237+

mkdirSync(bin, { recursive: true });

238+

const fakeApk = join(bin, "apk");

239+

writeFileSync(

240+

fakeApk,

241+

[

242+

"#!/usr/bin/env bash",

243+

"set -euo pipefail",

244+

`printf '%s\\n' "$*" >> ${JSON.stringify(apkLog)}`,

245+

"",

246+

].join("\n"),

247+

);

248+

chmodSync(fakeApk, 0o755);

249+250+

try {

251+

const result = runInstallShell(`

252+

set -euo pipefail

253+

source "${SCRIPT_PATH}"

254+

PATH=${JSON.stringify(`${bin}:/bin`)}

255+

OS=linux

256+

require_sudo() { :; }

257+

is_root() { return 0; }

258+

is_alpine_linux() { return 0; }

259+

ui_success() { printf 'success:%s\\n' "$*"; }

260+

ui_error() { printf 'error:%s\\n' "$*"; }

261+

run_quiet_step() {

262+

printf 'step:%s|%s\\n' "$1" "\${*:2}"

263+

"\${@:2}"

264+

}

265+

install_git

266+

`);

267+268+

expect(result.status).toBe(0);

269+

expect(result.stdout).toContain("step:Installing Git|apk add --no-cache git");

270+

expect(result.stdout).toContain("success:Git installed");

271+

expect(readFileSync(apkLog, "utf8").trim()).toBe("add --no-cache git");

272+

} finally {

273+

rmSync(tmp, { recursive: true, force: true });

274+

}

275+

});

276+277+

it("does not select apk Git on non-Alpine hosts", () => {

278+

const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-git-native-"));

279+

const bin = join(tmp, "bin");

280+

const apkLog = join(tmp, "apk-args.txt");

281+

mkdirSync(bin, { recursive: true });

282+

const fakeApk = join(bin, "apk");

283+

const fakeApt = join(bin, "apt-get");

284+

writeFileSync(apkLog, "");

285+

writeFileSync(

286+

fakeApk,

287+

[

288+

"#!/usr/bin/env bash",

289+

"set -euo pipefail",

290+

`printf '%s\\n' "$*" >> ${JSON.stringify(apkLog)}`,

291+

"",

292+

].join("\n"),

293+

);

294+

writeFileSync(fakeApt, "#!/usr/bin/env bash\nexit 0\n");

295+

chmodSync(fakeApk, 0o755);

296+

chmodSync(fakeApt, 0o755);

297+298+

try {

299+

const result = runInstallShell(`

300+

set -euo pipefail

301+

source "${SCRIPT_PATH}"

302+

PATH=${JSON.stringify(`${bin}:/bin`)}

303+

OS=linux

304+

require_sudo() { :; }

305+

is_root() { return 0; }

306+

is_alpine_linux() { return 1; }

307+

apt_get_update() { printf 'apt-update\\n'; }

308+

apt_get_install() { printf 'apt-install:%s\\n' "$*"; }

309+

ui_success() { printf 'success:%s\\n' "$*"; }

310+

ui_error() { printf 'error:%s\\n' "$*"; }

311+

run_quiet_step() {

312+

printf 'step:%s|%s\\n' "$1" "\${*:2}"

313+

"\${@:2}"

314+

}

315+

install_git

316+

`);

317+318+

expect(result.status).toBe(0);

319+

expect(result.stdout).toContain("step:Updating package index|apt_get_update");

320+

expect(result.stdout).toContain("apt-update");

321+

expect(result.stdout).toContain("step:Installing Git|apt_get_install git");

322+

expect(result.stdout).toContain("apt-install:git");

323+

expect(readFileSync(apkLog, "utf8")).toBe("");

324+

} finally {

325+

rmSync(tmp, { recursive: true, force: true });

326+

}

327+

});

328+148329

it("clears npm freshness filters for package installs", () => {

149330

expect(script).toContain("env -u NPM_CONFIG_BEFORE -u npm_config_before");

150331

expect(script).toContain('freshness_flag="--min-release-age=0"');

@@ -156,10 +337,12 @@ describe("install.sh", () => {

156337

it("does not emit --before when raw user npmrc config contains min-release-age", () => {

157338

const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-npmrc-"));

158339

const bin = join(tmp, "bin");

340+

const home = join(tmp, "home");

159341

const npmrc = join(tmp, "user.npmrc");

160342

const calls = join(tmp, "npm-calls.txt");

161343

const installArgs = join(tmp, "npm-install-args.txt");

162344

mkdirSync(bin, { recursive: true });

345+

mkdirSync(home, { recursive: true });

163346

writeFileSync(npmrc, "min-release-age=7\n");

164347

const fakeNpm = join(bin, "npm");

165348

writeFileSync(

@@ -194,10 +377,11 @@ describe("install.sh", () => {

194377

'printf "cmd=%s\\n" "$LAST_NPM_INSTALL_CMD"',

195378

].join("\n"),

196379

{

380+

HOME: home,

197381

NPM_CONFIG_USERCONFIG: npmrc,

198382

NPM_FAKE_CALLS: calls,

199383

NPM_FAKE_INSTALL_ARGS: installArgs,

200-

PATH: `${bin}:${process.env.PATH}`,

384+

PATH: `${bin}:/usr/local/bin:/usr/bin:/bin`,

201385

},

202386

);

203387

@@ -638,6 +822,13 @@ describe("install.sh", () => {

638822

[

639823

`cd ${JSON.stringify(process.cwd())}`,

640824

`source ${JSON.stringify(SCRIPT_PATH)}`,

825+

"type() {",

826+

' if [[ "$*" == "-P -a node" ]]; then',

827+

` printf '%s\\n' ${JSON.stringify(staleNode)} ${JSON.stringify(supportedNode)}`,

828+

" return 0",

829+

" fi",

830+

' builtin type "$@"',

831+

"}",

641832

"set +e",

642833

"OS=linux",

643834

"promote_supported_node_binary",