mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-11 04:48:05 +00:00
fix(installer): persist Linux supported PATH
This commit is contained in:
@@ -1366,6 +1366,32 @@ prepend_path_dir() {
|
||||
refresh_shell_command_cache
|
||||
}
|
||||
|
||||
persist_shell_path_prepend() {
|
||||
local dir="${1%/}"
|
||||
if [[ -z "$dir" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local path_line="export PATH=\"${dir}:\$PATH\""
|
||||
local wrote_rc=0
|
||||
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
|
||||
if [[ -f "$rc" ]]; then
|
||||
if ! grep -Fq "$dir" "$rc"; then
|
||||
local tmp_rc="${rc}.openclaw-tmp"
|
||||
{
|
||||
printf '%s\n' "$path_line"
|
||||
cat "$rc"
|
||||
} > "$tmp_rc"
|
||||
mv "$tmp_rc" "$rc"
|
||||
fi
|
||||
wrote_rc=1
|
||||
fi
|
||||
done
|
||||
if [[ "$wrote_rc" -eq 0 ]]; then
|
||||
printf '%s\n' "$path_line" >> "$HOME/.bashrc"
|
||||
fi
|
||||
}
|
||||
|
||||
promote_supported_node_binary() {
|
||||
local candidates=()
|
||||
local candidate dir seen_dirs=":"
|
||||
@@ -1397,6 +1423,9 @@ promote_supported_node_binary() {
|
||||
seen_dirs="${seen_dirs}${dir}:"
|
||||
if node_binary_is_at_least_required "$candidate"; then
|
||||
prepend_path_dir "$dir" || continue
|
||||
if [[ "$OS" == "linux" ]]; then
|
||||
persist_shell_path_prepend "$dir" || true
|
||||
fi
|
||||
ui_info "Using Node.js runtime at ${candidate}"
|
||||
return 0
|
||||
fi
|
||||
@@ -1623,8 +1652,8 @@ install_node() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
promote_supported_node_binary || true
|
||||
ui_success "Node.js v${NODE_DEFAULT_MAJOR} installed"
|
||||
activate_supported_node_on_path || true
|
||||
print_active_node_paths || true
|
||||
fi
|
||||
}
|
||||
@@ -1738,7 +1767,12 @@ fix_npm_permissions() {
|
||||
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
|
||||
if [[ -f "$rc" ]]; then
|
||||
if ! grep -q ".npm-global" "$rc"; then
|
||||
echo "$path_line" >> "$rc"
|
||||
local tmp_rc="${rc}.openclaw-tmp"
|
||||
{
|
||||
printf '%s\n' "$path_line"
|
||||
cat "$rc"
|
||||
} > "$tmp_rc"
|
||||
mv "$tmp_rc" "$rc"
|
||||
fi
|
||||
wrote_rc=1
|
||||
fi
|
||||
@@ -2665,6 +2699,7 @@ main() {
|
||||
if ! check_node; then
|
||||
install_node
|
||||
fi
|
||||
activate_supported_node_on_path || true
|
||||
if ! ensure_default_node_active_shell; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -155,6 +155,64 @@ describe("install.sh", () => {
|
||||
expect(output).toContain("version=v22.22.0");
|
||||
});
|
||||
|
||||
it("persists a supported Linux Node path before noninteractive shell guards", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-linux-node-path-"));
|
||||
const home = join(tmp, "home");
|
||||
const oldBin = join(tmp, "old/bin");
|
||||
const installedBin = join(tmp, "usr/bin");
|
||||
mkdirSync(home, { recursive: true });
|
||||
mkdirSync(oldBin, { recursive: true });
|
||||
mkdirSync(installedBin, { recursive: true });
|
||||
|
||||
const oldNode = join(oldBin, "node");
|
||||
const installedNode = join(installedBin, "node");
|
||||
writeFileSync(
|
||||
join(home, ".bashrc"),
|
||||
["case $- in", " *i*) ;;", " *) return ;;", "esac", ""].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
oldNode,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
'if [[ "${1:-}" == "-p" ]]; then echo "20 20"; exit 0; fi',
|
||||
'if [[ "${1:-}" == "-v" ]]; then echo "v20.20.0"; exit 0; fi',
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
installedNode,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
'if [[ "${1:-}" == "-p" ]]; then echo "24 13"; exit 0; fi',
|
||||
'if [[ "${1:-}" == "-v" ]]; then echo "v24.13.0"; exit 0; fi',
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(oldNode, 0o755);
|
||||
chmodSync(installedNode, 0o755);
|
||||
|
||||
let result: ReturnType<typeof runInstallShell> | undefined;
|
||||
try {
|
||||
result = runInstallShell(`
|
||||
set -euo pipefail
|
||||
source "${SCRIPT_PATH}"
|
||||
OS=linux
|
||||
HOME=${JSON.stringify(home)}
|
||||
PATH=${JSON.stringify(`${oldBin}:${installedBin}:/usr/bin:/bin`)}
|
||||
ui_info() { :; }
|
||||
activate_supported_node_on_path
|
||||
printf 'first=%s\\n' "$(sed -n '1p' "$HOME/.bashrc")"
|
||||
HOME=${JSON.stringify(home)} PATH=${JSON.stringify(`${oldBin}:${installedBin}:/usr/bin:/bin`)} bash -lc '. "$HOME/.bashrc"; printf "node=%s\\n" "$(command -v node)"'
|
||||
`);
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
expect(result?.status).toBe(0);
|
||||
expect(result?.stdout).toContain(`first=export PATH="${installedBin}:$PATH"`);
|
||||
expect(result?.stdout).toContain(`node=${installedNode}`);
|
||||
});
|
||||
|
||||
it("warns before redirecting an unwritable npm prefix", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-npm-prefix-"));
|
||||
const home = join(tmp, "home");
|
||||
@@ -208,6 +266,50 @@ describe("install.sh", () => {
|
||||
expect(result?.stdout).not.toContain("has been saved");
|
||||
});
|
||||
|
||||
it("persists npm prefix PATH before noninteractive shell guards", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-npm-prefix-shell-"));
|
||||
const home = join(tmp, "home");
|
||||
mkdirSync(home, { recursive: true });
|
||||
writeFileSync(
|
||||
join(home, ".bashrc"),
|
||||
["case $- in", " *i*) ;;", " *) return ;;", "esac", ""].join("\n"),
|
||||
);
|
||||
|
||||
let result: ReturnType<typeof runInstallShell> | undefined;
|
||||
try {
|
||||
result = runInstallShell(`
|
||||
set -euo pipefail
|
||||
source "${SCRIPT_PATH}"
|
||||
OS=linux
|
||||
HOME=${JSON.stringify(home)}
|
||||
PATH=/usr/bin:/bin
|
||||
prefix=${JSON.stringify(join(tmp, "root-owned-prefix"))}
|
||||
npm() {
|
||||
if [[ "$1" == "config" && "$2" == "get" && "$3" == "prefix" ]]; then
|
||||
printf '%s\\n' "$prefix"
|
||||
return 0
|
||||
fi
|
||||
if [[ "$1" == "config" && "$2" == "set" && "$3" == "prefix" ]]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
ui_info() { :; }
|
||||
ui_warn() { :; }
|
||||
ui_success() { :; }
|
||||
fix_npm_permissions
|
||||
printf 'first=%s\\n' "$(sed -n '1p' "$HOME/.bashrc")"
|
||||
HOME=${JSON.stringify(home)} PATH=/usr/bin:/bin bash -lc '. "$HOME/.bashrc"; printf "path=%s\\n" "\${PATH%%:*}"'
|
||||
`);
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
expect(result?.status).toBe(0);
|
||||
expect(result?.stdout).toContain('first=export PATH="$HOME/.npm-global/bin:$PATH"');
|
||||
expect(result?.stdout).toContain(`path=${home}/.npm-global/bin`);
|
||||
});
|
||||
|
||||
it("uses a quoted absolute openclaw path in follow-up commands when npm bin is not on the original PATH", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-command-"));
|
||||
const npmBin = join(tmp, "npm bin");
|
||||
|
||||
Reference in New Issue
Block a user