test: remove low-value implementation assertions (#121085)

* test: remove low-value implementation assertions

* test: refresh native i18n inventory
This commit is contained in:
Peter Steinberger
2026-08-09 08:48:48 -07:00
committed by GitHub
parent e750dab6d1
commit 0303af17f3
61 changed files with 86 additions and 1688 deletions
-8
View File
@@ -32561,14 +32561,6 @@
"surface": "apple",
"id": "native.apple.e7d1ee5662c1d646"
},
{
"kind": "ui-call",
"line": 1020,
"path": "apps/macos/Sources/OpenClaw/DebugSettings.swift",
"source": "Test",
"surface": "apple",
"id": "native.apple.0397fa643df26663"
},
{
"kind": "ui-named-argument",
"line": 74,
@@ -973,53 +973,4 @@ struct DebugSettings_Previews: PreviewProvider {
.frame(width: SettingsTab.windowWidth, height: SettingsTab.windowHeight)
}
}
@MainActor
extension DebugSettings {
static func exerciseForTesting() async {
let view = DebugSettings(state: .preview)
view.gatewayRootInput = "/tmp/openclaw"
view.sessionStorePath = "/tmp/sessions.json"
view.sessionStoreSaveError = "Save failed"
view.debugSendInFlight = true
view.debugSendStatus = "Sent"
view.debugSendError = "Failed"
view.portCheckInFlight = true
view.portReports = [
DebugActions.PortReport(
port: GatewayEnvironment.gatewayPort(),
expected: "Gateway websocket (node/tsx)",
status: .missing("Missing"),
listeners: []),
]
view.portKillStatus = "Killed"
view.pendingKill = DebugActions.PortListener(
pid: 1,
command: "node",
fullCommand: "node",
user: nil,
expected: true)
view.canvasSessionKey = "main"
view.canvasStatus = "Canvas ok"
view.canvasError = "Canvas error"
view.canvasEvalJS = "document.title"
view.canvasEvalResult = "Canvas"
view.canvasSnapshotPath = "/tmp/snapshot.png"
_ = view.body
_ = view.header
_ = view.overviewSection
_ = view.appInfoSection
_ = view.gatewaySection
_ = view.logsSection
_ = view.portsSection
_ = view.pathsSection
_ = view.quickActionsSection
_ = view.canvasSection
_ = view.experimentsSection
_ = view.gridLabel("Test")
view.loadSessionStorePath()
}
}
#endif
@@ -937,36 +937,4 @@ struct VoiceWakeSettings_Previews: PreviewProvider {
.frame(width: SettingsTab.windowWidth, height: SettingsTab.windowHeight)
}
}
@MainActor
extension VoiceWakeSettings {
static func exerciseForTesting() {
let state = AppState(preview: true)
state.swabbleEnabled = true
state.voicePushToTalkEnabled = true
state.swabbleTriggerWords = ["Claude", "Hey"]
let view = VoiceWakeSettings(state: state, isActive: true)
view.availableMics = [AudioInputDevice(uid: "mic-1", name: "Built-in")]
view.availableLocales = [Locale(identifier: "en_US")]
view.meterLevel = 0.42
view.meterError = "No input"
view.testState = .detected("ok")
view.isTesting = true
view.triggerEntries = [TriggerEntry(id: UUID(), value: "Claude")]
_ = view.body
_ = view.localePicker
_ = view.micPicker
_ = view.levelMeter
_ = view.triggerTable
_ = view.chimeSection
_ = view.unsupportedVoiceWakePanel
view.addWord()
if let entryId = view.triggerEntries.first?.id {
view.removeWord(id: entryId)
}
}
}
#endif
@@ -93,12 +93,4 @@ struct LowCoverageViewSmokeTests {
DockIconManager.shared.updateDockVisibility()
DockIconManager.shared.temporarilyShowDock()
}
@Test func `voice wake settings exercises helpers`() {
VoiceWakeSettings.exerciseForTesting()
}
@Test func `debug settings exercises helpers`() async {
await DebugSettings.exerciseForTesting()
}
}
+3 -17
View File
@@ -1,5 +1,4 @@
// Chutes tests cover models plugin behavior.
import { expectDefined } from "@openclaw/normalization-core";
import { clearLiveCatalogCacheForTests } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { CHUTES_DEFAULT_MODEL_ID } from "./api.js";
@@ -98,22 +97,6 @@ describe("chutes-models", () => {
clearLiveCatalogCacheForTests();
});
it("builds static definitions with required fields", () => {
const entry = expectDefined(CHUTES_MODEL_CATALOG[0], "first Chutes catalog model");
const def = entry;
expect(def.id).toBe(entry.id);
expect(def.name).toBe(entry.name);
expect(def.reasoning).toBe(entry.reasoning);
expect(def.input).toEqual(entry.input);
expect(def.cost).toEqual(entry.cost);
expect(def.contextWindow).toBe(entry.contextWindow);
expect(def.maxTokens).toBe(entry.maxTokens);
if (!def.compat) {
throw new Error("expected Chutes model compat");
}
expect(def.compat.supportsUsageInStreaming).toBe(false);
});
it("keeps image-capable fallback models in the runtime catalog", () => {
const visionModelIds = ["moonshotai/Kimi-K2.6-TEE", "Qwen/Qwen3.6-27B-TEE"];
for (const id of visionModelIds) {
@@ -131,6 +114,9 @@ describe("chutes-models", () => {
const runtimeIds = CHUTES_MODEL_CATALOG.map((model) => model.id);
expect(manifestIds).toEqual(EXPECTED_STATIC_MODEL_IDS);
expect(runtimeIds).toEqual(EXPECTED_STATIC_MODEL_IDS);
expect(
CHUTES_MODEL_CATALOG.every((model) => model.compat?.supportsUsageInStreaming === false),
).toBe(true);
expect(CHUTES_DEFAULT_MODEL_ID).toBe(manifest.modelCatalog.providers.chutes.defaultModel);
expect(manifest.modelCatalog.providers.chutes.defaultModel).toBe("zai-org/GLM-5.2-TEE");
expect(
@@ -922,6 +922,54 @@ describe("comfy image-generation provider", () => {
expect(release).toHaveBeenCalledTimes(1);
});
it("bounds oversized local workflow submit responses and releases the request", async () => {
setComfyFetchGuardForTesting(fetchWithSsrFGuardMock);
const chunk = new Uint8Array(1024 * 1024);
const totalBytes = 32 * chunk.length;
let bytesPulled = 0;
let canceled = false;
const release = vi.fn(async () => {});
fetchWithSsrFGuardMock.mockResolvedValueOnce({
response: new Response(
new ReadableStream<Uint8Array>({
pull(controller) {
if (bytesPulled >= totalBytes) {
controller.close();
return;
}
bytesPulled += chunk.length;
controller.enqueue(chunk);
},
cancel() {
canceled = true;
},
}),
{ status: 200, headers: { "content-type": "application/json" } },
),
release,
});
const provider = buildComfyImageGenerationProvider();
await expect(
provider.generateImage({
provider: "comfy",
model: "workflow",
prompt: "draw a lobster",
cfg: buildComfyConfig({
workflow: {
"6": { inputs: { text: "" } },
"9": { inputs: {} },
},
promptNodeId: "6",
outputNodeId: "9",
}),
}),
).rejects.toThrow("Comfy workflow submit failed: JSON response exceeds 16777216 bytes");
expect(canceled).toBe(true);
expect(bytesPulled).toBeLessThan(totalBytes);
expect(release).toHaveBeenCalledTimes(1);
});
it("uploads reference images for local edit workflows", async () => {
setComfyFetchGuardForTesting(fetchWithSsrFGuardMock);
fetchWithSsrFGuardMock
-172
View File
@@ -1,172 +0,0 @@
// Comfy tests cover workflow-runtime bounded-read delegation.
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { setComfyFetchGuardForTesting } from "./test-support.js";
import { readJsonResponseForTest } from "./workflow-runtime.js";
describe("readJsonResponse bounded read (readProviderJsonResponse delegation)", () => {
const fetchMock = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
setComfyFetchGuardForTesting(null);
vi.restoreAllMocks();
});
it("cancels oversized JSON body via the 16 MiB provider cap", async () => {
const ONE_MIB = 1024 * 1024;
const TOTAL_CHUNKS = 32;
const chunk = new Uint8Array(ONE_MIB);
let bytesPulled = 0;
let canceled = false;
const oversizedJson = new Response(
new ReadableStream<Uint8Array>({
pull(controller) {
if (bytesPulled >= TOTAL_CHUNKS * ONE_MIB) {
controller.close();
return;
}
bytesPulled += chunk.length;
controller.enqueue(chunk);
},
cancel() {
canceled = true;
},
}),
{ status: 200, headers: { "Content-Type": "application/json" } },
);
const release = vi.fn(async () => {});
fetchMock.mockResolvedValueOnce({ response: oversizedJson, release });
setComfyFetchGuardForTesting(fetchMock);
await expect(
readJsonResponseForTest({
url: "http://127.0.0.1:9999/test",
init: { method: "GET" },
timeoutMs: 10_000,
auditContext: "comfy-test",
errorPrefix: "Comfy test failed",
}),
).rejects.toThrow(/JSON response exceeds 16777216 bytes/);
expect(canceled).toBe(true);
expect(bytesPulled).toBeLessThan(TOTAL_CHUNKS * ONE_MIB);
expect(release).toHaveBeenCalledOnce();
});
it("rejects oversized body with correct error prefix", async () => {
const ONE_MIB = 1024 * 1024;
const chunk = new Uint8Array(ONE_MIB);
let bytesPulled = 0;
let canceled = false;
const oversizedJson = new Response(
new ReadableStream<Uint8Array>({
pull(controller) {
if (bytesPulled >= 32 * ONE_MIB) {
controller.close();
return;
}
bytesPulled += chunk.length;
controller.enqueue(chunk);
},
cancel() {
canceled = true;
},
}),
{ status: 200, headers: { "Content-Type": "application/json" } },
);
const release = vi.fn(async () => {});
fetchMock.mockResolvedValueOnce({ response: oversizedJson, release });
setComfyFetchGuardForTesting(fetchMock);
await expect(
readJsonResponseForTest({
url: "http://127.0.0.1:9999/test",
init: { method: "GET" },
timeoutMs: 10_000,
auditContext: "comfy-test",
errorPrefix: "Comfy test failed",
}),
).rejects.toThrow(/^Comfy test failed: JSON response exceeds 16777216 bytes/);
expect(canceled).toBe(true);
expect(bytesPulled).toBeLessThan(32 * ONE_MIB);
});
it("parses small valid JSON body (negative control)", async () => {
const smallBody = { status: "ok" };
const release = vi.fn(async () => {});
fetchMock.mockResolvedValueOnce({
response: new Response(JSON.stringify(smallBody), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
release,
});
setComfyFetchGuardForTesting(fetchMock);
const result = await readJsonResponseForTest<{ status: string }>({
url: "http://127.0.0.1:9999/test",
init: { method: "GET" },
timeoutMs: 10_000,
auditContext: "comfy-test",
errorPrefix: "Comfy test failed",
});
expect(result.status).toBe("ok");
expect(release).toHaveBeenCalledOnce();
});
it("parses valid JSON with expected comfy response shape (happy path)", async () => {
const comfyResponse = { prompt_id: "abc-123" };
const release = vi.fn(async () => {});
fetchMock.mockResolvedValueOnce({
response: new Response(JSON.stringify(comfyResponse), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
release,
});
setComfyFetchGuardForTesting(fetchMock);
const result = await readJsonResponseForTest<{ prompt_id: string }>({
url: "http://127.0.0.1:9999/test",
init: { method: "GET" },
timeoutMs: 10_000,
auditContext: "comfy-test",
errorPrefix: "Comfy test failed",
});
expect(result.prompt_id).toBe("abc-123");
expect(release).toHaveBeenCalledOnce();
});
it("propagates HTTP error status before reading body", async () => {
const release = vi.fn(async () => {});
fetchMock.mockResolvedValueOnce({
response: new Response(null, { status: 500, statusText: "Internal Server Error" }),
release,
});
setComfyFetchGuardForTesting(fetchMock);
await expect(
readJsonResponseForTest({
url: "http://127.0.0.1:9999/test",
init: { method: "GET" },
timeoutMs: 10_000,
auditContext: "comfy-test",
errorPrefix: "Comfy test failed",
}),
).rejects.toThrow(/Comfy test failed/);
expect(release).toHaveBeenCalledOnce();
});
});
-3
View File
@@ -347,9 +347,6 @@ async function readJsonResponse<T>(params: {
}
}
/** @internal Test-only export. */
export const readJsonResponseForTest = readJsonResponse;
function resolveFileExtension(params: { fileName?: string; mimeType?: string }): string {
const extension = extensionForMime(params.mimeType);
if (extension) {
+3 -3
View File
@@ -16,9 +16,9 @@ type CuaDriverSdk = Pick<
export type CuaToolResult = import("@trycua/cua-driver").ToolResult;
// These numeric values are part of the pinned 0.14.1 SDK contract and are also
// frozen in driver-contract-fixtures. Keeping them local avoids loading the
// native library while OpenClaw is only registering the bundled plugin.
// These numeric values are part of the pinned 0.14.1 SDK contract. Keeping
// them local avoids loading the native library while OpenClaw is only
// registering the bundled plugin.
export const ClickButton = {
Left: 0 as DriverClickButton,
Right: 1 as DriverClickButton,
@@ -1,207 +0,0 @@
/**
* Frozen CUA Driver 0.14.1 desktop contract fixtures used by the CUA fulfiller tests.
*
* Evidence: cua-driver-rs-v0.14.1 (41ae29b44b49b68c6e01c934fffbbe74d22e26fb)
* and @trycua/cua-driver@0.14.1. The SDK declarations name these methods with
* camelCase and encode DesktopScope.Desktop as 0; MCP uses the snake_case tool
* names and the "desktop" scope string below.
*/
export const CUA_DRIVER_0141_CONTRACT = {
version: "0.14.1",
releaseTag: "cua-driver-rs-v0.14.1",
releaseCommit: "41ae29b44b49b68c6e01c934fffbbe74d22e26fb",
npmIntegrity:
"sha512-/o16k+vcTbdqwmvQqgFCKzrYksSQHz282qO8RkpD67GQoY4Vp3pyDndQexRJ8AbzNQpUt1bIXSAAaFBaMad6rg==",
serverName: "cua-driver",
capabilityVersion: "1",
schemaVersion: "1",
} as const;
export const CUA_DRIVER_0141_SDK_DESKTOP_SCOPE = 0 as const;
export const CUA_DRIVER_0141_SDK_FIXTURES = {
getDesktopState: {},
getScreenSize: {},
getCursorPosition: {},
click: {
x: 960,
y: 540,
scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE,
button: 0,
count: 1,
},
drag: {
fromX: 100,
fromY: 200,
toX: 960,
toY: 540,
scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE,
durationMs: 500n,
},
moveCursor: { x: 960, y: 540, scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE },
scroll: {
x: 960,
y: 540,
direction: 1,
scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE,
by: 0,
amount: 3n,
},
typeText: { text: "hello", scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE },
pressKey: {
key: "enter",
scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE,
modifiers: ["shift"],
},
hotkey: { keys: ["ctrl", "c"], scope: CUA_DRIVER_0141_SDK_DESKTOP_SCOPE },
} as const;
export const CUA_DRIVER_0141_MCP_FIXTURES = {
serverInfo: {
name: CUA_DRIVER_0141_CONTRACT.serverName,
version: CUA_DRIVER_0141_CONTRACT.version,
},
toolsList: {
capability_version: CUA_DRIVER_0141_CONTRACT.capabilityVersion,
schema_version: CUA_DRIVER_0141_CONTRACT.schemaVersion,
},
desktopState: {
platform: "linux",
display: "primary",
screenshot_width: 3840,
screenshot_height: 2160,
screen_width: 3840,
screen_height: 2160,
scale_factor: 1,
screenshot_mime_type: "image/png",
},
screenSize: { width: 3840, height: 2160, scale_factor: 1 },
} as const;
export const CUA_DRIVER_0141_FAILURE_FIXTURES = {
invalidArguments: {
isError: true,
content: [{ type: "text", text: "click: invalid arguments: missing field `x`" }],
structuredContent: { code: "invalid_arguments", tool: "click" },
},
refusal: {
isError: true,
content: [{ type: "text", text: "desktop input is unavailable" }],
structuredContent: { code: "desktop_unavailable" },
},
} as const;
export const CUA_DRIVER_0141_GENERATION_FIXTURE = {
initial: "connection-e8dcf30c",
reconnected: "connection-7857c486",
} as const;
export const CUA_DRIVER_0141_DESKTOP_OPERATIONS = [
"get_desktop_state",
"get_screen_size",
"get_cursor_position",
"click",
"drag",
"move_cursor",
"scroll",
"type_text",
"press_key",
"hotkey",
] as const;
type CuaDriver0141DesktopOperation = (typeof CUA_DRIVER_0141_DESKTOP_OPERATIONS)[number];
type CuaDriver0141SdkMethod = keyof typeof CUA_DRIVER_0141_SDK_FIXTURES;
export const CUA_DRIVER_0141_COMPUTER_ACT_PARITY = [
{
operation: "get_desktop_state",
sdkMethod: "getDesktopState",
disposition: "screen.snapshot",
computerActions: ["screenshot"],
},
{
operation: "get_screen_size",
sdkMethod: "getScreenSize",
disposition: "frame verification",
computerActions: [],
},
{
operation: "get_cursor_position",
sdkMethod: "getCursorPosition",
disposition: "not projected",
computerActions: [],
},
{
operation: "click",
sdkMethod: "click",
disposition: "computer.act",
computerActions: ["left_click", "right_click", "middle_click", "double_click", "triple_click"],
},
{
operation: "drag",
sdkMethod: "drag",
disposition: "computer.act",
computerActions: ["left_click_drag"],
},
{
operation: "move_cursor",
sdkMethod: "moveCursor",
disposition: "computer.act",
computerActions: ["mouse_move"],
},
{
operation: "scroll",
sdkMethod: "scroll",
disposition: "computer.act",
computerActions: ["scroll"],
},
{
operation: "type_text",
sdkMethod: "typeText",
disposition: "computer.act",
computerActions: ["type"],
},
{
operation: "press_key",
sdkMethod: "pressKey",
disposition: "computer.act",
computerActions: ["key"],
},
{
operation: "hotkey",
sdkMethod: "hotkey",
disposition: "not projected",
computerActions: [],
},
] as const satisfies readonly {
operation: CuaDriver0141DesktopOperation;
sdkMethod: CuaDriver0141SdkMethod;
disposition: "screen.snapshot" | "frame verification" | "computer.act" | "not projected";
computerActions: readonly string[];
}[];
export const COMPUTER_ACT_ACTION_FIXTURES = [
"screenshot",
"left_click",
"right_click",
"middle_click",
"double_click",
"triple_click",
"mouse_move",
"left_click_drag",
"left_mouse_down",
"left_mouse_up",
"scroll",
"type",
"key",
"hold_key",
"wait",
] as const;
export const CUA_DRIVER_0141_UNSUPPORTED_COMPUTER_ACT_ACTIONS = [
"hold_key",
"left_mouse_down",
"left_mouse_up",
] as const;
export const CUA_DRIVER_0141_CORE_LOCAL_COMPUTER_ACT_ACTIONS = ["wait"] as const;
@@ -1,76 +0,0 @@
import { describe, expect, it } from "vitest";
import {
COMPUTER_ACT_ACTION_FIXTURES,
CUA_DRIVER_0141_COMPUTER_ACT_PARITY,
CUA_DRIVER_0141_CONTRACT,
CUA_DRIVER_0141_CORE_LOCAL_COMPUTER_ACT_ACTIONS,
CUA_DRIVER_0141_DESKTOP_OPERATIONS,
CUA_DRIVER_0141_FAILURE_FIXTURES,
CUA_DRIVER_0141_GENERATION_FIXTURE,
CUA_DRIVER_0141_MCP_FIXTURES,
CUA_DRIVER_0141_SDK_DESKTOP_SCOPE,
CUA_DRIVER_0141_SDK_FIXTURES,
CUA_DRIVER_0141_UNSUPPORTED_COMPUTER_ACT_ACTIONS,
} from "./driver-contract-fixtures.test-fixtures.js";
describe("cua-driver 0.14.1 computer.act parity fixtures", () => {
it("pins the released CUA driver identity and SDK desktop-scope representation", () => {
expect(CUA_DRIVER_0141_CONTRACT).toMatchObject({
version: "0.14.1",
releaseTag: "cua-driver-rs-v0.14.1",
releaseCommit: "41ae29b44b49b68c6e01c934fffbbe74d22e26fb",
serverName: "cua-driver",
capabilityVersion: "1",
schemaVersion: "1",
});
expect(CUA_DRIVER_0141_SDK_FIXTURES.click.scope).toBe(CUA_DRIVER_0141_SDK_DESKTOP_SCOPE);
expect(CUA_DRIVER_0141_SDK_FIXTURES.drag.durationMs).toBe(500n);
expect(Object.keys(CUA_DRIVER_0141_SDK_FIXTURES)).toEqual(
CUA_DRIVER_0141_COMPUTER_ACT_PARITY.map(({ sdkMethod }) => sdkMethod),
);
expect(CUA_DRIVER_0141_MCP_FIXTURES.desktopState.screenshot_mime_type).toBe("image/png");
});
it("freezes driver failures and reconnect generations for later runtime migration", () => {
expect(CUA_DRIVER_0141_FAILURE_FIXTURES.invalidArguments).toMatchObject({
isError: true,
structuredContent: { code: "invalid_arguments", tool: "click" },
});
expect(CUA_DRIVER_0141_FAILURE_FIXTURES.refusal).toMatchObject({
isError: true,
structuredContent: { code: "desktop_unavailable" },
});
expect(typeof CUA_DRIVER_0141_GENERATION_FIXTURE.initial).toBe("string");
expect(CUA_DRIVER_0141_GENERATION_FIXTURE.reconnected).not.toBe(
CUA_DRIVER_0141_GENERATION_FIXTURE.initial,
);
});
it("classifies every frozen desktop operation and computer action exactly once", () => {
const operations = CUA_DRIVER_0141_COMPUTER_ACT_PARITY.map(({ operation }) => operation);
expect(new Set(operations).size).toBe(operations.length);
expect(new Set(operations)).toEqual(new Set(CUA_DRIVER_0141_DESKTOP_OPERATIONS));
const classifiedActions = [
...CUA_DRIVER_0141_COMPUTER_ACT_PARITY.flatMap(({ computerActions }) => computerActions),
...CUA_DRIVER_0141_UNSUPPORTED_COMPUTER_ACT_ACTIONS,
...CUA_DRIVER_0141_CORE_LOCAL_COMPUTER_ACT_ACTIONS,
];
expect(classifiedActions).toHaveLength(COMPUTER_ACT_ACTION_FIXTURES.length);
expect(new Set(classifiedActions).size).toBe(COMPUTER_ACT_ACTION_FIXTURES.length);
expect(new Set(classifiedActions)).toEqual(new Set(COMPUTER_ACT_ACTION_FIXTURES));
});
it("keeps the existing model-facing projection narrow", () => {
expect(
CUA_DRIVER_0141_COMPUTER_ACT_PARITY.filter(
({ disposition }) => disposition === "computer.act",
).map(({ operation }) => operation),
).toEqual(["click", "drag", "move_cursor", "scroll", "type_text", "press_key"]);
expect(
CUA_DRIVER_0141_COMPUTER_ACT_PARITY.filter(
({ disposition }) => disposition === "not projected",
).map(({ operation }) => operation),
).toEqual(["get_cursor_position", "hotkey"]);
});
});
-17
View File
@@ -1,17 +0,0 @@
// Diffs tests cover manifest plugin behavior.
import fs from "node:fs";
import { describe, expect, it } from "vitest";
type DiffsPackageManifest = {
dependencies?: Record<string, string>;
};
describe("diffs package manifest", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as DiffsPackageManifest;
expect(packageJson.dependencies).toHaveProperty("@pierre/diffs");
});
});
-1
View File
@@ -1,6 +1,5 @@
// Huggingface API module exposes the plugin public contract.
export {
buildHuggingfaceModelDefinition,
discoverHuggingfaceModels,
HUGGINGFACE_BASE_URL,
HUGGINGFACE_MODEL_CATALOG,
-13
View File
@@ -3,7 +3,6 @@ import { expectDefined } from "@openclaw/normalization-core";
import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
buildHuggingfaceModelDefinition,
discoverHuggingfaceModels,
HUGGINGFACE_MODEL_CATALOG,
isHuggingfacePolicyLocked,
@@ -42,18 +41,6 @@ afterEach(() => {
});
describe("huggingface models", () => {
it("buildHuggingfaceModelDefinition returns config with required fields", () => {
const entry = expectDefined(HUGGINGFACE_MODEL_CATALOG[0], "first Hugging Face catalog model");
const def = buildHuggingfaceModelDefinition(entry);
expect(def.id).toBe(entry.id);
expect(def.name).toBe(entry.name);
expect(def.reasoning).toBe(entry.reasoning);
expect(def.input).toEqual(entry.input);
expect(def.cost).toEqual(entry.cost);
expect(def.contextWindow).toBe(entry.contextWindow);
expect(def.maxTokens).toBe(entry.maxTokens);
});
it("does not advertise the retired Llama 3.3 Turbo route", () => {
expect(HUGGINGFACE_MODEL_CATALOG.map((model) => model.id)).not.toContain(
"meta-llama/Llama-3.3-70B-Instruct-Turbo",
+4 -18
View File
@@ -77,20 +77,6 @@ export function isHuggingfacePolicyLocked(modelRef: string): boolean {
return HUGGINGFACE_POLICY_SUFFIXES.some((suffix) => ref.endsWith(`:${suffix}`) || ref === suffix);
}
export function buildHuggingfaceModelDefinition(
model: (typeof HUGGINGFACE_MODEL_CATALOG)[number],
): ModelDefinitionConfig {
return {
id: model.id,
name: model.name,
reasoning: model.reasoning,
input: model.input,
cost: model.cost,
contextWindow: model.contextWindow,
maxTokens: model.maxTokens,
};
}
function isReasoningModelHeuristic(modelId: string): boolean {
const lower = normalizeLowercaseStringOrEmpty(modelId);
return (
@@ -147,7 +133,7 @@ function projectHuggingfaceModels(rows: readonly unknown[]): ModelDefinitionConf
const catalogEntry = catalogById.get(id);
if (catalogEntry) {
models.push(buildHuggingfaceModelDefinition(catalogEntry));
models.push(Object.assign({}, catalogEntry));
continue;
}
@@ -176,12 +162,12 @@ export async function discoverHuggingfaceModels(
timeoutMs = HUGGINGFACE_DISCOVERY_TIMEOUT_MS,
): Promise<ModelDefinitionConfig[]> {
if (isHuggingfaceModelDiscoveryTestEnvironment()) {
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
return HUGGINGFACE_MODEL_CATALOG.map((model) => Object.assign({}, model));
}
const trimmedKey = apiKey?.trim();
if (!trimmedKey) {
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
return HUGGINGFACE_MODEL_CATALOG.map((model) => Object.assign({}, model));
}
const requestTimeoutMs = resolveTimerTimeoutMs(timeoutMs, HUGGINGFACE_DISCOVERY_TIMEOUT_MS);
@@ -189,7 +175,7 @@ export async function discoverHuggingfaceModels(
providerId: "huggingface",
endpoint: `${HUGGINGFACE_BASE_URL}/models`,
providerConfig: { baseUrl: HUGGINGFACE_BASE_URL, api: "openai-completions" },
models: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition),
models: HUGGINGFACE_MODEL_CATALOG.map((model) => Object.assign({}, model)),
discoveryApiKey: trimmedKey,
signal: AbortSignal.timeout(requestTimeoutMs),
timeoutMs: requestTimeoutMs,
+2 -6
View File
@@ -1,10 +1,6 @@
// Huggingface setup module handles plugin onboarding behavior.
import { createModelCatalogPresetAppliers } from "openclaw/plugin-sdk/provider-onboard";
import {
buildHuggingfaceModelDefinition,
HUGGINGFACE_BASE_URL,
HUGGINGFACE_MODEL_CATALOG,
} from "./models.js";
import { HUGGINGFACE_BASE_URL, HUGGINGFACE_MODEL_CATALOG } from "./models.js";
export const HUGGINGFACE_DEFAULT_MODEL_REF = "huggingface/deepseek-ai/DeepSeek-R1";
@@ -14,7 +10,7 @@ export const { applyConfig: applyHuggingfaceConfig } = createModelCatalogPresetA
providerId: "huggingface",
api: "openai-completions",
baseUrl: HUGGINGFACE_BASE_URL,
catalogModels: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition),
catalogModels: HUGGINGFACE_MODEL_CATALOG.map((model) => Object.assign({}, model)),
aliases: [{ modelRef: HUGGINGFACE_DEFAULT_MODEL_REF, alias: "Hugging Face" }],
}),
});
+1 -2
View File
@@ -1,7 +1,6 @@
// Huggingface provider module implements model/runtime integration.
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-types";
import {
buildHuggingfaceModelDefinition,
discoverHuggingfaceModels,
HUGGINGFACE_BASE_URL,
HUGGINGFACE_MODEL_CATALOG,
@@ -14,7 +13,7 @@ export async function buildHuggingfaceProvider(
const models =
resolvedSecret !== ""
? await discoverHuggingfaceModels(resolvedSecret)
: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
: HUGGINGFACE_MODEL_CATALOG.map((model) => Object.assign({}, model));
return {
baseUrl: HUGGINGFACE_BASE_URL,
api: "openai-completions",
+4 -4
View File
@@ -1,6 +1,6 @@
// Telegram tests cover plain-text chunk-splitting behavior.
import { describe, expect, it } from "vitest";
import { splitTelegramPlainTextChunksForTests } from "./send.js";
import { splitTelegramPlainTextChunks } from "./rich-plain-fallback.js";
function containsLoneSurrogate(text: string): boolean {
for (let index = 0; index < text.length; index += 1) {
@@ -24,7 +24,7 @@ describe("splitTelegramPlainTextChunks", () => {
it("does not split an astral char across the chunk boundary", () => {
// Emoji surrogate pair straddles index 10 (limit): high at 9, low at 10.
const input = `${"A".repeat(9)}😀${"B".repeat(20)}`;
const chunks = splitTelegramPlainTextChunksForTests(input, 10);
const chunks = splitTelegramPlainTextChunks(input, 10);
expect(chunks.length).toBeGreaterThan(1);
expect(chunks.join("")).toBe(input);
for (const chunk of chunks) {
@@ -37,7 +37,7 @@ describe("splitTelegramPlainTextChunks", () => {
// causing the while-loop to spin forever. The surrogate pair must be
// emitted as a unit (2 code units) so the loop always advances.
const input = "😀X";
const chunks = splitTelegramPlainTextChunksForTests(input, 1);
const chunks = splitTelegramPlainTextChunks(input, 1);
expect(chunks.join("")).toBe(input);
for (const chunk of chunks) {
expect(containsLoneSurrogate(chunk)).toBe(false);
@@ -48,7 +48,7 @@ describe("splitTelegramPlainTextChunks", () => {
// 'A' + emoji: with limit=1, second iteration starts at index 1 (high
// surrogate) — same stall condition as above, now mid-string.
const input = "A😀B";
const chunks = splitTelegramPlainTextChunksForTests(input, 1);
const chunks = splitTelegramPlainTextChunks(input, 1);
expect(chunks.join("")).toBe(input);
for (const chunk of chunks) {
expect(containsLoneSurrogate(chunk)).toBe(false);
-8
View File
@@ -1,5 +1,3 @@
import { splitTelegramPlainTextChunks } from "./rich-plain-fallback.js";
export { buildInlineKeyboard } from "./inline-keyboard.js";
export {
resetTelegramClientOptionsCacheForTests,
@@ -21,9 +19,3 @@ export { editMessageReplyMarkupTelegram, editMessageTelegram } from "./send-edit
export { sendLocationTelegram } from "./send-location.js";
export { sendMessageTelegram } from "./send-message.js";
export { sendPollTelegram, sendStickerTelegram } from "./send-special.js";
// Test-only handle: the plain-text splitter is internal, but its surrogate-safe
// chunk boundary needs direct behavior coverage.
export function splitTelegramPlainTextChunksForTests(text: string, limit: number): string[] {
return splitTelegramPlainTextChunks(text, limit);
}
-12
View File
@@ -2,10 +2,6 @@
import fs from "node:fs";
import { describe, expect, it } from "vitest";
type TokenjuicePackageManifest = {
dependencies?: Record<string, string>;
};
type TokenjuicePluginManifest = {
contracts?: {
agentToolResultMiddleware?: string[];
@@ -13,14 +9,6 @@ type TokenjuicePluginManifest = {
};
describe("tokenjuice package manifest", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("./package.json", import.meta.url), "utf8"),
) as TokenjuicePackageManifest;
expect(packageJson.dependencies?.tokenjuice).toBe("0.8.1");
});
it("declares runtime-neutral tool result middleware ownership in the manifest contract", () => {
const manifest = JSON.parse(
fs.readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8"),
-13
View File
@@ -1,5 +1,4 @@
// Venice tests cover models plugin behavior.
import { expectDefined } from "@openclaw/normalization-core";
import {
buildOpenAICompatibleLiveModelProviderConfig,
clearLiveCatalogCacheForTests,
@@ -131,18 +130,6 @@ describe("venice-models", () => {
restoreDiscoveryEnv();
});
it("builds static definitions with required fields", () => {
const entry = expectDefined(VENICE_MODEL_CATALOG[0], "first Venice catalog model");
const def = entry;
expect(def.id).toBe(entry.id);
expect(def.name).toBe(entry.name);
expect(def.reasoning).toBe(entry.reasoning);
expect(def.input).toEqual(entry.input);
expect(def.cost).toEqual({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
expect(def.contextWindow).toBe(entry.contextWindow);
expect(def.maxTokens).toBe(entry.maxTokens);
});
it("excludes stale models from the static fallback catalog", () => {
const catalogIds = new Set(VENICE_MODEL_CATALOG.map((model) => model.id));
for (const staleId of [
-1
View File
@@ -9,7 +9,6 @@ export * from "./html-tags.js";
export * from "./ir.js";
export * from "./render-aware-chunking.js";
export * from "./render-attributed.js";
export * from "./render-plain.js";
export * from "./render.js";
export * from "./tables.js";
export * from "./types.js";
@@ -1,39 +0,0 @@
import { applyConstructFallbacks } from "./construct-fallbacks.js";
import type { FormatCapabilityProfile } from "./format-capabilities.js";
import type { MarkdownIR } from "./ir.js";
export type PlainRenderOptions = {
linkStyle?: "label" | "label-and-url";
};
/** Projects Markdown IR to plain text, optionally applying channel capability fallbacks. */
export function renderMarkdownAsPlainText(
ir: MarkdownIR,
options: PlainRenderOptions = {},
profile?: FormatCapabilityProfile,
): string {
const effectiveProfile =
profile && options.linkStyle === "label"
? { ...profile, constructs: { ...profile.constructs, linkLabel: "strip" as const } }
: profile;
const projected = effectiveProfile ? applyConstructFallbacks(ir, effectiveProfile) : ir;
if ((options.linkStyle ?? "label-and-url") === "label" || projected.links.length === 0) {
return projected.text;
}
let output = "";
let cursor = 0;
for (const link of [...projected.links].toSorted((a, b) => a.start - b.start)) {
if (link.start < cursor) {
continue;
}
output += projected.text.slice(cursor, link.end);
const href = link.href.trim();
const label = projected.text.slice(link.start, link.end).trim();
const comparableHref = href.startsWith("mailto:") ? href.slice("mailto:".length) : href;
if (href && label && label !== href && label !== comparableHref) {
output += ` (${href})`;
}
cursor = link.end;
}
return output + projected.text.slice(cursor);
}
@@ -2,7 +2,6 @@ import { describe, expect, it } from "vitest";
import type { FormatCapabilityProfile } from "./format-capabilities.js";
import { markdownToIR } from "./ir.js";
import { renderMarkdownWithAttributedRanges } from "./render-attributed.js";
import { renderMarkdownAsPlainText } from "./render-plain.js";
import { renderMarkdownWithMarkers } from "./render.js";
const ALL_NATIVE = {
@@ -72,16 +71,4 @@ describe("format capability driver plumbing", () => {
renderMarkdownWithAttributedRanges(ir, options),
);
});
it("keeps plain projection byte-identical for an all-native optional profile", () => {
expect(renderMarkdownAsPlainText(ir, {}, ALL_NATIVE)).toBe(renderMarkdownAsPlainText(ir));
});
it("keeps explicit label-only link projection above profile fallback", () => {
const profile = {
...ALL_NATIVE,
constructs: { ...ALL_NATIVE.constructs, linkLabel: "fallback" as const },
};
expect(renderMarkdownAsPlainText(ir, { linkStyle: "label" }, profile)).toBe("See docs");
});
});
@@ -1,6 +1,4 @@
// Normalization Core tests cover record coerce behavior.
import { readFileSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { asNullableRecord, asOptionalRecord } from "./record-coerce.js";
@@ -13,13 +11,4 @@ describe("record-coerce", () => {
expect(asNullableRecord(null)).toBeNull();
expect(asNullableRecord([{ ok: true }])).toBeNull();
});
it("stays isolated from utils.ts so browser bundles stay Node-free", () => {
const source = readFileSync(
path.resolve("packages/normalization-core/src/record-coerce.ts"),
"utf8",
);
expect(source).not.toContain("../utils.js");
});
});
@@ -157,12 +157,12 @@ const boundaryChecker = createExtensionImportBoundaryChecker({
});
/** Cached inventory of src/plugins imports that cross into bundled extensions. */
export const collectPluginExtensionImportBoundaryInventory = boundaryChecker.collectInventory;
const collectPluginExtensionImportBoundaryInventory = boundaryChecker.collectInventory;
/**
* Cached expected plugin-extension import inventory baseline.
*/
export const readExpectedInventory = createCachedAsync(
const readExpectedInventory = createCachedAsync(
async (): Promise<PluginExtensionInventoryEntry[]> =>
JSON.parse(await fs.readFile(baselinePath, "utf8")),
);
@@ -170,7 +170,7 @@ export const readExpectedInventory = createCachedAsync(
/**
* Diffs expected and actual plugin-extension boundary inventory entries.
*/
export function diffInventory(
function diffInventory(
expected: PluginExtensionInventoryEntry[],
actual: PluginExtensionInventoryEntry[],
) {
@@ -12,10 +12,6 @@ const checker = createExtensionImportBoundaryChecker({
inventoryTitle: "Test-helper extension import boundary inventory:",
});
/**
* Collects test-helper extension import boundary inventory.
*/
export const collectTestHelperExtensionImportBoundaryInventory = checker.collectInventory;
/**
* Entrypoint for the test-helper extension import boundary checker.
*/
@@ -79,7 +79,7 @@ let webFetchProviderViolationsPromise:
/**
* Collects web-fetch provider boundary violations in core source files.
*/
export async function collectWebFetchProviderBoundaryViolations() {
async function collectWebFetchProviderBoundaryViolations() {
if (!webFetchProviderViolationsPromise) {
webFetchProviderViolationsPromise = scanWebFetchProviderBoundaryViolations();
try {
@@ -179,7 +179,7 @@ function scanGenericCoreImports(
/**
* Collects web-search provider boundary inventory from core source files.
*/
export async function collectWebSearchProviderBoundaryInventory() {
async function collectWebSearchProviderBoundaryInventory() {
if (!webSearchProviderInventoryPromise) {
webSearchProviderInventoryPromise = (async () => {
const inventory: InventoryEntry[] = [];
@@ -213,7 +213,7 @@ export async function collectWebSearchProviderBoundaryInventory() {
/**
* Reads the expected web-search provider boundary inventory baseline.
*/
export async function readExpectedInventory(): Promise<InventoryEntry[]> {
async function readExpectedInventory(): Promise<InventoryEntry[]> {
try {
const parsed: unknown = JSON.parse(await fs.readFile(baselinePath, "utf8"));
const result = z.array(inventoryEntrySchema).safeParse(parsed);
@@ -229,7 +229,7 @@ export async function readExpectedInventory(): Promise<InventoryEntry[]> {
/**
* Diffs expected and actual web-search provider boundary inventory entries.
*/
export function diffInventory(expected: InventoryEntry[], actual: InventoryEntry[]) {
function diffInventory(expected: InventoryEntry[], actual: InventoryEntry[]) {
return diffInventoryEntries(expected, actual, compareInventoryEntries);
}
+2 -9
View File
@@ -2510,7 +2510,6 @@ const SEMANTIC_TOOLING_TARGET_PATTERNS: Array<[RegExp, string[]]> = [
[
/^scripts\/e2e\/session-runtime-context-docker\.sh$/u,
[
"docker-e2e-clients",
dockerE2e,
"src/agents/embedded-agent-runner/run/runtime-context-prompt.test.ts",
"src/agents/embedded-agent-runner/transcript-rewrite.test.ts",
@@ -2539,12 +2538,7 @@ const SEMANTIC_TOOLING_TARGET_PATTERNS: Array<[RegExp, string[]]> = [
[/^scripts\/e2e\/live-plugin-tool-docker\.sh$/u, ["live-plugin-tool-assertions"]],
[
/^scripts\/e2e\/commitments-safety-docker\.sh$/u,
[
"docker-e2e-clients",
dockerE2e,
"src/commitments/runtime.test.ts",
"src/commitments/store.test.ts",
],
[dockerE2e, "src/commitments/runtime.test.ts", "src/commitments/store.test.ts"],
],
[/^scripts\/e2e\/onboard-docker\.sh$/u, [dockerBuild, "openclaw-test-state"]],
[
@@ -2636,12 +2630,11 @@ const SEMANTIC_TOOLING_TARGET_PATTERNS: Array<[RegExp, string[]]> = [
],
[
/^scripts\/e2e\/commitments-safety-docker(?:-client)?\.(?:sh|ts)$/u,
["docker-e2e-clients", "src/commitments/runtime.test.ts", "src/commitments/store.test.ts"],
["src/commitments/runtime.test.ts", "src/commitments/store.test.ts"],
],
[
/^scripts\/e2e\/session-runtime-context-docker(?:-client)?\.(?:sh|ts)$/u,
[
"docker-e2e-clients",
"src/agents/embedded-agent-runner/run/runtime-context-prompt.test.ts",
"src/agents/embedded-agent-runner/transcript-rewrite.test.ts",
],
+1 -1
View File
@@ -9,9 +9,9 @@ import { resolveStorePath } from "../config/sessions/paths.js";
import { listSessionEntriesReadOnly } from "../config/sessions/session-accessor.js";
import type { SessionEntry } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { formatDurationCompact } from "../infra/format-time/format-duration.js";
import { parseAgentSessionKey, type ParsedAgentSessionKey } from "../routing/session-key.js";
import {
formatDurationCompact,
formatTokenUsageDisplay,
resolveTotalTokens,
truncateLine,
-37
View File
@@ -1,37 +0,0 @@
// Tests for thinking block detection.
import { describe, expect, it } from "vitest";
import { isThinkingLikeBlock } from "./thinking-block.js";
describe("isThinkingLikeBlock", () => {
it("returns true for thinking type", () => {
expect(isThinkingLikeBlock({ type: "thinking" })).toBe(true);
});
it("returns true for redacted_thinking type", () => {
expect(isThinkingLikeBlock({ type: "redacted_thinking" })).toBe(true);
});
it("returns false for non-thinking type", () => {
expect(isThinkingLikeBlock({ type: "text" })).toBe(false);
});
it("returns false for missing type field", () => {
expect(isThinkingLikeBlock({ content: "hello" })).toBe(false);
});
it("returns false for null", () => {
expect(isThinkingLikeBlock(null)).toBe(false);
});
it("returns false for undefined", () => {
expect(isThinkingLikeBlock(undefined)).toBe(false);
});
it("returns false for string", () => {
expect(isThinkingLikeBlock("thinking")).toBe(false);
});
it("returns false for empty object", () => {
expect(isThinkingLikeBlock({})).toBe(false);
});
});
@@ -1,30 +0,0 @@
import type { SubagentRunRecord } from "../subagent-registry.types.js";
import "./agents-wait-tool.js";
type WaitError = { runId: string; error: "not_found" | "not_owner" };
type WaitTarget = { runId: string; entry: SubagentRunRecord };
type AgentsWaitToolTestApi = {
testing: {
ownsRun(entry: SubagentRunRecord, currentSessionKeys: ReadonlySet<string>): boolean;
readResolvedWaitState(targets: readonly WaitTarget[], errors: readonly WaitError[]): unknown;
readWaitState(ids: readonly string[], currentSessionKeys: ReadonlySet<string>): unknown;
resolveWaitTargets(
ids: readonly string[],
currentSessionKeys: ReadonlySet<string>,
): { targets: WaitTarget[]; errors: WaitError[] };
waitForCollector(params: {
ids: readonly string[];
currentSessionKeys: ReadonlySet<string>;
timeoutMs: number;
signal?: AbortSignal;
}): Promise<unknown>;
};
};
function getTestApi(): AgentsWaitToolTestApi {
return (globalThis as Record<PropertyKey, unknown>)[
Symbol.for("openclaw.agentsWaitToolTestApi")
] as AgentsWaitToolTestApi;
}
export const testing = getTestApi().testing;
@@ -29,7 +29,6 @@ vi.mock("../subagent-registry-state.js", () => ({
import { isToolResultError } from "../tool-result-error.js";
import { createAgentsWaitTool, waitForCollectorCompletion } from "./agents-wait-tool.js";
import { testing } from "./agents-wait-tool.test-support.js";
function collectorRun(
runId: string,
@@ -120,11 +119,6 @@ describe("agents_wait", () => {
expect(registryEvents.listeners.size).toBe(0);
});
it("exposes ownership helpers through test support", () => {
const entry = collectorRun("owned", "agent:main:main");
expect(testing.ownsRun(entry, new Set(["agent:main:main"]))).toBe(true);
});
it("returns the first completed child and leaves siblings pending", async () => {
records.set("one", collectorRun("one", "agent:main:main"));
records.set("two", collectorRun("two", "agent:main:main"));
-14
View File
@@ -245,17 +245,3 @@ export function createAgentsWaitTool(opts: {
},
};
}
const testing = {
ownsRun,
readResolvedWaitState,
readWaitState,
resolveWaitTargets,
waitForCollector,
};
if (process.env.VITEST || process.env.NODE_ENV === "test") {
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.agentsWaitToolTestApi")] = {
testing,
};
}
@@ -6,9 +6,9 @@ import { getSubagentRunsSnapshotForRead } from "../../../agents/subagent-registr
import { resolveSubagentDisplayStatus } from "../../../agents/subagent-session-metrics.js";
import { resolveStorePath } from "../../../config/sessions/paths.js";
import { loadSessionEntryReadOnly } from "../../../config/sessions/session-accessor.js";
import { formatDurationCompact } from "../../../infra/format-time/format-duration.js";
import { formatTimeAgo } from "../../../infra/format-time/format-relative.ts";
import { parseAgentSessionKey } from "../../../routing/session-key.js";
import { formatDurationCompact } from "../../../shared/subagents-format.js";
import { findTaskByRunIdForOwner } from "../../../tasks/task-owner-access.js";
import { sanitizeTaskStatusText } from "../../../tasks/task-status.js";
import type { CommandHandlerResult } from "../commands-types.js";
+1 -20
View File
@@ -1,6 +1,6 @@
import { Command } from "commander";
import { afterEach, describe, expect, it, vi } from "vitest";
import { registerUsersCli, testApi } from "./users-cli.js";
import { registerUsersCli } from "./users-cli.js";
const callGatewayFromCli = vi.hoisted(() => vi.fn());
vi.mock("./gateway-rpc.js", () => ({ callGatewayFromCli }));
@@ -91,23 +91,4 @@ describe("registerUsersCli", () => {
expect(output).toHaveBeenCalledWith('{\n "profile": {\n "id": "p-1"\n }\n}\n');
});
it("escapes untrusted profile fields in human list output", () => {
const output = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
testApi.writeUsersList(
{
profiles: [
{
id: "p-1",
displayName: "Ada\n\t\u001b[2J\u0007",
emails: ["ada@example.com\nnext@example.com"],
},
],
},
false,
);
expect(output).toHaveBeenCalledWith("p-1\tAda\\n\\t\tada@example.com\\nnext@example.com\n");
});
});
-2
View File
@@ -75,5 +75,3 @@ export function registerUsersCli(program: Command) {
applyParentDefaultHelpAction(users);
}
export const testApi = { writeUsersList };
@@ -1,46 +0,0 @@
// Audits heartbeat config coverage across inventory entries.
import { describe, expect, it } from "vitest";
import {
auditConfigHonorInventory,
listSchemaLeafKeysForPrefixes,
} from "../../test/helpers/config/config-honor-audit.js";
import {
HEARTBEAT_CONFIG_HONOR_INVENTORY,
HEARTBEAT_CONFIG_PREFIXES,
} from "../../test/helpers/config/heartbeat-config-honor.inventory.js";
const EXPECTED_HEARTBEAT_KEYS = [
"every",
"model",
"prompt",
"timeoutSeconds",
"lightContext",
"isolatedSession",
"target",
"to",
"accountId",
"directPolicy",
] as const;
describe("heartbeat config-honor inventory", () => {
it("keeps the planned heartbeat audit slice aligned with schema leaf keys", () => {
const schemaKeys = listSchemaLeafKeysForPrefixes([...HEARTBEAT_CONFIG_PREFIXES]);
for (const key of EXPECTED_HEARTBEAT_KEYS) {
expect(schemaKeys).toContain(key);
}
});
it("covers the planned heartbeat keys with runtime, reload, and test proofs", () => {
const audit = auditConfigHonorInventory({
prefixes: [...HEARTBEAT_CONFIG_PREFIXES],
expectedKeys: [...EXPECTED_HEARTBEAT_KEYS],
rows: HEARTBEAT_CONFIG_HONOR_INVENTORY,
});
expect(audit.missingKeys).toStrictEqual([]);
expect(audit.extraKeys).toStrictEqual([]);
expect(audit.missingSchemaPaths).toStrictEqual([]);
expect(audit.missingFiles).toStrictEqual([]);
expect(audit.missingProofs).toStrictEqual([]);
});
});
-10
View File
@@ -1,10 +0,0 @@
import { describe, expect, it } from "vitest";
import { parseCronPacingBounds } from "./pacing.js";
describe("parseCronPacingBounds", () => {
it("rejects pacing without a minimum or maximum", () => {
expect(() => parseCronPacingBounds({})).toThrow(
"cron pacing requires at least one of min or max",
);
});
});
@@ -1,77 +0,0 @@
// Verifies provider capability contracts for media-generation runtimes.
import { describe, expect, it } from "vitest";
import { BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS } from "../plugins/contracts/inventory/bundled-capability-metadata.js";
const EXPECTED_BUNDLED_VIDEO_PROVIDER_PLUGIN_IDS = [
"alibaba",
"byteplus",
"comfy",
"deepinfra",
"fal",
"google",
"minimax",
"openai",
"openrouter",
"pixverse",
"qwen",
"runway",
"together",
"vydra",
"xai",
] as const;
const EXPECTED_BUNDLED_MUSIC_PROVIDER_PLUGIN_IDS = [
"comfy",
"fal",
"google",
"minimax",
"openrouter",
] as const;
const EXPECTED_BUNDLED_VIDEO_PROVIDER_IDS_BY_PLUGIN: Record<string, readonly string[]> = {
minimax: ["minimax", "minimax-portal"],
};
const EXPECTED_BUNDLED_MUSIC_PROVIDER_IDS_BY_PLUGIN: Record<string, readonly string[]> = {
minimax: ["minimax", "minimax-portal"],
};
function bundledVideoProviderPluginIds(): string[] {
return BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
(entry) => entry.videoGenerationProviderIds.length > 0,
)
.map((entry) => entry.pluginId)
.toSorted((left, right) => left.localeCompare(right));
}
function bundledMusicProviderPluginIds(): string[] {
return BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
(entry) => entry.musicGenerationProviderIds.length > 0,
)
.map((entry) => entry.pluginId)
.toSorted((left, right) => left.localeCompare(right));
}
describe("bundled media-generation provider capabilities", () => {
it("tracks every bundled video-generation provider manifest", () => {
expect(bundledVideoProviderPluginIds()).toEqual(EXPECTED_BUNDLED_VIDEO_PROVIDER_PLUGIN_IDS);
for (const entry of BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
(snapshot) => snapshot.videoGenerationProviderIds.length > 0,
)) {
expect(entry.videoGenerationProviderIds, entry.pluginId).toEqual(
EXPECTED_BUNDLED_VIDEO_PROVIDER_IDS_BY_PLUGIN[entry.pluginId] ?? [entry.pluginId],
);
}
});
it("tracks every bundled music-generation provider manifest", () => {
expect(bundledMusicProviderPluginIds()).toEqual(EXPECTED_BUNDLED_MUSIC_PROVIDER_PLUGIN_IDS);
for (const entry of BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
(snapshot) => snapshot.musicGenerationProviderIds.length > 0,
)) {
expect(entry.musicGenerationProviderIds, entry.pluginId).toEqual(
EXPECTED_BUNDLED_MUSIC_PROVIDER_IDS_BY_PLUGIN[entry.pluginId] ?? [entry.pluginId],
);
}
});
});
@@ -9,14 +9,12 @@ export const pluginRegistrationContractCases = {
alibaba: {
pluginId: "alibaba",
videoGenerationProviderIds: ["alibaba"],
requireGenerateVideo: true,
},
anthropic: {
pluginId: "anthropic",
providerIds: ["anthropic"],
mediaUnderstandingProviderIds: ["anthropic"],
cliBackendIds: ["claude-cli"],
requireDescribeImages: true,
},
brave: {
pluginId: "brave",
@@ -26,7 +24,6 @@ export const pluginRegistrationContractCases = {
pluginId: "byteplus",
providerIds: ["byteplus", "byteplus-plan"],
videoGenerationProviderIds: ["byteplus"],
requireGenerateVideo: true,
},
comfy: {
pluginId: "comfy",
@@ -34,8 +31,6 @@ export const pluginRegistrationContractCases = {
imageGenerationProviderIds: ["comfy"],
musicGenerationProviderIds: ["comfy"],
videoGenerationProviderIds: ["comfy"],
requireGenerateImage: true,
requireGenerateVideo: true,
},
deepgram: {
pluginId: "deepgram",
@@ -48,7 +43,6 @@ export const pluginRegistrationContractCases = {
elevenlabs: {
pluginId: "elevenlabs",
speechProviderIds: ["elevenlabs"],
requireSpeechVoices: true,
},
exa: {
pluginId: "exa",
@@ -60,8 +54,6 @@ export const pluginRegistrationContractCases = {
imageGenerationProviderIds: ["fal"],
musicGenerationProviderIds: ["fal"],
videoGenerationProviderIds: ["fal"],
requireGenerateImage: true,
requireGenerateVideo: true,
},
firecrawl: {
pluginId: "firecrawl",
@@ -78,9 +70,6 @@ export const pluginRegistrationContractCases = {
mediaUnderstandingProviderIds: ["google"],
imageGenerationProviderIds: ["google"],
videoGenerationProviderIds: ["google"],
requireDescribeImages: true,
requireGenerateImage: true,
requireGenerateVideo: true,
},
gradium: {
pluginId: "gradium",
@@ -97,7 +86,6 @@ export const pluginRegistrationContractCases = {
microsoft: {
pluginId: "microsoft",
speechProviderIds: ["microsoft"],
requireSpeechVoices: true,
},
minimax: {
pluginId: "minimax",
@@ -108,9 +96,6 @@ export const pluginRegistrationContractCases = {
musicGenerationProviderIds: ["minimax", "minimax-portal"],
videoGenerationProviderIds: ["minimax", "minimax-portal"],
webSearchProviderIds: ["minimax"],
requireDescribeImages: true,
requireGenerateImage: true,
requireGenerateVideo: true,
},
mistral: {
pluginId: "mistral",
@@ -121,7 +106,6 @@ export const pluginRegistrationContractCases = {
providerIds: ["moonshot"],
webSearchProviderIds: ["kimi"],
mediaUnderstandingProviderIds: ["moonshot"],
requireDescribeImages: true,
manifestAuthChoice: {
pluginId: "kimi",
choiceId: "kimi-code-api-key",
@@ -157,22 +141,16 @@ export const pluginRegistrationContractCases = {
mediaUnderstandingProviderIds: ["openai"],
imageGenerationProviderIds: ["openai"],
videoGenerationProviderIds: ["openai"],
requireSpeechVoices: true,
requireDescribeImages: true,
requireGenerateImage: true,
requireGenerateVideo: true,
},
"opencode-go": {
pluginId: "opencode-go",
providerIds: ["opencode-go"],
mediaUnderstandingProviderIds: ["opencode-go"],
requireDescribeImages: true,
},
opencode: {
pluginId: "opencode",
providerIds: ["opencode"],
mediaUnderstandingProviderIds: ["opencode"],
requireDescribeImages: true,
},
openrouter: {
pluginId: "openrouter",
@@ -181,9 +159,6 @@ export const pluginRegistrationContractCases = {
imageGenerationProviderIds: ["openrouter"],
musicGenerationProviderIds: ["openrouter"],
videoGenerationProviderIds: ["openrouter"],
requireDescribeImages: true,
requireGenerateImage: true,
requireGenerateVideo: true,
},
parallel: {
pluginId: "parallel",
@@ -196,7 +171,6 @@ export const pluginRegistrationContractCases = {
pixverse: {
pluginId: "pixverse",
videoGenerationProviderIds: ["pixverse"],
requireGenerateVideo: true,
},
qwen: {
pluginId: "qwen",
@@ -210,13 +184,10 @@ export const pluginRegistrationContractCases = {
],
mediaUnderstandingProviderIds: ["qwen"],
videoGenerationProviderIds: ["qwen"],
requireDescribeImages: true,
requireGenerateVideo: true,
},
runway: {
pluginId: "runway",
videoGenerationProviderIds: ["runway"],
requireGenerateVideo: true,
},
senseaudio: {
pluginId: "senseaudio",
@@ -231,7 +202,6 @@ export const pluginRegistrationContractCases = {
pluginId: "together",
providerIds: ["together"],
videoGenerationProviderIds: ["together"],
requireGenerateVideo: true,
},
"tts-local-cli": {
pluginId: "tts-local-cli",
@@ -243,9 +213,6 @@ export const pluginRegistrationContractCases = {
speechProviderIds: ["vydra"],
imageGenerationProviderIds: ["vydra"],
videoGenerationProviderIds: ["vydra"],
requireSpeechVoices: true,
requireGenerateImage: true,
requireGenerateVideo: true,
manifestAuthChoice: {
pluginId: "vydra",
choiceId: "vydra-api-key",
@@ -263,11 +230,9 @@ export const pluginRegistrationContractCases = {
mediaUnderstandingProviderIds: ["xai"],
videoGenerationProviderIds: ["xai"],
toolNames: ["code_execution", "x_search"],
requireGenerateVideo: true,
},
zai: {
pluginId: "zai",
mediaUnderstandingProviderIds: ["zai"],
requireDescribeImages: true,
},
} satisfies Record<string, PluginRegistrationContractParams>;
@@ -20,10 +20,6 @@ type PluginRegistrationContractParams = {
videoGenerationProviderIds?: string[];
musicGenerationProviderIds?: string[];
toolNames?: string[];
requireSpeechVoices?: boolean;
requireDescribeImages?: boolean;
requireGenerateImage?: boolean;
requireGenerateVideo?: boolean;
manifestAuthChoice?: {
pluginId: string;
choiceId: string;
@@ -79,6 +79,7 @@ const packageManifestContractTests: PackageManifestContractParams[] = [
{ pluginId: "synology-chat", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "telegram" },
{ pluginId: "tlon", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "tokenjuice", pluginLocalRuntimeDeps: ["tokenjuice"] },
{ pluginId: "twitch", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "voice-call", minHostVersionBaseline: "2026.3.22" },
{
@@ -1,4 +0,0 @@
import { pluginRegistrationContractCases } from "openclaw/plugin-sdk/plugin-test-contracts";
import { describePluginRegistrationContract } from "openclaw/plugin-sdk/plugin-test-contracts";
describePluginRegistrationContract(pluginRegistrationContractCases.parallel);
+1 -16
View File
@@ -1,11 +1,6 @@
// Subagent format tests cover concise subagent status and duration formatting.
import { describe, expect, it } from "vitest";
import {
formatDurationCompact,
formatTokenUsageDisplay,
resolveTotalTokens,
truncateLine,
} from "./subagents-format.js";
import { formatTokenUsageDisplay, resolveTotalTokens, truncateLine } from "./subagents-format.js";
const freshUsage = (totalTokens: number) => ({
totalTokens,
@@ -14,16 +9,6 @@ const freshUsage = (totalTokens: number) => ({
});
describe("shared/subagents-format", () => {
it("re-exports the canonical formatter with second-level precision", () => {
expect(formatDurationCompact()).toBeUndefined();
expect(formatDurationCompact(30_000)).toBe("30s");
expect(formatDurationCompact(90_000)).toBe("1m30s");
expect(formatDurationCompact(60 * 60_000)).toBe("1h");
expect(formatDurationCompact(61 * 60_000)).toBe("1h1m");
expect(formatDurationCompact(24 * 60 * 60_000)).toBe("1d");
expect(formatDurationCompact(25 * 60 * 60_000)).toBe("1d1h");
});
it("formats token counts with integer, kilo, and million branches", () => {
expect(formatTokenUsageDisplay()).toBe("");
expect(formatTokenUsageDisplay(freshUsage(999.9))).toBe("tokens 999 prompt/cache");
-1
View File
@@ -1,6 +1,5 @@
// Subagent formatting helpers expose compact durations and status text.
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
export { formatDurationCompact } from "../infra/format-time/format-duration.ts";
/** Formats token counts using compact k/m suffixes for subagent summaries. */
function formatTokenShort(value?: number) {
-155
View File
@@ -1,155 +0,0 @@
// Config honor audit helper checks config fields against expected consumers.
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { computeBaseConfigSchemaResponse } from "../../../src/config/schema-base.js";
// Config honor audit helpers that compare schema keys with proof inventories.
/** Inventory row describing where one config key is declared, merged, consumed, and tested. */
export type ConfigHonorInventoryRow = {
key: string;
schemaPaths: string[];
typePaths: string[];
mergePaths: string[];
consumerPaths: string[];
reloadPaths: string[];
testPaths: string[];
notes?: string[];
};
type ConfigHonorProofKey =
| "schemaPaths"
| "typePaths"
| "mergePaths"
| "consumerPaths"
| "reloadPaths"
| "testPaths";
/** Result of auditing one config honor inventory. */
type ConfigHonorAuditResult = {
schemaKeys: string[];
missingKeys: string[];
extraKeys: string[];
missingSchemaPaths: string[];
missingFiles: string[];
missingProofs: Array<{
key: string;
missing: ConfigHonorProofKey[];
}>;
};
const REPO_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
const BASE_CONFIG_SCHEMA = computeBaseConfigSchemaResponse({
generatedAt: "2026-05-05T00:00:00.000Z",
});
/** Return true when a dotted schema path exists in the generated base config schema. */
function hasSchemaPath(schemaPath: string): boolean {
const segments = schemaPath.split(".");
let current: unknown = BASE_CONFIG_SCHEMA.schema;
for (const segment of segments) {
if (!current || typeof current !== "object") {
return false;
}
if (segment === "*") {
const wildcardTarget =
(current as { additionalProperties?: unknown; items?: unknown }).items ??
(current as { additionalProperties?: unknown }).additionalProperties;
if (!wildcardTarget || typeof wildcardTarget !== "object") {
return false;
}
current = wildcardTarget;
continue;
}
const properties = (current as { properties?: Record<string, unknown> }).properties;
if (!properties || !Object.hasOwn(properties, segment)) {
return false;
}
current = properties[segment];
}
return true;
}
/** List leaf schema keys for the requested config prefixes. */
export function listSchemaLeafKeysForPrefixes(prefixes: string[]): string[] {
const keys = new Set<string>();
for (const prefix of prefixes) {
const segments = prefix.split(".");
let current: unknown = BASE_CONFIG_SCHEMA.schema;
for (const segment of segments) {
if (!current || typeof current !== "object") {
current = null;
break;
}
if (segment === "*") {
current =
(current as { additionalProperties?: unknown; items?: unknown }).items ??
(current as { additionalProperties?: unknown }).additionalProperties ??
null;
continue;
}
current = (current as { properties?: Record<string, unknown> }).properties?.[segment] ?? null;
}
const properties = (current as { properties?: Record<string, unknown> } | null)?.properties;
if (!properties) {
continue;
}
for (const key of Object.keys(properties)) {
keys.add(key);
}
}
return [...keys].toSorted();
}
/** Audit an inventory against schema keys, proof paths, and file existence. */
export function auditConfigHonorInventory(params: {
prefixes: string[];
rows: ConfigHonorInventoryRow[];
expectedKeys?: string[];
repoRoot?: string;
}): ConfigHonorAuditResult {
const repoRoot = params.repoRoot ?? REPO_ROOT;
const schemaKeys = listSchemaLeafKeysForPrefixes(params.prefixes);
const expectedKeys = new Set(params.expectedKeys ?? schemaKeys);
const rowKeys = new Set(params.rows.map((row) => row.key));
const missingKeys = [...expectedKeys].filter((key) => !rowKeys.has(key)).toSorted();
const extraKeys = params.rows
.map((row) => row.key)
.filter((key) => !expectedKeys.has(key))
.toSorted();
const missingSchemaPaths = params.rows.flatMap((row) =>
row.schemaPaths.filter((schemaPath) => !hasSchemaPath(schemaPath)),
);
const missingFiles = params.rows.flatMap((row) => {
const files = [...row.typePaths, ...row.mergePaths, ...row.consumerPaths, ...row.testPaths];
return files
.filter((relativePath) => !fs.existsSync(path.join(repoRoot, relativePath)))
.map((relativePath) => `${row.key}:${relativePath}`);
});
const missingProofs = params.rows
.map((row) => {
const missing: ConfigHonorProofKey[] = [
row.schemaPaths.length === 0 ? "schemaPaths" : null,
row.typePaths.length === 0 ? "typePaths" : null,
row.mergePaths.length === 0 ? "mergePaths" : null,
row.consumerPaths.length === 0 ? "consumerPaths" : null,
row.reloadPaths.length === 0 ? "reloadPaths" : null,
row.testPaths.length === 0 ? "testPaths" : null,
].filter((value): value is ConfigHonorProofKey => value !== null);
return missing.length > 0 ? { key: row.key, missing } : null;
})
.filter((row): row is NonNullable<typeof row> => row !== null);
return {
schemaKeys,
missingKeys,
extraKeys,
missingSchemaPaths,
missingFiles,
missingProofs,
};
}
@@ -1,135 +0,0 @@
// Heartbeat config honor inventory lists heartbeat config ownership rows.
import type { ConfigHonorInventoryRow } from "./config-honor-audit.js";
// Inventory of heartbeat config keys and the proof paths that should honor them.
/** Config prefixes audited for heartbeat key coverage. */
export const HEARTBEAT_CONFIG_PREFIXES = [
"agents.defaults.heartbeat",
"agents.entries.*.heartbeat",
] as const;
/** Heartbeat config honor inventory consumed by config audit tests. */
export const HEARTBEAT_CONFIG_HONOR_INVENTORY: ConfigHonorInventoryRow[] = [
{
key: "every",
schemaPaths: ["agents.defaults.heartbeat.every", "agents.entries.*.heartbeat.every"],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts", "src/agents/acp-spawn.ts"],
consumerPaths: ["src/infra/heartbeat-runner.ts", "src/agents/acp-spawn.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: [
"src/infra/heartbeat-runner.returns-default-unset.test.ts",
"src/gateway/config-reload.test.ts",
],
},
{
key: "model",
schemaPaths: ["agents.defaults.heartbeat.model", "agents.entries.*.heartbeat.model"],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts"],
consumerPaths: ["src/infra/heartbeat-runner.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: [
"src/infra/heartbeat-runner.model-override.test.ts",
"src/gateway/config-reload.test.ts",
],
},
{
key: "prompt",
schemaPaths: ["agents.defaults.heartbeat.prompt", "agents.entries.*.heartbeat.prompt"],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts"],
consumerPaths: ["src/infra/heartbeat-runner.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: ["src/infra/heartbeat-runner.returns-default-unset.test.ts"],
},
{
key: "timeoutSeconds",
schemaPaths: [
"agents.defaults.heartbeat.timeoutSeconds",
"agents.entries.*.heartbeat.timeoutSeconds",
],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts"],
consumerPaths: ["src/infra/heartbeat-runner.ts", "src/auto-reply/reply/get-reply.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: [
"src/config/zod-schema.agent-defaults.test.ts",
"src/infra/heartbeat-runner.model-override.test.ts",
],
},
{
key: "lightContext",
schemaPaths: [
"agents.defaults.heartbeat.lightContext",
"agents.entries.*.heartbeat.lightContext",
],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts"],
consumerPaths: ["src/infra/heartbeat-runner.ts", "src/agents/bootstrap-files.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: [
"src/infra/heartbeat-runner.model-override.test.ts",
"src/agents/bootstrap-files.test.ts",
"src/gateway/config-reload.test.ts",
],
},
{
key: "isolatedSession",
schemaPaths: [
"agents.defaults.heartbeat.isolatedSession",
"agents.entries.*.heartbeat.isolatedSession",
],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts"],
consumerPaths: ["src/infra/heartbeat-runner.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: ["src/infra/heartbeat-runner.model-override.test.ts"],
},
{
key: "target",
schemaPaths: ["agents.defaults.heartbeat.target", "agents.entries.*.heartbeat.target"],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts", "src/infra/outbound/targets.ts"],
consumerPaths: ["src/infra/outbound/targets.ts", "src/infra/heartbeat-runner.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: [
"src/infra/heartbeat-runner.returns-default-unset.test.ts",
"src/cron/service.main-job-passes-heartbeat-target-last.test.ts",
],
},
{
key: "to",
schemaPaths: ["agents.defaults.heartbeat.to", "agents.entries.*.heartbeat.to"],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts", "src/infra/outbound/targets.ts"],
consumerPaths: ["src/infra/outbound/targets.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: ["src/infra/heartbeat-runner.returns-default-unset.test.ts"],
},
{
key: "accountId",
schemaPaths: ["agents.defaults.heartbeat.accountId", "agents.entries.*.heartbeat.accountId"],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts", "src/infra/outbound/targets.ts"],
consumerPaths: ["src/infra/outbound/targets.ts", "src/infra/heartbeat-runner.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: [
"src/infra/heartbeat-runner.returns-default-unset.test.ts",
"src/infra/heartbeat-runner.ack-token-heartbeat-acks.test.ts",
],
},
{
key: "directPolicy",
schemaPaths: [
"agents.defaults.heartbeat.directPolicy",
"agents.entries.*.heartbeat.directPolicy",
],
typePaths: ["src/config/types.agent-defaults.ts", "src/config/zod-schema.agent-runtime.ts"],
mergePaths: ["src/infra/heartbeat-runner.ts", "src/infra/outbound/targets.ts"],
consumerPaths: ["src/infra/outbound/targets.ts"],
reloadPaths: ["src/gateway/config-reload-plan.ts"],
testPaths: ["src/infra/heartbeat-runner.returns-default-unset.test.ts"],
},
];
+1 -63
View File
@@ -2,11 +2,7 @@
import { readFileSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
collectPluginExtensionImportBoundaryInventory,
diffInventory,
main,
} from "../scripts/check-plugin-extension-import-boundary.mts";
import { main } from "../scripts/check-plugin-extension-import-boundary.mts";
import { createCapturedIo } from "./helpers/captured-io.js";
const repoRoot = process.cwd();
@@ -18,65 +14,7 @@ const baselinePath = path.join(
);
const baseline = JSON.parse(readFileSync(baselinePath, "utf8"));
function collectInventoryFiles(
inventory: Awaited<ReturnType<typeof collectPluginExtensionImportBoundaryInventory>>,
predicate: (file: string) => boolean,
): string[] {
const files: string[] = [];
for (const entry of inventory) {
if (predicate(entry.file)) {
files.push(entry.file);
}
}
return files;
}
describe("plugin extension import boundary inventory", () => {
it("keeps dedicated web-search registry shims out of the remaining inventory", async () => {
const inventory = await collectPluginExtensionImportBoundaryInventory();
const blockedShimFiles = collectInventoryFiles(
inventory,
(file) =>
file === "src/plugins/web-search-providers.ts" ||
file === "src/plugins/bundled-web-search-registry.ts",
);
expect(blockedShimFiles).toStrictEqual([]);
});
it("ignores boundary shims by scope", async () => {
const inventory = await collectPluginExtensionImportBoundaryInventory();
const boundaryShimFiles = collectInventoryFiles(
inventory,
(file) => file.startsWith("src/plugin-sdk/") || file.startsWith("src/plugin-sdk-internal/"),
);
expect(boundaryShimFiles).toStrictEqual([]);
});
it("produces stable sorted output", async () => {
const first = await collectPluginExtensionImportBoundaryInventory();
const second = await collectPluginExtensionImportBoundaryInventory();
expect(second).toEqual(first);
expect(
[...first].toSorted(
(left, right) =>
left.file.localeCompare(right.file) ||
left.line - right.line ||
left.kind.localeCompare(right.kind) ||
left.specifier.localeCompare(right.specifier) ||
left.reason.localeCompare(right.reason),
),
).toEqual(first);
});
it("matches the checked-in baseline", async () => {
const actual = await collectPluginExtensionImportBoundaryInventory();
expect(diffInventory(baseline, actual)).toEqual({ missing: [], unexpected: [] });
});
it("script json output matches the baseline exactly", async () => {
const captured = createCapturedIo();
const exitCode = await main(["--json"], captured.io);
@@ -10,11 +10,6 @@ import {
} from "../../scripts/e2e/cron-mcp-cleanup-docker-client.ts";
describe("cron MCP cleanup docker client", () => {
it("binds a device identity for the UI-mode gateway client", () => {
const source = fs.readFileSync("scripts/e2e/cron-mcp-cleanup-docker-client.ts", "utf8");
expect(source).toContain("bindFreshDevice: true");
});
it("rejects malformed probe pid wait limits", () => {
expect(readCronMcpCleanupProbePidWaitMs({})).toBe(120_000);
expect(readCronMcpCleanupProbePidWaitMs({ OPENCLAW_CRON_MCP_CLEANUP_PID_WAIT_MS: "250" })).toBe(
-37
View File
@@ -1,37 +0,0 @@
// Docker E2E client tests cover packaged-dist harness wiring.
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
function readScript(pathname: string): string {
return readFileSync(pathname, "utf8");
}
describe("Docker E2E client scripts", () => {
it("keeps commitments safety checks wired to packaged commitment runtime", () => {
const source = readScript("scripts/e2e/commitments-safety-docker-client.ts");
expect(source).toContain("../../dist/commitments/runtime.js");
expect(source).toContain("../../dist/commitments/store.js");
expect(source).toContain("resetCommitmentExtractionRuntimeForTests");
expect(source).toContain("verifyExtractionRemainsRetired()");
expect(source).toContain("verifyDoctorImportAndRuntimeIsolation()");
expect(source).toContain("verifyExpiryTransition()");
expect(source).toContain('[entry, "doctor", "--fix", "--yes", "--force"]');
expect(source).toContain("CALL_TOOL");
});
it("keeps session runtime-context checks wired to packaged transcript behavior", () => {
const source = readScript("scripts/e2e/session-runtime-context-docker-client.ts");
expect(source).toContain("openclaw/plugin-sdk/agent-sessions");
expect(source).toContain(
"../../dist/agents/embedded-agent-runner/run/runtime-context-prompt.js",
);
expect(source).toContain("SessionManager.inMemory()");
expect(source).toContain("verifyRuntimeContextTranscriptShape()");
expect(source).toContain("verifyDoctorRepair(root)");
expect(source).toContain("<<<BEGIN_OPENCLAW_INTERNAL_CONTEXT>>>");
expect(source).toContain("openclaw.runtime-context");
expect(source).toContain("doctor repair left runtime context in active transcript");
});
});
-13
View File
@@ -10,7 +10,6 @@ import { describe, expect, it } from "vitest";
const execFileAsync = promisify(execFile);
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const scriptPath = path.join(repoRoot, "scripts/lib/openclaw-test-state.mts");
const onboardDockerScriptPath = path.join(repoRoot, "scripts/e2e/onboard-docker.sh");
function shellQuote(value: string): string {
return `'${value.replace(/'/gu, `'\\''`)}'`;
@@ -299,16 +298,4 @@ describe("scripts/lib/openclaw-test-state", () => {
await fs.rm(tempRoot, { recursive: true, force: true });
}
});
it("keeps onboard Docker temp homes on the shared test-state helper", async () => {
const scriptText = await fs.readFile(onboardDockerScriptPath, "utf8");
const scenarioText = await fs.readFile("scripts/e2e/lib/onboard/scenario.sh", "utf8");
expect(scriptText).toContain("OPENCLAW_TEST_STATE_FUNCTION_B64");
expect(scriptText).toContain("scripts/e2e/lib/onboard/scenario.sh");
expect(scenarioText).toContain("set_isolated_openclaw_env local-basic");
expect(scenarioText).toContain("run_wizard_cmd channels channels");
expect(scriptText).not.toContain("make_home");
expect(scenarioText).not.toContain("make_home");
});
});
-11
View File
@@ -222,17 +222,6 @@ describe("plugins Docker assertions", () => {
);
});
it("passes ClawHub preflight body timeouts into the bounded reader", () => {
const script = readFileSync(ASSERTIONS_SCRIPT, "utf8");
expect(script).toContain("run(controller.signal, timeoutPromise)");
expect(
script.match(
/readBoundedResponseText\([\s\S]*?limits\.bodyMaxBytes,\n\s+\{ createTooLargeError: createBoundedResponseTooLargeError, timeoutPromise \},/gu,
),
).toHaveLength(2);
});
it("keeps sweep artifact paths aligned with the assertion scratch root", () => {
const scripts = [
"scripts/e2e/lib/plugins/sweep.sh",
-96
View File
@@ -1,5 +1,4 @@
// Prompt Snapshots tests cover prompt snapshots script behavior.
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
@@ -17,8 +16,6 @@ import {
runCodexModelPromptFixtureSync,
} from "../../scripts/sync-codex-model-prompt-fixture.js";
import { getPluginModuleLoaderStats } from "../../src/plugins/plugin-module-loader-cache.js";
import { expectNoReaddirSyncDuring } from "../../src/test-utils/fs-scan-assertions.js";
import { toRepoRelativePath } from "../../src/test-utils/repo-files.js";
import { createHappyPathPromptSnapshotFiles } from "../helpers/agents/happy-path-prompt-snapshots.js";
import {
CODEX_MODEL_PROMPT_FIXTURE_DIR,
@@ -38,104 +35,11 @@ function renderedPromptSection(content: string, heading: string, nextHeading: st
return content.slice(start, end);
}
function listCommittedPromptSnapshotFiles(): string[] {
const externalFiles = listExternalCommittedPromptSnapshotFiles();
if (externalFiles) {
return externalFiles;
}
return fs
.readdirSync(CODEX_RUNTIME_HAPPY_PATH_PROMPT_SNAPSHOT_DIR)
.filter((entry) => entry.endsWith(".md") || entry.endsWith(".json"))
.map((entry) => path.join(CODEX_RUNTIME_HAPPY_PATH_PROMPT_SNAPSHOT_DIR, entry))
.toSorted();
}
function listExternalCommittedPromptSnapshotFiles(): string[] | null {
return listGitCommittedPromptSnapshotFiles() ?? listFindCommittedPromptSnapshotFiles();
}
function listGitCommittedPromptSnapshotFiles(): string[] | null {
const result = spawnSync(
"git",
["ls-files", "--", CODEX_RUNTIME_HAPPY_PATH_PROMPT_SNAPSHOT_DIR],
{
cwd: process.cwd(),
encoding: "utf8",
maxBuffer: 1024 * 1024,
stdio: ["ignore", "pipe", "ignore"],
},
);
if (result.status !== 0) {
return null;
}
return result.stdout
.split("\n")
.map((line) => line.trim())
.filter((line) => line.endsWith(".md") || line.endsWith(".json"))
.toSorted();
}
function listFindCommittedPromptSnapshotFiles(): string[] | null {
const result = spawnSync(
"find",
[
path.join(process.cwd(), CODEX_RUNTIME_HAPPY_PATH_PROMPT_SNAPSHOT_DIR),
"-maxdepth",
"1",
"-type",
"f",
"(",
"-name",
"*.md",
"-o",
"-name",
"*.json",
")",
],
{
cwd: process.cwd(),
encoding: "utf8",
maxBuffer: 1024 * 1024,
stdio: ["ignore", "pipe", "ignore"],
},
);
if (result.status !== 0) {
return null;
}
return result.stdout
.split("\n")
.map((line) => line.trim())
.filter((line) => line.length > 0)
.map((filePath) => toRepoRelativePath(process.cwd(), filePath))
.toSorted();
}
describe("happy path prompt snapshots", () => {
it("loads the generator entrypoint used by the prompt snapshot check", () => {
expect(createFormattedPromptSnapshotFiles).toEqual(expect.any(Function));
});
it("lists committed Codex prompt snapshot artifacts without scanning directories in-process", () => {
expectNoReaddirSyncDuring(() => {
const committed = listCommittedPromptSnapshotFiles();
expect(committed.length).toBeGreaterThan(0);
expect(committed.every((file) => file.endsWith(".md") || file.endsWith(".json"))).toBe(true);
});
});
it("keeps the committed Codex prompt snapshot artifact set explicit", () => {
expect(listCommittedPromptSnapshotFiles().map((file) => path.basename(file))).toEqual([
"README.md",
"codex-dynamic-tools.discord-group.json",
"codex-dynamic-tools.heartbeat-turn.json",
"codex-dynamic-tools.telegram-direct.json",
"discord-group-codex-message-tool.md",
"telegram-direct-codex-message-tool.md",
"telegram-heartbeat-codex-tool.md",
]);
});
it("reconstructs complete Codex tool catalogs from readable full-tool overrides", async () => {
const generated = await createHappyPathPromptSnapshotFiles();
const scenarios = [
-13
View File
@@ -1,13 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
describe("QA CLI onboarding evidence", () => {
it("retains the bounded redacted child log", () => {
const source = readFileSync("scripts/e2e/qa-cli-onboarding.mjs", "utf8");
expect(source).toContain("writer.appendLog(chunk)");
expect(source).toContain("const logArtifact = await writer.writeLog()");
expect(source).toContain("artifactPaths: [logArtifact]");
expect(source).not.toContain("artifactPaths: []");
});
});
@@ -1,14 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const FILE_SPEC_MARKER = "Testing install from npm spec (file:)...";
describe("QA plugin install source coverage", () => {
it("requires the executable npm file-spec assertion marker", () => {
const qaWrapper = readFileSync("scripts/e2e/qa-plugin-install-sources.mjs", "utf8");
const pluginSweep = readFileSync("scripts/e2e/lib/plugins/sweep.sh", "utf8");
expect(pluginSweep).toContain(`echo "${FILE_SPEC_MARKER}"`);
expect(qaWrapper).toContain(`"${FILE_SPEC_MARKER}",`);
});
});
+1 -8
View File
@@ -683,23 +683,19 @@ describe("scripts/test-projects changed-target routing", () => {
"src/system-agent/audit.test.ts",
],
"scripts/e2e/commitments-safety-docker-client.ts": [
"test/scripts/docker-e2e-clients.test.ts",
"src/commitments/runtime.test.ts",
"src/commitments/store.test.ts",
],
"scripts/e2e/commitments-safety-docker.sh": [
"test/scripts/docker-e2e-clients.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
"src/commitments/runtime.test.ts",
"src/commitments/store.test.ts",
],
"scripts/e2e/session-runtime-context-docker-client.ts": [
"test/scripts/docker-e2e-clients.test.ts",
"src/agents/embedded-agent-runner/run/runtime-context-prompt.test.ts",
"src/agents/embedded-agent-runner/transcript-rewrite.test.ts",
],
"scripts/e2e/session-runtime-context-docker.sh": [
"test/scripts/docker-e2e-clients.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
"src/agents/embedded-agent-runner/run/runtime-context-prompt.test.ts",
"src/agents/embedded-agent-runner/transcript-rewrite.test.ts",
@@ -724,10 +720,7 @@ describe("scripts/test-projects changed-target routing", () => {
"src/cron/active-jobs-manual-run.test.ts",
],
"scripts/e2e/cron-mcp-cleanup-seed.ts": ["test/scripts/docker-e2e-seeds.test.ts"],
"scripts/e2e/lib/onboard/scenario.sh": [
"test/scripts/e2e-shell-tempfiles.test.ts",
"test/scripts/openclaw-test-state.test.ts",
],
"scripts/e2e/lib/onboard/scenario.sh": ["test/scripts/e2e-shell-tempfiles.test.ts"],
"scripts/e2e/lib/onboard/assert-config.mjs": ["test/scripts/onboard-config-fixtures.test.ts"],
"scripts/e2e/lib/onboard/write-config.mjs": ["test/scripts/onboard-config-fixtures.test.ts"],
"scripts/e2e/lib/package-compat.mjs": [
@@ -1,16 +1,9 @@
// Test helper extension boundary tests enforce helper import boundaries.
import { describe, expect, it } from "vitest";
import {
collectTestHelperExtensionImportBoundaryInventory,
main,
} from "../scripts/check-test-helper-extension-import-boundary.mts";
import { main } from "../scripts/check-test-helper-extension-import-boundary.mts";
import { createCapturedIo } from "./helpers/captured-io.js";
describe("test-helper extension import boundary inventory", () => {
it("stays empty", async () => {
expect(await collectTestHelperExtensionImportBoundaryInventory()).toStrictEqual([]);
});
it("script json output stays empty", async () => {
const captured = createCapturedIo();
const exitCode = await main(["--json"], captured.io);
+4 -25
View File
@@ -1,18 +1,10 @@
// Web provider boundary tests enforce provider import boundaries.
import { describe, expect, it } from "vitest";
import {
collectWebFetchProviderBoundaryViolations,
main as webFetchMain,
} from "../scripts/check-web-fetch-provider-boundaries.mts";
import {
collectWebSearchProviderBoundaryInventory,
main as webSearchMain,
} from "../scripts/check-web-search-provider-boundaries.mts";
import { main as webFetchMain } from "../scripts/check-web-fetch-provider-boundaries.mts";
import { main as webSearchMain } from "../scripts/check-web-search-provider-boundaries.mts";
import { createCapturedIo } from "./helpers/captured-io.js";
const webFetchViolationsPromise = collectWebFetchProviderBoundaryViolations();
const webFetchJsonOutputPromise = getJsonOutput(webFetchMain);
const webSearchInventoryPromise = collectWebSearchProviderBoundaryInventory();
const webSearchJsonOutputPromise = getJsonOutput(webSearchMain);
async function getJsonOutput(
@@ -28,30 +20,17 @@ async function getJsonOutput(
}
describe("web provider boundaries", () => {
it("keeps Firecrawl-specific fetch logic out of core runtime/tooling", async () => {
const violations = await webFetchViolationsPromise;
it("runs the web fetch boundary script in JSON mode", async () => {
const jsonOutput = await webFetchJsonOutputPromise;
expect(violations).toStrictEqual([]);
expect(jsonOutput.exitCode).toBe(0);
expect(jsonOutput.stderr).toBe("");
expect(jsonOutput.json).toStrictEqual([]);
});
it("keeps web search provider boundary inventory empty, core-only, and sorted", async () => {
const inventory = await webSearchInventoryPromise;
it("runs the web search boundary script in JSON mode", async () => {
const jsonOutput = await webSearchJsonOutputPromise;
expect(inventory).toStrictEqual([]);
expect(
[...inventory].toSorted(
(left, right) =>
left.provider.localeCompare(right.provider) ||
left.file.localeCompare(right.file) ||
left.line - right.line ||
left.reason.localeCompare(right.reason),
),
).toEqual(inventory);
expect(jsonOutput.exitCode).toBe(0);
expect(jsonOutput.stderr).toBe("");
expect(jsonOutput.json).toStrictEqual([]);
@@ -1,21 +1,9 @@
// @vitest-environment node
import { readFile } from "node:fs/promises";
import { describe, expect, it } from "vitest";
type CommandsModule = typeof import("./commands.js");
const browserImportPath = "./commands.ts?browser-import";
function importDeclarations(source: string): string[] {
return (source.match(/^import[\s\S]*?;$/gmu) ?? []).map((declaration) =>
declaration
.replace(/\s+/gu, " ")
.replace(/\{\s+/gu, "{ ")
.replace(/,\s*\}/gu, " }")
.replace(/\s+\}/gu, " }")
.trim(),
);
}
describe("slash command browser import", () => {
it("builds fallback commands from the browser-safe shared registry", async () => {
const mod = (await import(browserImportPath)) as CommandsModule;
@@ -35,40 +23,4 @@ describe("slash command browser import", () => {
source: "native",
});
});
it("keeps provider thinking runtime out of the Control UI import path", async () => {
const commands = await readFile(new URL("./commands.ts", import.meta.url), "utf8");
const sharedRegistry = await readFile(
new URL("../../../../src/auto-reply/commands-registry.shared.ts", import.meta.url),
"utf8",
);
const serverRegistry = await readFile(
new URL("../../../../src/auto-reply/commands-registry.data.ts", import.meta.url),
"utf8",
);
expect(importDeclarations(commands)).toEqual([
'import { asNullableRecord as asRecord } from "@openclaw/normalization-core/record-coerce";',
'import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";',
'import type { CommandEntry } from "../../../../packages/gateway-protocol/src/index.js";',
'import { buildBuiltinChatCommands } from "../../../../src/auto-reply/commands-registry.shared.js";',
'import { t } from "../../i18n/index.ts";',
'import { normalizeLowercaseStringOrEmpty } from "../string-coerce.ts";',
]);
expect(importDeclarations(sharedRegistry)).toEqual([
'import { normalizeOptionalLowercaseString } from "../../packages/normalization-core/src/string-coerce.js";',
'import { normalizeStringEntries } from "../../packages/normalization-core/src/string-normalization.js";',
'import { formatFastModeAutoLabel, resolveFastModeModelAutoOnSeconds } from "../shared/fast-mode.js";',
'import { COMMAND_ARG_FORMATTERS } from "./commands-args.js";',
'import type { ChatCommandDefinition, CommandArgChoiceContext, CommandCategory, CommandScope, CommandTier } from "./commands-registry.types.js";',
'import { BASE_THINKING_LEVELS, type ThinkLevel } from "./thinking.shared.js";',
]);
expect(importDeclarations(serverRegistry)).toEqual([
'import { listLoadedChannelPlugins } from "../channels/plugins/registry-loaded.js";',
'import { getActivePluginChannelRegistryVersionFromState } from "../plugins/runtime-channel-state.js";',
'import { assertCommandRegistry, buildBuiltinChatCommands, defineChatCommand } from "./commands-registry.shared.js";',
'import type { ChatCommandDefinition } from "./commands-registry.types.js";',
'import { listThinkingLevels } from "./thinking.js";',
]);
});
});