mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-22 23:41:07 +00:00
fix: isolate CLI startup imports (#50212)
* fix: isolate CLI startup imports * fix: clarify CLI preflight behavior * fix: tighten main-module detection * fix: isolate CLI startup imports (#50212)
This commit is contained in:
@@ -4,8 +4,8 @@ import type { RuntimeEnv } from "../../runtime.js";
|
||||
const loadAndMaybeMigrateDoctorConfigMock = vi.hoisted(() => vi.fn());
|
||||
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../../commands/doctor-config-flow.js", () => ({
|
||||
loadAndMaybeMigrateDoctorConfig: loadAndMaybeMigrateDoctorConfigMock,
|
||||
vi.mock("../../commands/doctor-config-preflight.js", () => ({
|
||||
runDoctorConfigPreflight: loadAndMaybeMigrateDoctorConfigMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
@@ -58,12 +58,17 @@ describe("ensureConfigReady", () => {
|
||||
}
|
||||
|
||||
function setInvalidSnapshot(overrides?: Partial<ReturnType<typeof makeSnapshot>>) {
|
||||
readConfigFileSnapshotMock.mockResolvedValue({
|
||||
const snapshot = {
|
||||
...makeSnapshot(),
|
||||
exists: true,
|
||||
valid: false,
|
||||
issues: [{ path: "channels.whatsapp", message: "invalid" }],
|
||||
...overrides,
|
||||
};
|
||||
readConfigFileSnapshotMock.mockResolvedValue(snapshot);
|
||||
loadAndMaybeMigrateDoctorConfigMock.mockResolvedValue({
|
||||
snapshot,
|
||||
baseConfig: {},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,6 +83,10 @@ describe("ensureConfigReady", () => {
|
||||
vi.clearAllMocks();
|
||||
resetConfigGuardStateForTests();
|
||||
readConfigFileSnapshotMock.mockResolvedValue(makeSnapshot());
|
||||
loadAndMaybeMigrateDoctorConfigMock.mockImplementation(async () => ({
|
||||
snapshot: makeSnapshot(),
|
||||
baseConfig: {},
|
||||
}));
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -94,6 +103,13 @@ describe("ensureConfigReady", () => {
|
||||
])("$name", async ({ commandPath, expectedDoctorCalls }) => {
|
||||
await runEnsureConfigReady(commandPath);
|
||||
expect(loadAndMaybeMigrateDoctorConfigMock).toHaveBeenCalledTimes(expectedDoctorCalls);
|
||||
if (expectedDoctorCalls > 0) {
|
||||
expect(loadAndMaybeMigrateDoctorConfigMock).toHaveBeenCalledWith({
|
||||
migrateState: false,
|
||||
migrateLegacyConfig: false,
|
||||
invalidConfigNote: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("exits for invalid config on non-allowlisted commands", async () => {
|
||||
@@ -132,6 +148,10 @@ describe("ensureConfigReady", () => {
|
||||
it("prevents preflight stdout noise when suppression is enabled", async () => {
|
||||
loadAndMaybeMigrateDoctorConfigMock.mockImplementation(async () => {
|
||||
process.stdout.write("Doctor warnings\n");
|
||||
return {
|
||||
snapshot: makeSnapshot(),
|
||||
baseConfig: {},
|
||||
};
|
||||
});
|
||||
const output = await withCapturedStdout(async () => {
|
||||
await runEnsureConfigReady(["message"], true);
|
||||
@@ -142,6 +162,10 @@ describe("ensureConfigReady", () => {
|
||||
it("allows preflight stdout noise when suppression is not enabled", async () => {
|
||||
loadAndMaybeMigrateDoctorConfigMock.mockImplementation(async () => {
|
||||
process.stdout.write("Doctor warnings\n");
|
||||
return {
|
||||
snapshot: makeSnapshot(),
|
||||
baseConfig: {},
|
||||
};
|
||||
});
|
||||
const output = await withCapturedStdout(async () => {
|
||||
await runEnsureConfigReady(["message"], false);
|
||||
|
||||
@@ -39,22 +39,25 @@ export async function ensureConfigReady(params: {
|
||||
suppressDoctorStdout?: boolean;
|
||||
}): Promise<void> {
|
||||
const commandPath = params.commandPath ?? [];
|
||||
let preflightSnapshot: Awaited<ReturnType<typeof readConfigFileSnapshot>> | null = null;
|
||||
if (!didRunDoctorConfigFlow && shouldMigrateStateFromPath(commandPath)) {
|
||||
didRunDoctorConfigFlow = true;
|
||||
const runDoctorConfigFlow = async () =>
|
||||
(await import("../../commands/doctor-config-flow.js")).loadAndMaybeMigrateDoctorConfig({
|
||||
options: { nonInteractive: true },
|
||||
confirm: async () => false,
|
||||
const runDoctorConfigPreflight = async () =>
|
||||
(await import("../../commands/doctor-config-preflight.js")).runDoctorConfigPreflight({
|
||||
// Keep ordinary CLI startup on the lightweight validation path.
|
||||
migrateState: false,
|
||||
migrateLegacyConfig: false,
|
||||
invalidConfigNote: false,
|
||||
});
|
||||
if (!params.suppressDoctorStdout) {
|
||||
await runDoctorConfigFlow();
|
||||
preflightSnapshot = (await runDoctorConfigPreflight()).snapshot;
|
||||
} else {
|
||||
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
||||
const originalSuppressNotes = process.env.OPENCLAW_SUPPRESS_NOTES;
|
||||
process.stdout.write = (() => true) as unknown as typeof process.stdout.write;
|
||||
process.env.OPENCLAW_SUPPRESS_NOTES = "1";
|
||||
try {
|
||||
await runDoctorConfigFlow();
|
||||
preflightSnapshot = (await runDoctorConfigPreflight()).snapshot;
|
||||
} finally {
|
||||
process.stdout.write = originalStdoutWrite;
|
||||
if (originalSuppressNotes === undefined) {
|
||||
@@ -66,7 +69,7 @@ export async function ensureConfigReady(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const snapshot = await getConfigSnapshot();
|
||||
const snapshot = preflightSnapshot ?? (await getConfigSnapshot());
|
||||
const commandName = commandPath[0];
|
||||
const subcommandName = commandPath[1];
|
||||
const allowInvalid = commandName
|
||||
|
||||
Reference in New Issue
Block a user