Skip to content

Commit 432adcd

Browse files
author
Xila
committed
Fix Android node shell wrapper
1 parent ef58307 commit 432adcd

4 files changed

Lines changed: 22 additions & 2 deletions

File tree

docs/cli/node.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Options:
6767

6868
`openclaw node run` and `openclaw node install` resolve gateway auth from config/env (no `--token`/`--password` flags on node commands):
6969

70+
- Android/Termux node hosts use `/data/data/com.termux/files/usr/bin/sh` as the shell wrapper for `system.run`.
7071
- `OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD` are checked first.
7172
- Then local config fallback: `gateway.auth.token` / `gateway.auth.password`.
7273
- In local mode, node host intentionally does not inherit `gateway.remote.token` / `gateway.remote.password`.

docs/nodes/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ Notes:
419419
- The node host stores its node id, token, display name, and gateway connection info in `~/.openclaw/node.json`.
420420
- Exec approvals are enforced locally via `~/.openclaw/exec-approvals.json`
421421
(see [Exec approvals](/tools/exec-approvals)).
422+
- Android/Termux node hosts use `/data/data/com.termux/files/usr/bin/sh` as the shell wrapper for `system.run`.
422423
- On macOS, the headless node host executes `system.run` locally by default. Set
423424
`OPENCLAW_NODE_EXEC_HOST=app` to route `system.run` through the companion app exec host; add
424425
`OPENCLAW_NODE_EXEC_FALLBACK=0` to require the app host and fail closed if it is unavailable.

src/infra/node-shell.test.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { buildNodeShellCommand } from "./node-shell.js";
2+
import { ANDROID_TERMUX_SHELL, buildNodeShellCommand } from "./node-shell.js";
33

44
describe("buildNodeShellCommand", () => {
55
it("uses cmd.exe for win-prefixed platform labels", () => {
@@ -26,7 +26,20 @@ describe("buildNodeShellCommand", () => {
2626
]);
2727
});
2828

29-
it("uses /bin/sh for non-windows and missing platform values", () => {
29+
it("uses the Termux shell for Android nodes", () => {
30+
expect(buildNodeShellCommand("echo hi", "android")).toEqual([
31+
ANDROID_TERMUX_SHELL,
32+
"-lc",
33+
"echo hi",
34+
]);
35+
expect(buildNodeShellCommand("echo hi", " Android ")).toEqual([
36+
ANDROID_TERMUX_SHELL,
37+
"-lc",
38+
"echo hi",
39+
]);
40+
});
41+
42+
it("uses /bin/sh for non-windows, non-android, and missing platform values", () => {
3043
expect(buildNodeShellCommand("echo hi", "darwin")).toEqual(["/bin/sh", "-lc", "echo hi"]);
3144
expect(buildNodeShellCommand("echo hi", "linux")).toEqual(["/bin/sh", "-lc", "echo hi"]);
3245
expect(buildNodeShellCommand("echo hi")).toEqual(["/bin/sh", "-lc", "echo hi"]);

src/infra/node-shell.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
22

3+
export const ANDROID_TERMUX_SHELL = "/data/data/com.termux/files/usr/bin/sh";
4+
35
export function buildNodeShellCommand(command: string, platform?: string | null) {
46
const normalized = normalizeLowercaseStringOrEmpty((platform ?? "").trim());
57
if (normalized.startsWith("win")) {
68
return ["cmd.exe", "/d", "/s", "/c", command];
79
}
10+
if (normalized === "android") {
11+
return [ANDROID_TERMUX_SHELL, "-lc", command];
12+
}
813
return ["/bin/sh", "-lc", command];
914
}

0 commit comments

Comments
 (0)