From 0303af17f3a9639273fbff34111ac9318c7011c5 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 9 Aug 2026 08:48:48 -0700 Subject: [PATCH] test: remove low-value implementation assertions (#121085) * test: remove low-value implementation assertions * test: refresh native i18n inventory --- apps/.i18n/native-source.json | 8 - .../Sources/OpenClaw/DebugSettings.swift | 49 ----- .../Sources/OpenClaw/VoiceWakeSettings.swift | 32 --- .../LowCoverageViewSmokeTests.swift | 8 - extensions/chutes/models.test.ts | 20 +- .../comfy/image-generation-provider.test.ts | 48 ++++ extensions/comfy/workflow-runtime.test.ts | 172 --------------- extensions/comfy/workflow-runtime.ts | 3 - extensions/cua-computer/src/driver-client.ts | 6 +- .../driver-contract-fixtures.test-fixtures.ts | 207 ------------------ .../src/driver-contract-fixtures.test.ts | 76 ------- extensions/diffs/src/manifest.test.ts | 17 -- extensions/huggingface/api.ts | 1 - extensions/huggingface/models.test.ts | 13 -- extensions/huggingface/models.ts | 22 +- extensions/huggingface/onboard.ts | 8 +- extensions/huggingface/provider-catalog.ts | 3 +- extensions/telegram/src/send.chunks.test.ts | 8 +- extensions/telegram/src/send.ts | 8 - extensions/tokenjuice/manifest.test.ts | 12 - extensions/venice/models.test.ts | 13 -- packages/markdown-core/src/index.ts | 1 - packages/markdown-core/src/render-plain.ts | 39 ---- .../src/render.capabilities.test.ts | 13 -- .../src/record-coerce.test.ts | 11 - ...check-plugin-extension-import-boundary.mts | 6 +- ...-test-helper-extension-import-boundary.mts | 4 - .../check-web-fetch-provider-boundaries.mts | 2 +- .../check-web-search-provider-boundaries.mts | 6 +- scripts/test-projects.test-support.mts | 11 +- src/agents/subagent-list.ts | 2 +- src/agents/thinking-block.test.ts | 37 ---- .../tools/agents-wait-tool.test-support.ts | 30 --- src/agents/tools/agents-wait-tool.test.ts | 6 - src/agents/tools/agents-wait-tool.ts | 14 -- .../reply/commands-subagents/action-info.ts | 2 +- src/cli/users-cli.test.ts | 21 +- src/cli/users-cli.ts | 2 - .../heartbeat-config-honor.inventory.test.ts | 46 ---- src/cron/pacing.test.ts | 10 - .../provider-capabilities.contract.test.ts | 77 ------- .../plugin-registration-contract-cases.ts | 35 --- .../plugin-registration-contract.ts | 4 - .../package-manifest.contract.test.ts | 1 + ...gin-registration.parallel.contract.test.ts | 4 - src/shared/subagents-format.test.ts | 17 +- src/shared/subagents-format.ts | 1 - test/helpers/config/config-honor-audit.ts | 155 ------------- .../heartbeat-config-honor.inventory.ts | 135 ------------ test/plugin-extension-import-boundary.test.ts | 64 +----- .../cron-mcp-cleanup-docker-client.test.ts | 5 - test/scripts/docker-e2e-clients.test.ts | 37 ---- test/scripts/openclaw-test-state.test.ts | 13 -- test/scripts/plugins-assertions.test.ts | 11 - test/scripts/prompt-snapshots.test.ts | 96 -------- test/scripts/qa-cli-onboarding.test.ts | 13 -- .../scripts/qa-plugin-install-sources.test.ts | 14 -- test/scripts/test-projects.test.ts | 9 +- ...t-helper-extension-import-boundary.test.ts | 9 +- test/web-provider-boundary.test.ts | 29 +-- .../lib/chat/commands.browser-import.test.ts | 48 ---- 61 files changed, 86 insertions(+), 1688 deletions(-) delete mode 100644 extensions/comfy/workflow-runtime.test.ts delete mode 100644 extensions/cua-computer/src/driver-contract-fixtures.test-fixtures.ts delete mode 100644 extensions/cua-computer/src/driver-contract-fixtures.test.ts delete mode 100644 extensions/diffs/src/manifest.test.ts delete mode 100644 packages/markdown-core/src/render-plain.ts delete mode 100644 src/agents/thinking-block.test.ts delete mode 100644 src/agents/tools/agents-wait-tool.test-support.ts delete mode 100644 src/config/heartbeat-config-honor.inventory.test.ts delete mode 100644 src/cron/pacing.test.ts delete mode 100644 src/media-generation/provider-capabilities.contract.test.ts delete mode 100644 src/plugins/contracts/plugin-registration.parallel.contract.test.ts delete mode 100644 test/helpers/config/config-honor-audit.ts delete mode 100644 test/helpers/config/heartbeat-config-honor.inventory.ts delete mode 100644 test/scripts/docker-e2e-clients.test.ts delete mode 100644 test/scripts/qa-cli-onboarding.test.ts delete mode 100644 test/scripts/qa-plugin-install-sources.test.ts diff --git a/apps/.i18n/native-source.json b/apps/.i18n/native-source.json index 8e784225e6f8..42b9617b5b37 100644 --- a/apps/.i18n/native-source.json +++ b/apps/.i18n/native-source.json @@ -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, diff --git a/apps/macos/Sources/OpenClaw/DebugSettings.swift b/apps/macos/Sources/OpenClaw/DebugSettings.swift index e5522d93e81d..75bab79f570a 100644 --- a/apps/macos/Sources/OpenClaw/DebugSettings.swift +++ b/apps/macos/Sources/OpenClaw/DebugSettings.swift @@ -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 diff --git a/apps/macos/Sources/OpenClaw/VoiceWakeSettings.swift b/apps/macos/Sources/OpenClaw/VoiceWakeSettings.swift index dac256b889e5..24823e23250e 100644 --- a/apps/macos/Sources/OpenClaw/VoiceWakeSettings.swift +++ b/apps/macos/Sources/OpenClaw/VoiceWakeSettings.swift @@ -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 diff --git a/apps/macos/Tests/OpenClawIPCTests/LowCoverageViewSmokeTests.swift b/apps/macos/Tests/OpenClawIPCTests/LowCoverageViewSmokeTests.swift index 9d0ae477eb87..965349c1ba86 100644 --- a/apps/macos/Tests/OpenClawIPCTests/LowCoverageViewSmokeTests.swift +++ b/apps/macos/Tests/OpenClawIPCTests/LowCoverageViewSmokeTests.swift @@ -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() - } } diff --git a/extensions/chutes/models.test.ts b/extensions/chutes/models.test.ts index 5d2ccdac7171..5a0c49f7951b 100644 --- a/extensions/chutes/models.test.ts +++ b/extensions/chutes/models.test.ts @@ -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( diff --git a/extensions/comfy/image-generation-provider.test.ts b/extensions/comfy/image-generation-provider.test.ts index 7ec2f4443ddd..592517ee4959 100644 --- a/extensions/comfy/image-generation-provider.test.ts +++ b/extensions/comfy/image-generation-provider.test.ts @@ -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({ + 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 diff --git a/extensions/comfy/workflow-runtime.test.ts b/extensions/comfy/workflow-runtime.test.ts deleted file mode 100644 index b02f9b069790..000000000000 --- a/extensions/comfy/workflow-runtime.test.ts +++ /dev/null @@ -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({ - 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({ - 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(); - }); -}); diff --git a/extensions/comfy/workflow-runtime.ts b/extensions/comfy/workflow-runtime.ts index 58156e562bc5..1c9d81692a63 100644 --- a/extensions/comfy/workflow-runtime.ts +++ b/extensions/comfy/workflow-runtime.ts @@ -347,9 +347,6 @@ async function readJsonResponse(params: { } } -/** @internal Test-only export. */ -export const readJsonResponseForTest = readJsonResponse; - function resolveFileExtension(params: { fileName?: string; mimeType?: string }): string { const extension = extensionForMime(params.mimeType); if (extension) { diff --git a/extensions/cua-computer/src/driver-client.ts b/extensions/cua-computer/src/driver-client.ts index 134c45aca09d..a9640b6097da 100644 --- a/extensions/cua-computer/src/driver-client.ts +++ b/extensions/cua-computer/src/driver-client.ts @@ -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, diff --git a/extensions/cua-computer/src/driver-contract-fixtures.test-fixtures.ts b/extensions/cua-computer/src/driver-contract-fixtures.test-fixtures.ts deleted file mode 100644 index 4bdeac1ac83e..000000000000 --- a/extensions/cua-computer/src/driver-contract-fixtures.test-fixtures.ts +++ /dev/null @@ -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; diff --git a/extensions/cua-computer/src/driver-contract-fixtures.test.ts b/extensions/cua-computer/src/driver-contract-fixtures.test.ts deleted file mode 100644 index f2a86a3f913b..000000000000 --- a/extensions/cua-computer/src/driver-contract-fixtures.test.ts +++ /dev/null @@ -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"]); - }); -}); diff --git a/extensions/diffs/src/manifest.test.ts b/extensions/diffs/src/manifest.test.ts deleted file mode 100644 index 05a3f477e4c3..000000000000 --- a/extensions/diffs/src/manifest.test.ts +++ /dev/null @@ -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; -}; - -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"); - }); -}); diff --git a/extensions/huggingface/api.ts b/extensions/huggingface/api.ts index 7dc9fc3c05c9..1837b537b9b0 100644 --- a/extensions/huggingface/api.ts +++ b/extensions/huggingface/api.ts @@ -1,6 +1,5 @@ // Huggingface API module exposes the plugin public contract. export { - buildHuggingfaceModelDefinition, discoverHuggingfaceModels, HUGGINGFACE_BASE_URL, HUGGINGFACE_MODEL_CATALOG, diff --git a/extensions/huggingface/models.test.ts b/extensions/huggingface/models.test.ts index 48e1509ed0b0..f0e76c57ecaa 100644 --- a/extensions/huggingface/models.test.ts +++ b/extensions/huggingface/models.test.ts @@ -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", diff --git a/extensions/huggingface/models.ts b/extensions/huggingface/models.ts index 58e2dab90e6f..3a3447bce0a6 100644 --- a/extensions/huggingface/models.ts +++ b/extensions/huggingface/models.ts @@ -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 { 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, diff --git a/extensions/huggingface/onboard.ts b/extensions/huggingface/onboard.ts index 661f1bd359cc..3661caef0ebe 100644 --- a/extensions/huggingface/onboard.ts +++ b/extensions/huggingface/onboard.ts @@ -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" }], }), }); diff --git a/extensions/huggingface/provider-catalog.ts b/extensions/huggingface/provider-catalog.ts index 00ec5c1b8dde..11703a4bf095 100644 --- a/extensions/huggingface/provider-catalog.ts +++ b/extensions/huggingface/provider-catalog.ts @@ -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", diff --git a/extensions/telegram/src/send.chunks.test.ts b/extensions/telegram/src/send.chunks.test.ts index c7c8673ba8e9..4c9c00c67efd 100644 --- a/extensions/telegram/src/send.chunks.test.ts +++ b/extensions/telegram/src/send.chunks.test.ts @@ -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); diff --git a/extensions/telegram/src/send.ts b/extensions/telegram/src/send.ts index be9ad2039076..884b09cb9085 100644 --- a/extensions/telegram/src/send.ts +++ b/extensions/telegram/src/send.ts @@ -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); -} diff --git a/extensions/tokenjuice/manifest.test.ts b/extensions/tokenjuice/manifest.test.ts index 01124917fae9..51528cd61b91 100644 --- a/extensions/tokenjuice/manifest.test.ts +++ b/extensions/tokenjuice/manifest.test.ts @@ -2,10 +2,6 @@ import fs from "node:fs"; import { describe, expect, it } from "vitest"; -type TokenjuicePackageManifest = { - dependencies?: Record; -}; - 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"), diff --git a/extensions/venice/models.test.ts b/extensions/venice/models.test.ts index 97e4255a4637..2ddfbe00d310 100644 --- a/extensions/venice/models.test.ts +++ b/extensions/venice/models.test.ts @@ -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 [ diff --git a/packages/markdown-core/src/index.ts b/packages/markdown-core/src/index.ts index 205745e6bab1..2ccec16e3729 100644 --- a/packages/markdown-core/src/index.ts +++ b/packages/markdown-core/src/index.ts @@ -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"; diff --git a/packages/markdown-core/src/render-plain.ts b/packages/markdown-core/src/render-plain.ts deleted file mode 100644 index 6b26304439d1..000000000000 --- a/packages/markdown-core/src/render-plain.ts +++ /dev/null @@ -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); -} diff --git a/packages/markdown-core/src/render.capabilities.test.ts b/packages/markdown-core/src/render.capabilities.test.ts index 8e7dd90d7f69..1d428b89b9f4 100644 --- a/packages/markdown-core/src/render.capabilities.test.ts +++ b/packages/markdown-core/src/render.capabilities.test.ts @@ -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"); - }); }); diff --git a/packages/normalization-core/src/record-coerce.test.ts b/packages/normalization-core/src/record-coerce.test.ts index b3225019f7dc..a41b6a44e74e 100644 --- a/packages/normalization-core/src/record-coerce.test.ts +++ b/packages/normalization-core/src/record-coerce.test.ts @@ -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"); - }); }); diff --git a/scripts/check-plugin-extension-import-boundary.mts b/scripts/check-plugin-extension-import-boundary.mts index b744e7cbcb6e..277e11c6ae1a 100644 --- a/scripts/check-plugin-extension-import-boundary.mts +++ b/scripts/check-plugin-extension-import-boundary.mts @@ -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 => 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[], ) { diff --git a/scripts/check-test-helper-extension-import-boundary.mts b/scripts/check-test-helper-extension-import-boundary.mts index d369357e6399..0e6fee4f1541 100644 --- a/scripts/check-test-helper-extension-import-boundary.mts +++ b/scripts/check-test-helper-extension-import-boundary.mts @@ -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. */ diff --git a/scripts/check-web-fetch-provider-boundaries.mts b/scripts/check-web-fetch-provider-boundaries.mts index 6122a985f5a8..e6a3a3946c5b 100644 --- a/scripts/check-web-fetch-provider-boundaries.mts +++ b/scripts/check-web-fetch-provider-boundaries.mts @@ -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 { diff --git a/scripts/check-web-search-provider-boundaries.mts b/scripts/check-web-search-provider-boundaries.mts index d1f527eb2c71..fcf971c2488f 100644 --- a/scripts/check-web-search-provider-boundaries.mts +++ b/scripts/check-web-search-provider-boundaries.mts @@ -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 { +async function readExpectedInventory(): Promise { 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 { /** * 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); } diff --git a/scripts/test-projects.test-support.mts b/scripts/test-projects.test-support.mts index a1e4d2ea1d89..7bfdbceb7b51 100644 --- a/scripts/test-projects.test-support.mts +++ b/scripts/test-projects.test-support.mts @@ -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", ], diff --git a/src/agents/subagent-list.ts b/src/agents/subagent-list.ts index a41053c6e91a..6b7d30f0e82a 100644 --- a/src/agents/subagent-list.ts +++ b/src/agents/subagent-list.ts @@ -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, diff --git a/src/agents/thinking-block.test.ts b/src/agents/thinking-block.test.ts deleted file mode 100644 index eb7cc2dc8c23..000000000000 --- a/src/agents/thinking-block.test.ts +++ /dev/null @@ -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); - }); -}); diff --git a/src/agents/tools/agents-wait-tool.test-support.ts b/src/agents/tools/agents-wait-tool.test-support.ts deleted file mode 100644 index e7d494631e56..000000000000 --- a/src/agents/tools/agents-wait-tool.test-support.ts +++ /dev/null @@ -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): boolean; - readResolvedWaitState(targets: readonly WaitTarget[], errors: readonly WaitError[]): unknown; - readWaitState(ids: readonly string[], currentSessionKeys: ReadonlySet): unknown; - resolveWaitTargets( - ids: readonly string[], - currentSessionKeys: ReadonlySet, - ): { targets: WaitTarget[]; errors: WaitError[] }; - waitForCollector(params: { - ids: readonly string[]; - currentSessionKeys: ReadonlySet; - timeoutMs: number; - signal?: AbortSignal; - }): Promise; - }; -}; - -function getTestApi(): AgentsWaitToolTestApi { - return (globalThis as Record)[ - Symbol.for("openclaw.agentsWaitToolTestApi") - ] as AgentsWaitToolTestApi; -} - -export const testing = getTestApi().testing; diff --git a/src/agents/tools/agents-wait-tool.test.ts b/src/agents/tools/agents-wait-tool.test.ts index e8a484c2c07d..76b4f978daca 100644 --- a/src/agents/tools/agents-wait-tool.test.ts +++ b/src/agents/tools/agents-wait-tool.test.ts @@ -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")); diff --git a/src/agents/tools/agents-wait-tool.ts b/src/agents/tools/agents-wait-tool.ts index 828794f455e7..2c18e1fb480a 100644 --- a/src/agents/tools/agents-wait-tool.ts +++ b/src/agents/tools/agents-wait-tool.ts @@ -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)[Symbol.for("openclaw.agentsWaitToolTestApi")] = { - testing, - }; -} diff --git a/src/auto-reply/reply/commands-subagents/action-info.ts b/src/auto-reply/reply/commands-subagents/action-info.ts index 5326c16946e6..93ad5192fc64 100644 --- a/src/auto-reply/reply/commands-subagents/action-info.ts +++ b/src/auto-reply/reply/commands-subagents/action-info.ts @@ -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"; diff --git a/src/cli/users-cli.test.ts b/src/cli/users-cli.test.ts index 91d2cd0ac2ba..85c76d1c048c 100644 --- a/src/cli/users-cli.test.ts +++ b/src/cli/users-cli.test.ts @@ -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"); - }); }); diff --git a/src/cli/users-cli.ts b/src/cli/users-cli.ts index a00664ef2ac8..3814c26f0637 100644 --- a/src/cli/users-cli.ts +++ b/src/cli/users-cli.ts @@ -75,5 +75,3 @@ export function registerUsersCli(program: Command) { applyParentDefaultHelpAction(users); } - -export const testApi = { writeUsersList }; diff --git a/src/config/heartbeat-config-honor.inventory.test.ts b/src/config/heartbeat-config-honor.inventory.test.ts deleted file mode 100644 index 8ebcafe6379d..000000000000 --- a/src/config/heartbeat-config-honor.inventory.test.ts +++ /dev/null @@ -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([]); - }); -}); diff --git a/src/cron/pacing.test.ts b/src/cron/pacing.test.ts deleted file mode 100644 index 787732dc58c1..000000000000 --- a/src/cron/pacing.test.ts +++ /dev/null @@ -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", - ); - }); -}); diff --git a/src/media-generation/provider-capabilities.contract.test.ts b/src/media-generation/provider-capabilities.contract.test.ts deleted file mode 100644 index 36ef6176063c..000000000000 --- a/src/media-generation/provider-capabilities.contract.test.ts +++ /dev/null @@ -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 = { - minimax: ["minimax", "minimax-portal"], -}; - -const EXPECTED_BUNDLED_MUSIC_PROVIDER_IDS_BY_PLUGIN: Record = { - 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], - ); - } - }); -}); diff --git a/src/plugin-sdk/test-helpers/plugin-registration-contract-cases.ts b/src/plugin-sdk/test-helpers/plugin-registration-contract-cases.ts index a7e83dcc184f..a12028f1fa34 100644 --- a/src/plugin-sdk/test-helpers/plugin-registration-contract-cases.ts +++ b/src/plugin-sdk/test-helpers/plugin-registration-contract-cases.ts @@ -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; diff --git a/src/plugin-sdk/test-helpers/plugin-registration-contract.ts b/src/plugin-sdk/test-helpers/plugin-registration-contract.ts index 7970d22c6fe9..88b89b58006a 100644 --- a/src/plugin-sdk/test-helpers/plugin-registration-contract.ts +++ b/src/plugin-sdk/test-helpers/plugin-registration-contract.ts @@ -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; diff --git a/src/plugins/contracts/package-manifest.contract.test.ts b/src/plugins/contracts/package-manifest.contract.test.ts index 81fa89e71651..d89fc8ddebe6 100644 --- a/src/plugins/contracts/package-manifest.contract.test.ts +++ b/src/plugins/contracts/package-manifest.contract.test.ts @@ -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" }, { diff --git a/src/plugins/contracts/plugin-registration.parallel.contract.test.ts b/src/plugins/contracts/plugin-registration.parallel.contract.test.ts deleted file mode 100644 index da9b0ac631a7..000000000000 --- a/src/plugins/contracts/plugin-registration.parallel.contract.test.ts +++ /dev/null @@ -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); diff --git a/src/shared/subagents-format.test.ts b/src/shared/subagents-format.test.ts index e02f0d7b07e0..5565103fdbf8 100644 --- a/src/shared/subagents-format.test.ts +++ b/src/shared/subagents-format.test.ts @@ -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"); diff --git a/src/shared/subagents-format.ts b/src/shared/subagents-format.ts index 904dcec0b37c..f0da689415d5 100644 --- a/src/shared/subagents-format.ts +++ b/src/shared/subagents-format.ts @@ -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) { diff --git a/test/helpers/config/config-honor-audit.ts b/test/helpers/config/config-honor-audit.ts deleted file mode 100644 index cb7fb2136a0f..000000000000 --- a/test/helpers/config/config-honor-audit.ts +++ /dev/null @@ -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 }).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(); - 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 }).properties?.[segment] ?? null; - } - const properties = (current as { properties?: Record } | 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 => row !== null); - - return { - schemaKeys, - missingKeys, - extraKeys, - missingSchemaPaths, - missingFiles, - missingProofs, - }; -} diff --git a/test/helpers/config/heartbeat-config-honor.inventory.ts b/test/helpers/config/heartbeat-config-honor.inventory.ts deleted file mode 100644 index 9039d38616e5..000000000000 --- a/test/helpers/config/heartbeat-config-honor.inventory.ts +++ /dev/null @@ -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"], - }, -]; diff --git a/test/plugin-extension-import-boundary.test.ts b/test/plugin-extension-import-boundary.test.ts index 0ade17ffd4e3..1202081d8a9f 100644 --- a/test/plugin-extension-import-boundary.test.ts +++ b/test/plugin-extension-import-boundary.test.ts @@ -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>, - 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); diff --git a/test/scripts/cron-mcp-cleanup-docker-client.test.ts b/test/scripts/cron-mcp-cleanup-docker-client.test.ts index d14a53b1d722..3cbfde817aca 100644 --- a/test/scripts/cron-mcp-cleanup-docker-client.test.ts +++ b/test/scripts/cron-mcp-cleanup-docker-client.test.ts @@ -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( diff --git a/test/scripts/docker-e2e-clients.test.ts b/test/scripts/docker-e2e-clients.test.ts deleted file mode 100644 index 722b12c3810e..000000000000 --- a/test/scripts/docker-e2e-clients.test.ts +++ /dev/null @@ -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("<<>>"); - expect(source).toContain("openclaw.runtime-context"); - expect(source).toContain("doctor repair left runtime context in active transcript"); - }); -}); diff --git a/test/scripts/openclaw-test-state.test.ts b/test/scripts/openclaw-test-state.test.ts index 7add06b37920..070a11daeff2 100644 --- a/test/scripts/openclaw-test-state.test.ts +++ b/test/scripts/openclaw-test-state.test.ts @@ -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"); - }); }); diff --git a/test/scripts/plugins-assertions.test.ts b/test/scripts/plugins-assertions.test.ts index b9d8491eb328..62372d9c0c03 100644 --- a/test/scripts/plugins-assertions.test.ts +++ b/test/scripts/plugins-assertions.test.ts @@ -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", diff --git a/test/scripts/prompt-snapshots.test.ts b/test/scripts/prompt-snapshots.test.ts index f8f495236a20..81220a1f37ff 100644 --- a/test/scripts/prompt-snapshots.test.ts +++ b/test/scripts/prompt-snapshots.test.ts @@ -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 = [ diff --git a/test/scripts/qa-cli-onboarding.test.ts b/test/scripts/qa-cli-onboarding.test.ts deleted file mode 100644 index ce636c3c97bf..000000000000 --- a/test/scripts/qa-cli-onboarding.test.ts +++ /dev/null @@ -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: []"); - }); -}); diff --git a/test/scripts/qa-plugin-install-sources.test.ts b/test/scripts/qa-plugin-install-sources.test.ts deleted file mode 100644 index 1db3d258f2ed..000000000000 --- a/test/scripts/qa-plugin-install-sources.test.ts +++ /dev/null @@ -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}",`); - }); -}); diff --git a/test/scripts/test-projects.test.ts b/test/scripts/test-projects.test.ts index 0161e0279758..c11267463129 100644 --- a/test/scripts/test-projects.test.ts +++ b/test/scripts/test-projects.test.ts @@ -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": [ diff --git a/test/test-helper-extension-import-boundary.test.ts b/test/test-helper-extension-import-boundary.test.ts index b62171dbc780..07d6e5ca73e7 100644 --- a/test/test-helper-extension-import-boundary.test.ts +++ b/test/test-helper-extension-import-boundary.test.ts @@ -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); diff --git a/test/web-provider-boundary.test.ts b/test/web-provider-boundary.test.ts index 05ca22e50b8c..2a26e3c43543 100644 --- a/test/web-provider-boundary.test.ts +++ b/test/web-provider-boundary.test.ts @@ -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([]); diff --git a/ui/src/lib/chat/commands.browser-import.test.ts b/ui/src/lib/chat/commands.browser-import.test.ts index 71a1f77235c0..1dd245aa90e6 100644 --- a/ui/src/lib/chat/commands.browser-import.test.ts +++ b/ui/src/lib/chat/commands.browser-import.test.ts @@ -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";', - ]); - }); });