File size: 2,346 Bytes
f778c12 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import { readConfigFileSnapshot } from "../../config/config.js";
import { resolveFutureConfigActionBlock } from "../../config/future-version-guard.js";
import { renderConfigValidationIssueLines } from "../../config/issue-location.js";
import { isPluginPackagingRuntimeOutputInvalidConfigSnapshot } from "../../config/recovery-policy.js";
import type { ConfigFileSnapshot } from "../../config/types.openclaw.js";
import { formatPluginPackagingRuntimeOutputRecoveryHint } from "../config-recovery-hints.js";
/** Service lifecycle actions; only start/restart bring the gateway up. */
type DaemonServiceAction = "start" | "restart" | "stop" | "uninstall";
type ServiceActionPreflightFailure = {
message: string;
hints?: string[];
};
const ACTION_PROSE: Record<DaemonServiceAction, string> = {
start: "start the gateway service",
restart: "restart the gateway service",
stop: "stop the gateway service",
uninstall: "uninstall the gateway service",
};
function formatPluginPackagingRuntimeOutputRecoveryHints(): string[] {
return formatPluginPackagingRuntimeOutputRecoveryHint().split("\n");
}
/** Best-effort validation before a service action mutates runtime state. */
export async function getServiceActionPreflightFailure(
action: DaemonServiceAction,
): Promise<ServiceActionPreflightFailure | null> {
let snapshot: ConfigFileSnapshot;
try {
// Stop must remain available before Doctor migrates newly installed plugins.
// Core validation and the newer-writer guard still protect service selection.
snapshot = await readConfigFileSnapshot({
observe: false,
pluginValidation: action === "stop" ? "core-only" : undefined,
});
if (snapshot.exists && !snapshot.valid) {
const message =
snapshot.issues.length > 0
? renderConfigValidationIssueLines(snapshot, "").join("\n")
: "Unknown validation issue.";
return {
message,
...(isPluginPackagingRuntimeOutputInvalidConfigSnapshot(snapshot)
? { hints: formatPluginPackagingRuntimeOutputRecoveryHints() }
: {}),
};
}
} catch {
return null;
}
const futureBlock = resolveFutureConfigActionBlock({ action: ACTION_PROSE[action], snapshot });
if (futureBlock) {
return { message: futureBlock.message, hints: futureBlock.hints };
}
return null;
}
|