diff --git a/src/auto-reply/reply/strip-inbound-meta.ts b/src/auto-reply/reply/strip-inbound-meta.ts
index aac05f85df9..e4db1246c57 100644
--- a/src/auto-reply/reply/strip-inbound-meta.ts
+++ b/src/auto-reply/reply/strip-inbound-meta.ts
@@ -12,9 +12,6 @@
* do not show AI-facing envelope metadata as user text.
*/
-import { z } from "zod";
-import { safeParseJsonWithSchema } from "../../utils/zod-parse.js";
-
const LEADING_TIMESTAMP_PREFIX_RE = /^\[[A-Za-z]{3} \d{4}-\d{2}-\d{2} \d{2}:\d{2}[^\]]*\] */;
/**
@@ -35,7 +32,6 @@ const UNTRUSTED_CONTEXT_HEADER =
const ACTIVE_MEMORY_OPEN_TAG = "";
const ACTIVE_MEMORY_CLOSE_TAG = "";
const [CONVERSATION_INFO_SENTINEL, SENDER_INFO_SENTINEL] = INBOUND_META_SENTINELS;
-const InboundMetaBlockSchema = z.record(z.string(), z.unknown());
// Pre-compiled fast-path regex — avoids line-by-line parse when no blocks present.
const SENTINEL_FAST_RE = new RegExp(
@@ -64,6 +60,18 @@ function restoreNeutralizedMarkdownFences(value: unknown): unknown {
);
}
+function parseJsonObjectRecord(jsonText: string): Record | null {
+ try {
+ const parsed: unknown = JSON.parse(jsonText);
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
+ return null;
+ }
+ return parsed as Record;
+ } catch {
+ return null;
+ }
+}
+
function parseInboundMetaBlock(lines: string[], sentinel: string): Record | null {
for (let i = 0; i < lines.length; i++) {
if (lines[i]?.trim() !== sentinel) {
@@ -86,7 +94,7 @@ function parseInboundMetaBlock(lines: string[], sentinel: string): Record) : null;
}
return null;
diff --git a/src/entry.version-fast-path.test.ts b/src/entry.version-fast-path.test.ts
index 673a0aef751..0edf58527ba 100644
--- a/src/entry.version-fast-path.test.ts
+++ b/src/entry.version-fast-path.test.ts
@@ -79,6 +79,12 @@ async function importEntry(scope: string) {
);
}
+async function flushEntrySideEffects() {
+ await Promise.resolve();
+ await Promise.resolve();
+ await new Promise((resolve) => setTimeout(resolve, 0));
+}
+
describe("entry root version fast path", () => {
let originalArgv: string[];
let originalGatewayToken: string | undefined;
@@ -109,13 +115,9 @@ describe("entry root version fast path", () => {
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
await importEntry("commit-tagged");
- await vi.waitFor(
- () => {
- expect(logSpy).toHaveBeenCalledWith("OpenClaw 9.9.9-test (abc1234)");
- expect(exitSpy).toHaveBeenCalledWith(0);
- },
- { interval: 1 },
- );
+ await flushEntrySideEffects();
+ expect(logSpy).toHaveBeenCalledWith("OpenClaw 9.9.9-test (abc1234)");
+ expect(exitSpy).toHaveBeenCalledWith(0);
logSpy.mockRestore();
});
@@ -125,13 +127,9 @@ describe("entry root version fast path", () => {
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
await importEntry("plain-version");
- await vi.waitFor(
- () => {
- expect(logSpy).toHaveBeenCalledWith("OpenClaw 9.9.9-test");
- expect(exitSpy).toHaveBeenCalledWith(0);
- },
- { interval: 1 },
- );
+ await flushEntrySideEffects();
+ expect(logSpy).toHaveBeenCalledWith("OpenClaw 9.9.9-test");
+ expect(exitSpy).toHaveBeenCalledWith(0);
logSpy.mockRestore();
});
@@ -141,12 +139,8 @@ describe("entry root version fast path", () => {
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
await importEntry("container-target");
- await vi.waitFor(
- () => {
- expect(runCliMock).toHaveBeenCalledWith(["node", "openclaw", "--version"]);
- },
- { interval: 1 },
- );
+ await flushEntrySideEffects();
+ expect(runCliMock).toHaveBeenCalledWith(["node", "openclaw", "--version"]);
expect(logSpy).not.toHaveBeenCalled();
expect(exitSpy).not.toHaveBeenCalled();
@@ -159,12 +153,8 @@ describe("entry root version fast path", () => {
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
await importEntry("gateway-override");
- await vi.waitFor(
- () => {
- expect(runCliMock).toHaveBeenCalledWith(["node", "openclaw", "--version"]);
- },
- { interval: 1 },
- );
+ await flushEntrySideEffects();
+ expect(runCliMock).toHaveBeenCalledWith(["node", "openclaw", "--version"]);
expect(errorSpy).not.toHaveBeenCalled();
expect(exitSpy).not.toHaveBeenCalled();
diff --git a/ui/src/ui/chat/context-notice.test.ts b/ui/src/ui/chat/context-notice.test.ts
index 48381082d1c..20ae5a9e14c 100644
--- a/ui/src/ui/chat/context-notice.test.ts
+++ b/ui/src/ui/chat/context-notice.test.ts
@@ -17,15 +17,16 @@ import { renderSideResult } from "./side-result-render.ts";
describe("context notice", () => {
afterEach(() => {
- document.documentElement.style.removeProperty("--warn");
- document.documentElement.style.removeProperty("--danger");
+ vi.restoreAllMocks();
resetContextNoticeThemeCacheForTest();
});
it("renders only for fresh high current usage", () => {
const container = document.createElement("div");
- document.documentElement.style.setProperty("--warn", "rgb(1, 2, 3)");
- document.documentElement.style.setProperty("--danger", "tomato");
+ vi.spyOn(window, "getComputedStyle").mockReturnValue({
+ getPropertyValue: (name: string) =>
+ name === "--warn" ? "#010203" : name === "--danger" ? "#040506" : "",
+ } as CSSStyleDeclaration);
resetContextNoticeThemeCacheForTest();
expect(
@@ -58,6 +59,7 @@ describe("context notice", () => {
const notice = container.querySelector(".context-notice");
expect(notice).not.toBeNull();
expect(notice?.style.getPropertyValue("--ctx-color")).toContain("rgb(");
+ expect(notice?.style.getPropertyValue("--ctx-color")).toContain("4, 5, 6");
expect(notice?.style.getPropertyValue("--ctx-color")).not.toContain("NaN");
expect(notice?.style.getPropertyValue("--ctx-bg")).not.toContain("NaN");
diff --git a/ui/src/ui/views/chat.test.ts b/ui/src/ui/views/chat.test.ts
index c8416e30245..9cd466b46d6 100644
--- a/ui/src/ui/views/chat.test.ts
+++ b/ui/src/ui/views/chat.test.ts
@@ -12,6 +12,10 @@ import type { SessionsListResult } from "../types.ts";
import type { MessageGroup } from "../types/chat-types.ts";
import { renderChat, type ChatProps } from "./chat.ts";
+vi.mock("../markdown.ts", () => ({
+ toSanitizedMarkdownHtml: (value: string) => value,
+}));
+
vi.mock("./markdown-sidebar.ts", async () => {
const { html } = await import("lit");
return {