




















@@ -1825,6 +1825,148 @@ npm_global_bin_dir() {
18251825return 1
18261826}
182718271828+canonicalize_dir() {
1829+local dir="$1"
1830+if [[ -z "$dir" || ! -d "$dir" ]]; then
1831+return 1
1832+fi
1833+ (cd "$dir" 2>/dev/null && pwd -P) || return 1
1834+}
1835+1836+openclaw_package_version() {
1837+local package_json="$1"
1838+if [[ ! -f "$package_json" ]]; then
1839+echo "unknown"
1840+return 0
1841+fi
1842+1843+local version=""
1844+if command -v node >/dev/null 2>&1; then
1845+ version="$(node -e 'const fs = require("fs"); const pkg = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(String(pkg.version || "unknown"));' "$package_json" 2>/dev/null || true)"
1846+fi
1847+if [[ -z "$version" ]]; then
1848+ version="$(sed -n -E 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' "$package_json" | head -n1)"
1849+fi
1850+echo "${version:-unknown}"
1851+}
1852+1853+emit_npm_root_candidate() {
1854+local root="${1%/}"
1855+if [[ -n "$root" && "$root" == /* ]]; then
1856+echo "$root"
1857+fi
1858+}
1859+1860+collect_openclaw_npm_root_candidates() {
1861+local root=""
1862+ root="$(npm root -g 2>/dev/null || true)"
1863+ emit_npm_root_candidate "$root"
1864+1865+local npm_cmd=""
1866+while IFS= read -r npm_cmd; do
1867+ [[ -n "$npm_cmd" ]] || continue
1868+ root="$("$npm_cmd" root -g 2>/dev/null || true)"
1869+ emit_npm_root_candidate "$root"
1870+done < <(type -aP npm 2>/dev/null | awk '!seen[$0]++' || true)
1871+1872+local extra_root=""
1873+local old_ifs="$IFS"
1874+ IFS=":"
1875+for extra_root in ${OPENCLAW_INSTALL_EXTRA_NPM_ROOTS:-}; do
1876+ emit_npm_root_candidate "$extra_root"
1877+done
1878+ IFS="$old_ifs"
1879+1880+ emit_npm_root_candidate "/opt/homebrew/lib/node_modules"
1881+ emit_npm_root_candidate "/usr/local/lib/node_modules"
1882+ emit_npm_root_candidate "/usr/lib/node_modules"
1883+1884+local manager_dir=""
1885+local candidate=""
1886+for manager_dir in "${NVM_DIR:-}" "$HOME/.nvm"; do
1887+ [[ -n "$manager_dir" && -d "$manager_dir" ]] || continue
1888+for candidate in "$manager_dir"/versions/node/*/lib/node_modules; do
1889+ [[ -d "$candidate" ]] && emit_npm_root_candidate "$candidate"
1890+done
1891+done
1892+1893+for manager_dir in "${FNM_DIR:-}" "$HOME/.fnm" "$HOME/.local/share/fnm"; do
1894+ [[ -n "$manager_dir" && -d "$manager_dir" ]] || continue
1895+for candidate in "$manager_dir"/node-versions/*/installation/lib/node_modules; do
1896+ [[ -d "$candidate" ]] && emit_npm_root_candidate "$candidate"
1897+done
1898+done
1899+1900+for manager_dir in "${VOLTA_HOME:-}" "$HOME/.volta"; do
1901+ [[ -n "$manager_dir" && -d "$manager_dir" ]] || continue
1902+for candidate in "$manager_dir"/tools/image/node/*/lib/node_modules; do
1903+ [[ -d "$candidate" ]] && emit_npm_root_candidate "$candidate"
1904+done
1905+done
1906+}
1907+1908+find_openclaw_global_installs() {
1909+local seen="|"
1910+local npm_root=""
1911+while IFS= read -r npm_root; do
1912+ [[ -n "$npm_root" ]] || continue
1913+local package_dir="${npm_root%/}/openclaw"
1914+local package_json="${package_dir}/package.json"
1915+ [[ -f "$package_json" ]] || continue
1916+1917+local real_package_dir=""
1918+ real_package_dir="$(canonicalize_dir "$package_dir" || true)"
1919+ [[ -n "$real_package_dir" ]] || real_package_dir="$package_dir"
1920+case "$seen" in
1921+*"|${real_package_dir}|"*) continue ;;
1922+esac
1923+ seen="${seen}${real_package_dir}|"
1924+1925+local version=""
1926+ version="$(openclaw_package_version "$package_json")"
1927+printf '%s\t%s\t%s\n' "$version" "$real_package_dir" "$npm_root"
1928+done < <(collect_openclaw_npm_root_candidates)
1929+}
1930+1931+warn_duplicate_openclaw_global_installs() {
1932+local installs=()
1933+local line=""
1934+while IFS= read -r line; do
1935+ [[ -n "$line" ]] && installs+=("$line")
1936+done < <(find_openclaw_global_installs)
1937+1938+if [[ "${#installs[@]}" -le 1 ]]; then
1939+return 0
1940+fi
1941+1942+ ui_warn "Multiple OpenClaw global installs detected"
1943+echo " Different Node/npm environments can run different OpenClaw versions."
1944+1945+local active_node active_npm active_openclaw
1946+ active_node="$(command -v node 2>/dev/null || true)"
1947+ active_npm="$(command -v npm 2>/dev/null || true)"
1948+ active_openclaw="${OPENCLAW_BIN:-}"
1949+if [[ -z "$active_openclaw" ]]; then
1950+ active_openclaw="$(type -P openclaw 2>/dev/null || true)"
1951+fi
1952+echo -e " Active node: ${INFO}${active_node:-none}${NC}"
1953+echo -e " Active npm: ${INFO}${active_npm:-none}${NC}"
1954+echo -e " Active openclaw: ${INFO}${active_openclaw:-none}${NC}"
1955+echo ""
1956+echo " Found installs:"
1957+1958+local install version package_dir npm_root
1959+for install in "${installs[@]}"; do
1960+ IFS=$'\t' read -r version package_dir npm_root <<< "$install"
1961+echo -e " - ${INFO}${version:-unknown}${NC} ${package_dir}"
1962+echo -e " npm root: ${MUTED}${npm_root}${NC}"
1963+done
1964+1965+echo ""
1966+echo " Keep one install source, then remove stale installs with that environment's npm:"
1967+echo " npm uninstall -g openclaw"
1968+}
1969+18281970refresh_shell_command_cache() {
18291971hash -r 2>/dev/null || true
18301972}
@@ -2435,6 +2577,7 @@ main() {
24352577 ui_stage "Finalizing setup"
2436257824372579 OPENCLAW_BIN="$(resolve_openclaw_bin || true)"
2580+ warn_duplicate_openclaw_global_installs || true
2438258124392582# PATH warning: installs can succeed while the user's login shell still lacks npm's global bin dir.
24402583local npm_bin=""
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。