fix(config): render warning newlines

This commit is contained in:
Peter Steinberger
2026-04-22 22:01:31 +01:00
parent b6fbf46eca
commit 2c45879120
3 changed files with 42 additions and 2 deletions

View File

@@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai
- Pi embedded runs: pass real built-in tools into Pi session creation and then narrow active tool names after custom tool registration, so the runner and compaction paths compile cleanly and keep OpenClaw-managed custom tool allowlists without feeding string arrays into `createAgentSession`. Thanks @vincentkoc.
- Agents/OpenAI websocket: route native OpenAI websocket metadata and session-header decisions through the shared endpoint classifier so local mocks and custom `models.providers.openai.baseUrl` endpoints stay out of the native OpenAI path consistently across embedded-runner and websocket transport code. Thanks @vincentkoc.
- Config: render validation warnings with real line breaks instead of a literal `\n` sequence in CLI/audit output. Fixes #70140.
- Cron/doctor: repair malformed persisted cron job IDs through `openclaw doctor`, including legacy `jobId`, non-string `id`, and missing `id` rows, so `cron list` no longer needs display-layer coercion for corrupt store data. Fixes #70128.
- Discord: normalize prefixed channel targets only at the thread-binding API boundary, so `sessions_spawn({ runtime: "acp", thread: true })` can create child threads from Discord channels without breaking current-channel ACP bindings. (#68034) Thanks @Zetarcos.
- Discord: harden inbound thread metadata handling against partial Carbon channel getters, so non-command thread messages and queued jobs no longer crash when `name`, `parentId`, `parent`, or `ownerId` requires fetched raw data.

View File

@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import { applyRuntimeLegacyConfigMigrations } from "../commands/doctor/shared/runtime-compat-api.js";
import { createConfigIO } from "./io.js";
import { normalizeExecSafeBinProfilesInConfig } from "./normalize-exec-safe-bin.js";
@@ -70,6 +70,45 @@ describe("config io paths", () => {
});
});
it("logs validation warnings with real line breaks", async () => {
await withTempHome(async (home) => {
const configPath = path.join(home, ".openclaw", "openclaw.json");
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(
configPath,
JSON.stringify(
{
plugins: {
entries: {
"google-antigravity-auth": {
enabled: false,
config: { stale: true },
},
},
},
},
null,
2,
),
);
const logger = {
error: vi.fn(),
warn: vi.fn(),
};
const io = createConfigIO({
configPath,
env: {} as NodeJS.ProcessEnv,
homedir: () => home,
logger,
});
io.loadConfig();
expect(logger.warn).toHaveBeenCalledWith(expect.stringMatching(/^Config warnings:\n- /));
expect(logger.warn).not.toHaveBeenCalledWith(expect.stringContaining("Config warnings:\\n"));
});
});
it("normalizes safe-bin config entries at config load time", async () => {
const cfg = {
tools: {

View File

@@ -1198,7 +1198,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) {
`- ${sanitizeTerminalText(iss.path || "<root>")}: ${sanitizeTerminalText(iss.message)}`,
)
.join("\n");
deps.logger.warn(`Config warnings:\\n${details}`);
deps.logger.warn(`Config warnings:\n${details}`);
}
warnIfConfigFromFuture(validated.config, deps.logger);
const cfg = materializeRuntimeConfig(validated.config, "load");