fix(doctor): keep service repair policy scoped

This commit is contained in:
Shakker
2026-04-26 08:46:42 +01:00
parent 6cf5a5fbcd
commit 5c0dc93d1e
4 changed files with 15 additions and 46 deletions

View File

@@ -4,6 +4,10 @@ Docs: https://docs.openclaw.ai
## Unreleased
### Fixes
- Doctor: honor `OPENCLAW_SERVICE_REPAIR_POLICY=external` by reporting gateway service health while skipping service install/start/restart/bootstrap, supervisor rewrites, and legacy service cleanup for externally managed environments. Thanks @shakkernerd.
## 2026.4.25
### Changes
@@ -79,7 +83,6 @@ Docs: https://docs.openclaw.ai
### Fixes
- Doctor: honor `OPENCLAW_SERVICE_REPAIR_POLICY=external` by reporting gateway service health while skipping service install/start/restart/bootstrap, supervisor rewrites, and legacy service cleanup for externally managed environments. Thanks @shakkernerd.
- UI/Windows: quote resolved pnpm `.cmd` launcher paths before spawning UI install/build/test commands so Node installs under `C:\Program Files` no longer fail as `C:\Program`. Fixes #45275. Thanks @Kobevictor, @stoppieboy, and @iubns.
- Codex/agent: translate `--thinking minimal` to `low` for modern Codex models (gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.2) at request build time so the first turn is accepted instead of paying a wasted call + retry-with-low fallback. Older Codex models still receive `minimal` directly. Fixes #71946. Thanks @hclsys.
- Plugins/uninstall: remove tracked plugin files from their recorded managed extensions root even when the current state directory points somewhere else, so `openclaw plugins uninstall --force` does not leave the plugin discoverable. Thanks @shakkernerd.

View File

@@ -335,27 +335,15 @@ export async function maybeRepairGatewayServiceConfig(
return;
}
const repair =
serviceRepairPolicy === "prompt"
? await confirmDoctorServiceRepair(
prompter,
{
message: needsAggressive
? "Overwrite gateway service config with current defaults now?"
: "Update gateway service config to the recommended defaults now?",
initialValue: needsAggressive ? prompter.shouldForce : true,
},
serviceRepairPolicy,
)
: needsAggressive
? await prompter.confirmAggressiveAutoFix({
message: "Overwrite gateway service config with current defaults now?",
initialValue: prompter.shouldForce,
})
: await prompter.confirmAutoFix({
message: "Update gateway service config to the recommended defaults now?",
initialValue: true,
});
const repair = needsAggressive
? await prompter.confirmAggressiveAutoFix({
message: "Overwrite gateway service config with current defaults now?",
initialValue: prompter.shouldForce,
})
: await prompter.confirmAutoFix({
message: "Update gateway service config to the recommended defaults now?",
initialValue: true,
});
if (!repair) {
return;
}

View File

@@ -16,7 +16,6 @@ export type DoctorPrompter = {
confirmAutoFix: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
confirmAggressiveAutoFix: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
confirmRuntimeRepair: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
confirmServiceRepair?: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
select: <T>(params: Parameters<typeof select>[0], fallback: T) => Promise<T>;
shouldRepair: boolean;
shouldForce: boolean;
@@ -89,18 +88,6 @@ export function createDoctorPrompter(params: {
params.runtime,
);
},
confirmServiceRepair: async (p) => {
if (repairMode.nonInteractive || !repairMode.canPrompt) {
return false;
}
return guardCancel(
await confirm({
...p,
message: stylePromptMessage(p.message),
}),
params.runtime,
);
},
select: async <T>(p: Parameters<typeof select>[0], fallback: T) => {
if (!repairMode.canPrompt || repairMode.shouldRepair) {
return fallback;

View File

@@ -1,6 +1,6 @@
import type { DoctorPrompter } from "./doctor-prompter.js";
export type ServiceRepairPolicy = "auto" | "prompt" | "external" | "disabled";
export type ServiceRepairPolicy = "auto" | "external";
export const SERVICE_REPAIR_POLICY_ENV = "OPENCLAW_SERVICE_REPAIR_POLICY";
@@ -13,9 +13,7 @@ export function resolveServiceRepairPolicy(
const value = env[SERVICE_REPAIR_POLICY_ENV]?.trim().toLowerCase();
switch (value) {
case "auto":
case "prompt":
case "external":
case "disabled":
return value;
default:
return "auto";
@@ -25,7 +23,7 @@ export function resolveServiceRepairPolicy(
export function isServiceRepairExternallyManaged(
policy: ServiceRepairPolicy = resolveServiceRepairPolicy(),
): boolean {
return policy === "external" || policy === "disabled";
return policy === "external";
}
export async function confirmDoctorServiceRepair(
@@ -37,12 +35,5 @@ export async function confirmDoctorServiceRepair(
return false;
}
if (policy === "prompt") {
if (!prompter.repairMode.canPrompt) {
return false;
}
return await (prompter.confirmServiceRepair?.(params) ?? prompter.confirmRuntimeRepair(params));
}
return await prompter.confirmRuntimeRepair(params);
}