Skip to content

Commit af2646d

Browse files
fix(installer): align config finalization
1 parent bd524e2 commit af2646d

3 files changed

Lines changed: 101 additions & 3 deletions

File tree

docs/install/installer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Recommended for most interactive installs on macOS/Linux/WSL.
8787
<Step title="Post-install tasks">
8888
- Resolves the just-installed `openclaw` binary for follow-up commands
8989
- For an unconfigured install, starts onboarding before doctor or gateway probes. With `--no-onboard` or no TTY, it prints the command to finish setup later.
90-
- For a configured install, refreshes and restarts a loaded gateway service best-effort and runs doctor. Upgrades also update plugins.
90+
- For a configured install, refreshes and restarts a loaded gateway service best-effort and runs doctor. Upgrades update plugins when possible, or print the manual command in a headless prompt-enabled run.
9191
- When `--verify` runs, it checks the installed version and checks gateway health only after configuration exists.
9292

9393
</Step>

scripts/install.sh

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ resolve_openclaw_effective_home() {
7272
echo "$openclaw_home"
7373
}
7474

75+
resolve_openclaw_user_path() {
76+
local input="$1"
77+
local effective_home
78+
effective_home="$(resolve_openclaw_effective_home)"
79+
if [[ "$input" == "~" ]]; then
80+
echo "$effective_home"
81+
elif [[ "$input" == \~/* ]]; then
82+
echo "${effective_home}${input:1}"
83+
elif [[ "$input" == /* ]]; then
84+
echo "$input"
85+
else
86+
echo "$PWD/$input"
87+
fi
88+
}
89+
7590
DOWNLOADER=""
7691
detect_downloader() {
7792
if command -v curl &> /dev/null; then
@@ -2911,8 +2926,26 @@ maybe_open_dashboard() {
29112926
has_openclaw_config() {
29122927
local effective_home
29132928
effective_home="$(resolve_openclaw_effective_home)"
2914-
local config_path="${OPENCLAW_CONFIG_PATH:-$effective_home/.openclaw/openclaw.json}"
2915-
if [[ -f "${config_path}" || -f "$effective_home/.clawdbot/clawdbot.json" ]]; then
2929+
if [[ -n "${OPENCLAW_CONFIG_PATH:-}" ]]; then
2930+
local config_path
2931+
config_path="$(resolve_openclaw_user_path "$OPENCLAW_CONFIG_PATH")"
2932+
[[ -f "$config_path" ]]
2933+
return
2934+
fi
2935+
2936+
if [[ -n "${OPENCLAW_STATE_DIR:-}" ]]; then
2937+
local state_dir
2938+
state_dir="$(resolve_openclaw_user_path "$OPENCLAW_STATE_DIR")"
2939+
if [[ -f "$state_dir/openclaw.json" || -f "$state_dir/clawdbot.json" ]]; then
2940+
return 0
2941+
fi
2942+
return 1
2943+
fi
2944+
2945+
if [[ -f "$effective_home/.openclaw/openclaw.json" ||
2946+
-f "$effective_home/.openclaw/clawdbot.json" ||
2947+
-f "$effective_home/.clawdbot/openclaw.json" ||
2948+
-f "$effective_home/.clawdbot/clawdbot.json" ]]; then
29162949
return 0
29172950
fi
29182951
return 1

test/scripts/install-sh.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,71 @@ NODE
789789
expect(result?.stderr ?? "").toBe("");
790790
});
791791

792+
it.each(["openclaw.json", "clawdbot.json"])(
793+
"detects %s under OPENCLAW_STATE_DIR",
794+
(configName) => {
795+
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-state-config-"));
796+
const stateDir = join(tmp, "state");
797+
mkdirSync(stateDir, { recursive: true });
798+
writeFileSync(join(stateDir, configName), "{}\n");
799+
800+
let result: ReturnType<typeof runInstallShell> | undefined;
801+
try {
802+
result = runInstallShell(
803+
[
804+
`cd ${JSON.stringify(process.cwd())}`,
805+
`source ${JSON.stringify(SCRIPT_PATH)}`,
806+
'if has_openclaw_config; then printf "configured=1\\n"; else printf "configured=0\\n"; fi',
807+
].join("\n"),
808+
{
809+
OPENCLAW_CONFIG_PATH: undefined,
810+
OPENCLAW_STATE_DIR: stateDir,
811+
TERM: "dumb",
812+
},
813+
);
814+
} finally {
815+
rmSync(tmp, { force: true, recursive: true });
816+
}
817+
818+
expect(result?.status).toBe(0);
819+
expect(result?.stdout).toContain("configured=1");
820+
expect(result?.stderr ?? "").toBe("");
821+
},
822+
);
823+
824+
it("does not fall back to home config when OPENCLAW_STATE_DIR is set", () => {
825+
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-state-override-"));
826+
const home = join(tmp, "home");
827+
const stateDir = join(tmp, "state");
828+
mkdirSync(join(home, ".openclaw"), { recursive: true });
829+
mkdirSync(stateDir, { recursive: true });
830+
writeFileSync(join(home, ".openclaw", "openclaw.json"), "{}\n");
831+
832+
let result: ReturnType<typeof runInstallShell> | undefined;
833+
try {
834+
result = runInstallShell(
835+
[
836+
`cd ${JSON.stringify(process.cwd())}`,
837+
`source ${JSON.stringify(SCRIPT_PATH)}`,
838+
'if has_openclaw_config; then printf "configured=1\\n"; else printf "configured=0\\n"; fi',
839+
].join("\n"),
840+
{
841+
HOME: home,
842+
OPENCLAW_CONFIG_PATH: undefined,
843+
OPENCLAW_HOME: undefined,
844+
OPENCLAW_STATE_DIR: stateDir,
845+
TERM: "dumb",
846+
},
847+
);
848+
} finally {
849+
rmSync(tmp, { force: true, recursive: true });
850+
}
851+
852+
expect(result?.status).toBe(0);
853+
expect(result?.stdout).toContain("configured=0");
854+
expect(result?.stderr ?? "").toBe("");
855+
});
856+
792857
it.each([
793858
{
794859
expected: /No TTY; run .*\/\.local\/bin\/openclaw onboard to finish setup/,

0 commit comments

Comments
 (0)