chore: Enable `typescript/no-explicit-any` rule.

main
cpojer 2026-02-02 15:45:05 +09:00
parent baa1e95b9d
commit 935a0e5708
No known key found for this signature in database
GPG Key ID: C29F94A3201118AF
65 changed files with 248 additions and 80 deletions

View File

@ -14,6 +14,7 @@
"oxc/no-accumulating-spread": "off",
"oxc/no-async-endpoint-handlers": "off",
"oxc/no-map-spread": "off",
"typescript/no-explicit-any": "error",
"typescript/no-extraneous-class": "off",
"typescript/no-unsafe-type-assertion": "off",
"unicorn/consistent-function-scoping": "off",

View File

@ -1216,7 +1216,9 @@ describe("BlueBubbles webhook monitor", () => {
const core = createMockRuntime();
// Use a timing-aware debouncer test double that respects debounceMs/buildKey/shouldDebounce.
// oxlint-disable-next-line typescript/no-explicit-any
core.channel.debounce.createInboundDebouncer = vi.fn((params: any) => {
// oxlint-disable-next-line typescript/no-explicit-any
type Item = any;
const buckets = new Map<
string,

View File

@ -26,7 +26,9 @@ function createRuntime(): { runtime: PluginRuntime; mocks: LineRuntimeMocks } {
? (lineConfig.accounts?.[accountId] ?? {})
: lineConfig;
const hasToken =
// oxlint-disable-next-line typescript/no-explicit-any
Boolean((entry as any).channelAccessToken) || Boolean((entry as any).tokenFile);
// oxlint-disable-next-line typescript/no-explicit-any
const hasSecret = Boolean((entry as any).channelSecret) || Boolean((entry as any).secretFile);
return { tokenSource: hasToken && hasSecret ? "config" : "none" };
},

View File

@ -12,6 +12,7 @@ vi.mock("../../../src/agents/pi-embedded-runner.js", () => {
import { runEmbeddedPiAgent } from "../../../src/agents/pi-embedded-runner.js";
import { createLlmTaskTool } from "./llm-task-tool.js";
// oxlint-disable-next-line typescript/no-explicit-any
function fakeApi(overrides: any = {}) {
return {
id: "llm-task",
@ -32,26 +33,31 @@ describe("llm-task tool (json-only)", () => {
beforeEach(() => vi.clearAllMocks());
it("returns parsed json", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: JSON.stringify({ foo: "bar" }) }],
});
const tool = createLlmTaskTool(fakeApi());
const res = await tool.execute("id", { prompt: "return foo" });
// oxlint-disable-next-line typescript/no-explicit-any
expect((res as any).details.json).toEqual({ foo: "bar" });
});
it("strips fenced json", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: '```json\n{"ok":true}\n```' }],
});
const tool = createLlmTaskTool(fakeApi());
const res = await tool.execute("id", { prompt: "return ok" });
// oxlint-disable-next-line typescript/no-explicit-any
expect((res as any).details.json).toEqual({ ok: true });
});
it("validates schema", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: JSON.stringify({ foo: "bar" }) }],
@ -64,10 +70,12 @@ describe("llm-task tool (json-only)", () => {
additionalProperties: false,
};
const res = await tool.execute("id", { prompt: "return foo", schema });
// oxlint-disable-next-line typescript/no-explicit-any
expect((res as any).details.json).toEqual({ foo: "bar" });
});
it("throws on invalid json", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: "not-json" }],
@ -77,6 +85,7 @@ describe("llm-task tool (json-only)", () => {
});
it("throws on schema mismatch", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: JSON.stringify({ foo: 1 }) }],
@ -87,18 +96,21 @@ describe("llm-task tool (json-only)", () => {
});
it("passes provider/model overrides to embedded runner", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: JSON.stringify({ ok: true }) }],
});
const tool = createLlmTaskTool(fakeApi());
await tool.execute("id", { prompt: "x", provider: "anthropic", model: "claude-4-sonnet" });
// oxlint-disable-next-line typescript/no-explicit-any
const call = (runEmbeddedPiAgent as any).mock.calls[0]?.[0];
expect(call.provider).toBe("anthropic");
expect(call.model).toBe("claude-4-sonnet");
});
it("enforces allowedModels", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: JSON.stringify({ ok: true }) }],
@ -112,12 +124,14 @@ describe("llm-task tool (json-only)", () => {
});
it("disables tools for embedded run", async () => {
// oxlint-disable-next-line typescript/no-explicit-any
(runEmbeddedPiAgent as any).mockResolvedValueOnce({
meta: {},
payloads: [{ text: JSON.stringify({ ok: true }) }],
});
const tool = createLlmTaskTool(fakeApi());
await tool.execute("id", { prompt: "x" });
// oxlint-disable-next-line typescript/no-explicit-any
const call = (runEmbeddedPiAgent as any).mock.calls[0]?.[0];
expect(call.disableTools).toBe(true);
});

View File

@ -15,7 +15,9 @@ async function loadRunEmbeddedPiAgent(): Promise<RunEmbeddedPiAgentFn> {
// Source checkout (tests/dev)
try {
const mod = await import("../../../src/agents/pi-embedded-runner.js");
// oxlint-disable-next-line typescript/no-explicit-any
if (typeof (mod as any).runEmbeddedPiAgent === "function") {
// oxlint-disable-next-line typescript/no-explicit-any
return (mod as any).runEmbeddedPiAgent;
}
} catch {
@ -111,7 +113,9 @@ export function createLlmTaskTool(api: OpenClawPluginApi) {
undefined;
const authProfileId =
// oxlint-disable-next-line typescript/no-explicit-any
(typeof (params as any).authProfileId === "string" &&
// oxlint-disable-next-line typescript/no-explicit-any
(params as any).authProfileId.trim()) ||
(typeof pluginCfg.defaultAuthProfileId === "string" &&
pluginCfg.defaultAuthProfileId.trim()) ||
@ -150,6 +154,7 @@ export function createLlmTaskTool(api: OpenClawPluginApi) {
: undefined,
};
// oxlint-disable-next-line typescript/no-explicit-any
const input = (params as any).input as unknown;
let inputJson: string;
try {
@ -192,6 +197,7 @@ export function createLlmTaskTool(api: OpenClawPluginApi) {
disableTools: true,
});
// oxlint-disable-next-line typescript/no-explicit-any
const text = collectText((result as any).payloads);
if (!text) {
throw new Error("LLM returned empty output");
@ -205,9 +211,11 @@ export function createLlmTaskTool(api: OpenClawPluginApi) {
throw new Error("LLM returned invalid JSON");
}
// oxlint-disable-next-line typescript/no-explicit-any
const schema = (params as any).schema as unknown;
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
const ajv = new Ajv({ allErrors: true, strict: false });
// oxlint-disable-next-line typescript/no-explicit-any
const validate = ajv.compile(schema as any);
const ok = validate(parsed);
if (!ok) {

View File

@ -36,8 +36,9 @@ function fakeApi(overrides: Partial<OpenClawPluginApi> = {}): OpenClawPluginApi
id: "lobster",
name: "lobster",
source: "test",
config: {} as any,
config: {},
pluginConfig: {},
// oxlint-disable-next-line typescript/no-explicit-any
runtime: { version: "test" } as any,
logger: { info() {}, warn() {}, error() {}, debug() {} },
registerTool() {},
@ -58,7 +59,7 @@ function fakeApi(overrides: Partial<OpenClawPluginApi> = {}): OpenClawPluginApi
function fakeCtx(overrides: Partial<OpenClawPluginToolContext> = {}): OpenClawPluginToolContext {
return {
config: {} as any,
config: {},
workspaceDir: "/tmp",
agentDir: "/tmp",
agentId: "main",

View File

@ -180,9 +180,13 @@ describeLive("memory plugin live tests", () => {
const liveApiKey = process.env.OPENAI_API_KEY ?? "";
// Mock plugin API
// oxlint-disable-next-line typescript/no-explicit-any
const registeredTools: any[] = [];
// oxlint-disable-next-line typescript/no-explicit-any
const registeredClis: any[] = [];
// oxlint-disable-next-line typescript/no-explicit-any
const registeredServices: any[] = [];
// oxlint-disable-next-line typescript/no-explicit-any
const registeredHooks: Record<string, any[]> = {};
const logs: string[] = [];
@ -207,15 +211,19 @@ describeLive("memory plugin live tests", () => {
error: (msg: string) => logs.push(`[error] ${msg}`),
debug: (msg: string) => logs.push(`[debug] ${msg}`),
},
// oxlint-disable-next-line typescript/no-explicit-any
registerTool: (tool: any, opts: any) => {
registeredTools.push({ tool, opts });
},
// oxlint-disable-next-line typescript/no-explicit-any
registerCli: (registrar: any, opts: any) => {
registeredClis.push({ registrar, opts });
},
// oxlint-disable-next-line typescript/no-explicit-any
registerService: (service: any) => {
registeredServices.push(service);
},
// oxlint-disable-next-line typescript/no-explicit-any
on: (hookName: string, handler: any) => {
if (!registeredHooks[hookName]) {
registeredHooks[hookName] = [];
@ -226,6 +234,7 @@ describeLive("memory plugin live tests", () => {
};
// Register plugin
// oxlint-disable-next-line typescript/no-explicit-any
memoryPlugin.register(mockApi as any);
// Check registration

View File

@ -355,7 +355,7 @@ export const tlonPlugin: ChannelPlugin = {
} finally {
await api.delete();
}
} catch (error: any) {
} catch (error) {
return { ok: false, error: error?.message ?? String(error) };
}
},

View File

@ -15,7 +15,7 @@ export async function fetchGroupChanges(
return changes;
}
return null;
} catch (error: any) {
} catch (error) {
runtime.log?.(
`[tlon] Failed to fetch changes (falling back to full init): ${error?.message ?? String(error)}`,
);
@ -31,6 +31,7 @@ export async function fetchAllChannels(
runtime.log?.("[tlon] Attempting auto-discovery of group channels...");
const changes = await fetchGroupChanges(api, runtime, 5);
// oxlint-disable-next-line typescript/no-explicit-any
let initData: any;
if (changes) {
runtime.log?.("[tlon] Changes data received, using full init for channel extraction");
@ -41,6 +42,7 @@ export async function fetchAllChannels(
const channels: string[] = [];
if (initData && initData.groups) {
// oxlint-disable-next-line typescript/no-explicit-any
for (const groupData of Object.values(initData.groups as Record<string, any>)) {
if (groupData && typeof groupData === "object" && groupData.channels) {
for (const channelNest of Object.keys(groupData.channels)) {
@ -63,7 +65,7 @@ export async function fetchAllChannels(
}
return channels;
} catch (error: any) {
} catch (error) {
runtime.log?.(`[tlon] Auto-discovery failed: ${error?.message ?? String(error)}`);
runtime.log?.(
"[tlon] To monitor group channels, add them to config: channels.tlon.groupChannels",

View File

@ -35,11 +35,13 @@ export async function fetchChannelHistory(
const scryPath = `/channels/v4/${channelNest}/posts/newest/${count}/outline.json`;
runtime?.log?.(`[tlon] Fetching history: ${scryPath}`);
// oxlint-disable-next-line typescript/no-explicit-any
const data: any = await api.scry(scryPath);
if (!data) {
return [];
}
// oxlint-disable-next-line typescript/no-explicit-any
let posts: any[] = [];
if (Array.isArray(data)) {
posts = data;
@ -65,7 +67,7 @@ export async function fetchChannelHistory(
runtime?.log?.(`[tlon] Extracted ${messages.length} messages from history`);
return messages;
} catch (error: any) {
} catch (error) {
runtime?.log?.(`[tlon] Error fetching channel history: ${error?.message ?? String(error)}`);
return [];
}

View File

@ -88,7 +88,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
error: (message) => runtime.error?.(message),
},
});
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Failed to authenticate: ${error?.message ?? String(error)}`);
throw error;
}
@ -102,7 +102,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
if (discoveredChannels.length > 0) {
groupChannels = discoveredChannels;
}
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Auto-discovery failed: ${error?.message ?? String(error)}`);
}
}
@ -120,6 +120,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
runtime.log?.("[tlon] No group channels to monitor (DMs only)");
}
// oxlint-disable-next-line typescript/no-explicit-any
const handleIncomingDM = async (update: any) => {
try {
const memo = update?.response?.add?.memo;
@ -154,11 +155,12 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
isGroup: false,
timestamp: memo.sent || Date.now(),
});
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Error handling DM: ${error?.message ?? String(error)}`);
}
};
// oxlint-disable-next-line typescript/no-explicit-any
const handleIncomingGroupMessage = (channelNest: string) => async (update: any) => {
try {
const parsed = parseChannelNest(channelNest);
@ -235,7 +237,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
timestamp: content.sent || Date.now(),
parentId,
});
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Error handling group message: ${error?.message ?? String(error)}`);
}
};
@ -294,7 +296,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
"2. Key decisions or conclusions\n" +
"3. Action items if any\n" +
"4. Notable participants";
} catch (error: any) {
} catch (error) {
const errorMsg = `Sorry, I encountered an error while fetching the channel history: ${error?.message ?? String(error)}`;
if (isGroup && groupChannel) {
const parsed = parseChannelNest(groupChannel);
@ -437,7 +439,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
});
subscribedChannels.add(channelNest);
runtime.log?.(`[tlon] Subscribed to group channel: ${channelNest}`);
} catch (error: any) {
} catch (error) {
runtime.error?.(
`[tlon] Failed to subscribe to ${channelNest}: ${error?.message ?? String(error)}`,
);
@ -463,7 +465,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
});
subscribedDMs.add(dmShip);
runtime.log?.(`[tlon] Subscribed to DM with ${dmShip}`);
} catch (error: any) {
} catch (error) {
runtime.error?.(
`[tlon] Failed to subscribe to DM with ${dmShip}: ${error?.message ?? String(error)}`,
);
@ -485,7 +487,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
await subscribeToChannel(channelNest);
}
}
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Channel refresh failed: ${error?.message ?? String(error)}`);
}
}
@ -500,7 +502,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
dmShips = dmList;
runtime.log?.(`[tlon] Found ${dmShips.length} DM conversation(s)`);
}
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Failed to fetch DM list: ${error?.message ?? String(error)}`);
}
@ -544,7 +546,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
} finally {
try {
await api?.close();
} catch (error: any) {
} catch (error) {
runtime.error?.(`[tlon] Cleanup error: ${error?.message ?? String(error)}`);
}
}

View File

@ -49,33 +49,39 @@ export function extractMessageText(content: unknown): string {
return "";
}
return content
.map((block: any) => {
if (block.inline && Array.isArray(block.inline)) {
return block.inline
.map((item: any) => {
if (typeof item === "string") {
return item;
}
if (item && typeof item === "object") {
if (item.ship) {
return item.ship;
}
if (item.break !== undefined) {
return "\n";
}
if (item.link && item.link.href) {
return item.link.href;
}
}
return "";
})
.join("");
}
return "";
})
.join("\n")
.trim();
return (
content
// oxlint-disable-next-line typescript/no-explicit-any
.map((block: any) => {
if (block.inline && Array.isArray(block.inline)) {
return (
block.inline
// oxlint-disable-next-line typescript/no-explicit-any
.map((item: any) => {
if (typeof item === "string") {
return item;
}
if (item && typeof item === "object") {
if (item.ship) {
return item.ship;
}
if (item.break !== undefined) {
return "\n";
}
if (item.link && item.link.href) {
return item.link.href;
}
}
return "";
})
.join("")
);
}
return "";
})
.join("\n")
.trim()
);
}
export function isSummarizationRequest(messageText: string): boolean {

View File

@ -12,6 +12,7 @@ const plugin = {
configSchema: emptyPluginConfigSchema(),
register(api: OpenClawPluginApi) {
setTwitchRuntime(api.runtime);
// oxlint-disable-next-line typescript/no-explicit-any
api.registerChannel({ plugin: twitchPlugin as any });
},
};

View File

@ -155,7 +155,6 @@ export function extractMentions(message: string): string[] {
const mentions: string[] = [];
let match: RegExpExecArray | null;
// biome-ignore lint/suspicious/noAssignInExpressions: Standard regex iteration pattern
while ((match = mentionRegex.exec(message)) !== null) {
const username = match[1];
if (username) {

View File

@ -64,7 +64,6 @@ export const twitchOutbound: ChannelOutboundAdapter = {
return { ok: true, to: normalizedTo };
}
// Fallback to first allowFrom entry
// biome-ignore lint/style/noNonNullAssertion: length > 0 check ensures element exists
return { ok: true, to: allowList[0] };
}
@ -74,7 +73,6 @@ export const twitchOutbound: ChannelOutboundAdapter = {
// No target provided, use allowFrom fallback
if (allowList.length > 0) {
// biome-ignore lint/style/noNonNullAssertion: length > 0 check ensures element exists
return { ok: true, to: allowList[0] };
}

View File

@ -21,10 +21,12 @@ const mockQuit = vi.fn();
const mockUnbind = vi.fn();
// Event handler storage for testing
// oxlint-disable-next-line typescript/no-explicit-any
const messageHandlers: Array<(channel: string, user: string, message: string, msg: any) => void> =
[];
// Mock functions that track handlers and return unbind objects
// oxlint-disable-next-line typescript/no-explicit-any
const mockOnMessage = vi.fn((handler: any) => {
messageHandlers.push(handler);
return { unbind: mockUnbind };
@ -269,6 +271,7 @@ describe("TwitchClientManager", () => {
// Check the stored handler is handler2
const key = manager.getAccountKey(testAccount);
// oxlint-disable-next-line typescript/no-explicit-any
expect((manager as any).messageHandlers.get(key)).toBe(handler2);
});
});
@ -290,7 +293,9 @@ describe("TwitchClientManager", () => {
await manager.disconnect(testAccount);
const key = manager.getAccountKey(testAccount);
// oxlint-disable-next-line typescript/no-explicit-any
expect((manager as any).clients.has(key)).toBe(false);
// oxlint-disable-next-line typescript/no-explicit-any
expect((manager as any).messageHandlers.has(key)).toBe(false);
});
@ -309,6 +314,7 @@ describe("TwitchClientManager", () => {
expect(mockQuit).toHaveBeenCalledTimes(1);
const key2 = manager.getAccountKey(testAccount2);
// oxlint-disable-next-line typescript/no-explicit-any
expect((manager as any).clients.has(key2)).toBe(true);
});
});
@ -321,7 +327,9 @@ describe("TwitchClientManager", () => {
await manager.disconnectAll();
expect(mockQuit).toHaveBeenCalledTimes(2);
// oxlint-disable-next-line typescript/no-explicit-any
expect((manager as any).clients.size).toBe(0);
// oxlint-disable-next-line typescript/no-explicit-any
expect((manager as any).messageHandlers.size).toBe(0);
});
@ -387,6 +395,7 @@ describe("TwitchClientManager", () => {
it("should create client if not already connected", async () => {
// Clear the existing client
// oxlint-disable-next-line typescript/no-explicit-any
(manager as any).clients.clear();
// Reset connect call count for this specific test

View File

@ -49,6 +49,7 @@ function median(values: number[]): number {
async function runModel(opts: {
label: string;
// oxlint-disable-next-line typescript/no-explicit-any
model: Model<any>;
apiKey: string;
runs: number;

View File

@ -193,7 +193,7 @@ for (const [login, lines] of linesByLogin.entries()) {
}
let user = apiByLogin.get(login);
if (!user) {
user = fetchUser(login);
user = fetchUser(login) || undefined;
}
if (user) {
const contributions = contributionsByLogin.get(login) ?? 0;
@ -256,7 +256,9 @@ function run(cmd: string): string {
}).trim();
}
// oxlint-disable-next-line typescript/no-explicit-any
function parsePaginatedJson(raw: string): any[] {
// oxlint-disable-next-line typescript/no-explicit-any
const items: any[] = [];
for (const line of raw.split("\n")) {
if (!line.trim()) {

View File

@ -73,7 +73,7 @@ const applyPatchSchema = Type.Object({
export function createApplyPatchTool(
options: { cwd?: string; sandboxRoot?: string } = {},
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
// oxlint-disable-next-line typescript/no-explicit-any
): AgentTool<any, ApplyPatchToolDetails> {
const cwd = options.cwd ?? process.cwd();
const sandboxRoot = options.sandboxRoot;

View File

@ -20,8 +20,7 @@ const OAUTH_PROVIDER_IDS = new Set<OAuthProvider>(
);
function isOAuthProvider(provider: string): provider is OAuthProvider {
// biome-ignore lint/suspicious/noExplicitAny: type guard needs runtime check
return OAUTH_PROVIDER_IDS.has(provider as any);
return OAUTH_PROVIDER_IDS.has(provider);
}
const resolveOAuthProvider = (provider: string): OAuthProvider | null =>

View File

@ -799,7 +799,7 @@ async function runExecProcess(opts: {
export function createExecTool(
defaults?: ExecToolDefaults,
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
// oxlint-disable-next-line typescript/no-explicit-any
): AgentTool<any, ExecToolDetails> {
const defaultBackgroundMs = clampNumber(
defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"),

View File

@ -43,7 +43,7 @@ const processSchema = Type.Object({
export function createProcessTool(
defaults?: ProcessToolDefaults,
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
// oxlint-disable-next-line typescript/no-explicit-any
): AgentTool<any> {
if (defaults?.cleanupMs !== undefined) {
setJobTtlMs(defaults.cleanupMs);

View File

@ -17,6 +17,7 @@ describe("downgradeOpenAIReasoningBlocks", () => {
},
];
// oxlint-disable-next-line typescript/no-explicit-any
expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual(input);
});
@ -34,6 +35,7 @@ describe("downgradeOpenAIReasoningBlocks", () => {
{ role: "user", content: "next" },
];
// oxlint-disable-next-line typescript/no-explicit-any
expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual([
{ role: "user", content: "next" },
]);
@ -52,6 +54,7 @@ describe("downgradeOpenAIReasoningBlocks", () => {
},
];
// oxlint-disable-next-line typescript/no-explicit-any
expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual([]);
});
@ -69,6 +72,7 @@ describe("downgradeOpenAIReasoningBlocks", () => {
},
];
// oxlint-disable-next-line typescript/no-explicit-any
expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual(input);
});
});

View File

@ -10,7 +10,7 @@ import { runBeforeToolCallHook } from "./pi-tools.before-tool-call.js";
import { normalizeToolName } from "./tool-policy.js";
import { jsonResult } from "./tools/common.js";
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
// oxlint-disable-next-line typescript/no-explicit-any
type AnyAgentTool = AgentTool<any, unknown>;
function isPlainObject(value: unknown): value is Record<string, unknown> {
@ -36,7 +36,6 @@ export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] {
name,
label: tool.label ?? name,
description: tool.description ?? "",
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema from pi-agent-core uses a different module instance.
parameters: tool.parameters,
execute: async (
toolCallId,
@ -87,6 +86,7 @@ export function toClientToolDefinitions(
name: func.name,
label: func.name,
description: func.description ?? "",
// oxlint-disable-next-line typescript/no-explicit-any
parameters: func.parameters as any,
execute: async (
toolCallId,

View File

@ -18,12 +18,14 @@ describe("before_tool_call hook integration", () => {
hasHooks: vi.fn(),
runBeforeToolCall: vi.fn(),
};
// oxlint-disable-next-line typescript/no-explicit-any
mockGetGlobalHookRunner.mockReturnValue(hookRunner as any);
});
it("executes tool normally when no hook is registered", async () => {
hookRunner.hasHooks.mockReturnValue(false);
const execute = vi.fn().mockResolvedValue({ content: [], details: { ok: true } });
// oxlint-disable-next-line typescript/no-explicit-any
const tool = wrapToolWithBeforeToolCallHook({ name: "Read", execute } as any, {
agentId: "main",
sessionKey: "main",
@ -39,6 +41,7 @@ describe("before_tool_call hook integration", () => {
hookRunner.hasHooks.mockReturnValue(true);
hookRunner.runBeforeToolCall.mockResolvedValue({ params: { mode: "safe" } });
const execute = vi.fn().mockResolvedValue({ content: [], details: { ok: true } });
// oxlint-disable-next-line typescript/no-explicit-any
const tool = wrapToolWithBeforeToolCallHook({ name: "exec", execute } as any);
await tool.execute("call-2", { cmd: "ls" }, undefined, undefined);
@ -58,6 +61,7 @@ describe("before_tool_call hook integration", () => {
blockReason: "blocked",
});
const execute = vi.fn().mockResolvedValue({ content: [], details: { ok: true } });
// oxlint-disable-next-line typescript/no-explicit-any
const tool = wrapToolWithBeforeToolCallHook({ name: "exec", execute } as any);
await expect(tool.execute("call-3", { cmd: "rm -rf /" }, undefined, undefined)).rejects.toThrow(
@ -70,6 +74,7 @@ describe("before_tool_call hook integration", () => {
hookRunner.hasHooks.mockReturnValue(true);
hookRunner.runBeforeToolCall.mockRejectedValue(new Error("boom"));
const execute = vi.fn().mockResolvedValue({ content: [], details: { ok: true } });
// oxlint-disable-next-line typescript/no-explicit-any
const tool = wrapToolWithBeforeToolCallHook({ name: "read", execute } as any);
await tool.execute("call-4", { path: "/tmp/file" }, undefined, undefined);
@ -81,6 +86,7 @@ describe("before_tool_call hook integration", () => {
hookRunner.hasHooks.mockReturnValue(true);
hookRunner.runBeforeToolCall.mockResolvedValue(undefined);
const execute = vi.fn().mockResolvedValue({ content: [], details: { ok: true } });
// oxlint-disable-next-line typescript/no-explicit-any
const tool = wrapToolWithBeforeToolCallHook({ name: "ReAd", execute } as any, {
agentId: "main",
sessionKey: "main",
@ -113,6 +119,7 @@ describe("before_tool_call hook integration for client tools", () => {
hasHooks: vi.fn(),
runBeforeToolCall: vi.fn(),
};
// oxlint-disable-next-line typescript/no-explicit-any
mockGetGlobalHookRunner.mockReturnValue(hookRunner as any);
});

View File

@ -1,4 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
// oxlint-disable-next-line typescript/no-explicit-any
export type AnyAgentTool = AgentTool<any, unknown>;

View File

@ -25,7 +25,8 @@ export function guardSessionManager(
const hookRunner = getGlobalHookRunner();
const transform = hookRunner?.hasHooks("tool_result_persist")
? (message: any, meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean }) => {
? // oxlint-disable-next-line typescript/no-explicit-any
(message: any, meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean }) => {
const out = hookRunner.runToolResultPersist(
{
toolName: meta.toolName,

View File

@ -52,6 +52,7 @@ describe("tool_result_persist hook", () => {
isError: false,
content: [{ type: "text", text: "ok" }],
details: { big: "x".repeat(10_000) },
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
const messages = sm
@ -59,6 +60,7 @@ describe("tool_result_persist hook", () => {
.filter((e) => e.type === "message")
.map((e) => (e as { message: AgentMessage }).message);
// oxlint-disable-next-line typescript/no-explicit-any
const toolResult = messages.find((m) => (m as any).role === "toolResult") as any;
expect(toolResult).toBeTruthy();
expect(toolResult.details).toBeTruthy();
@ -121,6 +123,7 @@ describe("tool_result_persist hook", () => {
isError: false,
content: [{ type: "text", text: "ok" }],
details: { big: "x".repeat(10_000) },
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
const messages = sm
@ -128,6 +131,7 @@ describe("tool_result_persist hook", () => {
.filter((e) => e.type === "message")
.map((e) => (e as { message: AgentMessage }).message);
// oxlint-disable-next-line typescript/no-explicit-any
const toolResult = messages.find((m) => (m as any).role === "toolResult") as any;
expect(toolResult).toBeTruthy();

View File

@ -3,7 +3,7 @@ import fs from "node:fs/promises";
import { detectMime } from "../../media/mime.js";
import { sanitizeToolResultImages } from "../tool-images.js";
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
// oxlint-disable-next-line typescript/no-explicit-any
export type AnyAgentTool = AgentTool<any, unknown>;
export type StringParamOptions = {

View File

@ -86,6 +86,7 @@ export async function handleCommands(params: HandleCommandsParams): Promise<Comm
// Send hook messages immediately if present
if (hookEvent.messages.length > 0) {
// Use OriginatingChannel/To if available, otherwise fall back to command channel/from
// oxlint-disable-next-line typescript/no-explicit-any
const channel = params.ctx.OriginatingChannel || (params.command.channel as any);
// For replies, use 'from' (the sender) not 'to' (which might be the bot itself)
const to = params.ctx.OriginatingTo || params.command.from || params.command.to;

View File

@ -25,6 +25,7 @@ export type InlineActionResult =
abortedLastRun: boolean;
};
// oxlint-disable-next-line typescript/no-explicit-any
function extractTextFromToolResult(result: any): string | null {
if (!result || typeof result !== "object") {
return null;
@ -193,6 +194,7 @@ export async function handleInlineActions(params: {
command: rawArgs,
commandName: skillInvocation.command.name,
skillName: skillInvocation.command.skillName,
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
const text = extractTextFromToolResult(result) ?? "✅ Done.";
typing.cleanup();

View File

@ -285,6 +285,7 @@ export async function runPreparedReply(
}
}
if (resetTriggered && command.isAuthorizedSender) {
// oxlint-disable-next-line typescript/no-explicit-any
const channel = ctx.OriginatingChannel || (command.channel as any);
const to = ctx.OriginatingTo || command.from || command.to;
if (channel && to) {

View File

@ -181,18 +181,14 @@ describe("color allocation", () => {
});
it("allocates next unused color from palette", () => {
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
const usedColors = new Set([PROFILE_COLORS[0].toUpperCase()]);
expect(allocateColor(usedColors)).toBe(PROFILE_COLORS[1]);
});
it("skips multiple used colors", () => {
const usedColors = new Set([
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
PROFILE_COLORS[0].toUpperCase(),
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
PROFILE_COLORS[1].toUpperCase(),
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
PROFILE_COLORS[2].toUpperCase(),
]);
expect(allocateColor(usedColors)).toBe(PROFILE_COLORS[3]);

View File

@ -100,7 +100,6 @@ export function allocateColor(usedColors: Set<string>): string {
}
// All colors used, cycle based on count
const index = usedColors.size % PROFILE_COLORS.length;
// biome-ignore lint/style/noNonNullAssertion: Array is non-empty constant
return PROFILE_COLORS[index] ?? PROFILE_COLORS[0];
}

View File

@ -51,12 +51,11 @@ describe("browser server-context ensureTabAvailable", () => {
} as unknown as Response;
});
// @ts-expect-error test override
global.fetch = fetchMock;
const state: BrowserServerState = {
// unused in these tests
// biome-ignore lint/suspicious/noExplicitAny: test stub
// oxlint-disable-next-line typescript/no-explicit-any
server: null as any,
port: 0,
resolved: {
@ -113,11 +112,10 @@ describe("browser server-context ensureTabAvailable", () => {
return { ok: true, json: async () => next } as unknown as Response;
});
// @ts-expect-error test override
global.fetch = fetchMock;
const state: BrowserServerState = {
// biome-ignore lint/suspicious/noExplicitAny: test stub
// oxlint-disable-next-line typescript/no-explicit-any
server: null as any,
port: 0,
resolved: {
@ -164,11 +162,11 @@ describe("browser server-context ensureTabAvailable", () => {
}
return { ok: true, json: async () => next } as unknown as Response;
});
// @ts-expect-error test override
global.fetch = fetchMock;
const state: BrowserServerState = {
// biome-ignore lint/suspicious/noExplicitAny: test stub
// oxlint-disable-next-line typescript/no-explicit-any
server: null as any,
port: 0,
resolved: {

View File

@ -15,7 +15,7 @@ function makeState(
profile: "remote" | "openclaw",
): BrowserServerState & { profiles: Map<string, { lastTargetId?: string | null }> } {
return {
// biome-ignore lint/suspicious/noExplicitAny: test stub
// oxlint-disable-next-line typescript/no-explicit-any
server: null as any,
port: 0,
resolved: {
@ -67,7 +67,7 @@ describe("browser server-context remote profile tab operations", () => {
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
});
// @ts-expect-error test override
global.fetch = fetchMock;
const { createBrowserRouteContext } = await import("./server-context.js");
@ -134,7 +134,7 @@ describe("browser server-context remote profile tab operations", () => {
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
});
// @ts-expect-error test override
global.fetch = fetchMock;
const { createBrowserRouteContext } = await import("./server-context.js");
@ -163,7 +163,7 @@ describe("browser server-context remote profile tab operations", () => {
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
});
// @ts-expect-error test override
global.fetch = fetchMock;
const { createBrowserRouteContext } = await import("./server-context.js");
@ -191,7 +191,7 @@ describe("browser server-context remote profile tab operations", () => {
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
});
// @ts-expect-error test override
global.fetch = fetchMock;
const { createBrowserRouteContext } = await import("./server-context.js");
@ -229,7 +229,7 @@ describe("browser server-context remote profile tab operations", () => {
],
} as unknown as Response;
});
// @ts-expect-error test override
global.fetch = fetchMock;
const { createBrowserRouteContext } = await import("./server-context.js");
@ -273,7 +273,7 @@ describe("browser server-context tab selection state", () => {
],
} as unknown as Response;
});
// @ts-expect-error test override
global.fetch = fetchMock;
const { createBrowserRouteContext } = await import("./server-context.js");

View File

@ -22,6 +22,7 @@ describe("directory (config-backed)", () => {
channels: { C111: { users: ["U777"] } },
},
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const peers = await listSlackDirectoryPeersFromConfig({
@ -65,6 +66,7 @@ describe("directory (config-backed)", () => {
},
},
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const peers = await listDiscordDirectoryPeersFromConfig({
@ -94,6 +96,7 @@ describe("directory (config-backed)", () => {
groups: { "-1001": {}, "*": {} },
},
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const peers = await listTelegramDirectoryPeersFromConfig({
@ -121,6 +124,7 @@ describe("directory (config-backed)", () => {
groups: { "999@g.us": { requireMention: true }, "*": {} },
},
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const peers = await listWhatsAppDirectoryPeersFromConfig({

View File

@ -30,7 +30,6 @@ import type {
} from "./types.core.js";
// Channel docking: implement this contract in src/channels/plugins/<id>.ts.
// biome-ignore lint/suspicious/noExplicitAny: registry aggregates heterogeneous account types.
export type ChannelConfigUiHint = {
label?: string;
help?: string;
@ -45,6 +44,7 @@ export type ChannelConfigSchema = {
uiHints?: Record<string, ChannelConfigUiHint>;
};
// oxlint-disable-next-line typescript/no-explicit-any
export type ChannelPlugin<ResolvedAccount = any> = {
id: ChannelId;
meta: ChannelMeta;

View File

@ -77,8 +77,11 @@ async function dockerImageExists(image: string): Promise<boolean> {
try {
await runExec("docker", ["image", "inspect", image], { timeoutMs: 5_000 });
return true;
} catch (error: any) {
const stderr = error?.stderr || error?.message || "";
} catch (error) {
const stderr =
(error as { stderr: string } | undefined)?.stderr ||
(error as { message: string } | undefined)?.message ||
"";
if (String(stderr).includes("No such image")) {
return false;
}

View File

@ -49,7 +49,9 @@ describe("parseExecApprovalData", () => {
});
it("rejects null/undefined input", () => {
// oxlint-disable-next-line typescript/no-explicit-any
expect(parseExecApprovalData(null as any)).toBeNull();
// oxlint-disable-next-line typescript/no-explicit-any
expect(parseExecApprovalData(undefined as any)).toBeNull();
});

View File

@ -31,10 +31,13 @@ describe("discord processDiscordMessage inbound contract", () => {
const storePath = path.join(dir, "sessions.json");
await processDiscordMessage({
// oxlint-disable-next-line typescript/no-explicit-any
cfg: { messages: {}, session: { store: storePath } } as any,
// oxlint-disable-next-line typescript/no-explicit-any
discordConfig: {} as any,
accountId: "default",
token: "token",
// oxlint-disable-next-line typescript/no-explicit-any
runtime: { log: () => {}, error: () => {} } as any,
guildHistories: new Map(),
historyLimit: 0,
@ -44,19 +47,23 @@ describe("discord processDiscordMessage inbound contract", () => {
replyToMode: "off",
ackReactionScope: "direct",
groupPolicy: "open",
// oxlint-disable-next-line typescript/no-explicit-any
data: { guild: null } as any,
// oxlint-disable-next-line typescript/no-explicit-any
client: { rest: {} } as any,
message: {
id: "m1",
channelId: "c1",
timestamp: new Date().toISOString(),
attachments: [],
// oxlint-disable-next-line typescript/no-explicit-any
} as any,
author: {
id: "U1",
username: "alice",
discriminator: "0",
globalName: "Alice",
// oxlint-disable-next-line typescript/no-explicit-any
} as any,
channelInfo: null,
channelName: undefined,
@ -86,7 +93,9 @@ describe("discord processDiscordMessage inbound contract", () => {
accountId: "default",
sessionKey: "agent:main:discord:dm:u1",
mainSessionKey: "agent:main:main",
// oxlint-disable-next-line typescript/no-explicit-any
} as any,
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(capturedCtx).toBeTruthy();

View File

@ -105,6 +105,7 @@ describe("processDiscordMessage ack reactions", () => {
sender: { label: "user" },
});
// oxlint-disable-next-line typescript/no-explicit-any
await processDiscordMessage(ctx as any);
expect(reactMessageDiscord).not.toHaveBeenCalled();
@ -117,6 +118,7 @@ describe("processDiscordMessage ack reactions", () => {
sender: { label: "user" },
});
// oxlint-disable-next-line typescript/no-explicit-any
await processDiscordMessage(ctx as any);
expect(reactMessageDiscord).toHaveBeenCalledWith("c1", "m1", "👀", { rest: {} });

View File

@ -28,6 +28,7 @@ export function resolveDiscordWebhookId(message: DiscordWebhookMessageLike): str
export function resolveDiscordSenderIdentity(params: {
author: User;
// oxlint-disable-next-line typescript/no-explicit-any
member?: any;
pluralkitInfo?: PluralKitMessageInfo | null;
}): DiscordSenderIdentity {
@ -73,6 +74,7 @@ export function resolveDiscordSenderIdentity(params: {
export function resolveDiscordSenderLabel(params: {
author: User;
// oxlint-disable-next-line typescript/no-explicit-any
member?: any;
pluralkitInfo?: PluralKitMessageInfo | null;
}): string {

View File

@ -132,6 +132,7 @@ export class GatewayClient {
return new Error("gateway tls fingerprint mismatch");
}
return undefined;
// oxlint-disable-next-line typescript/no-explicit-any
}) as any;
}
this.ws = new WebSocket(url, wsOptions);

View File

@ -128,12 +128,14 @@ describe("timestampOptsFromConfig", () => {
userTimezone: "America/Chicago",
},
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(opts.timezone).toBe("America/Chicago");
});
it("falls back gracefully with empty config", () => {
// oxlint-disable-next-line typescript/no-explicit-any
const opts = timestampOptsFromConfig({} as any);
expect(opts.timezone).toBeDefined(); // resolveUserTimezone provides a default

View File

@ -310,6 +310,7 @@ describe("gateway server auth/connect", () => {
gateway: {
trustedProxies: ["127.0.0.1"],
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN;
process.env.OPENCLAW_GATEWAY_TOKEN = "secret";

View File

@ -34,6 +34,7 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const port = await getFreePort();
@ -60,12 +61,14 @@ describe("POST /tools/invoke", () => {
// No explicit tool allowlist; rely on profile + alsoAllow.
testState.agentsConfig = {
list: [{ id: "main" }],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
// minimal profile does NOT include agents_list, but alsoAllow should.
const { writeConfigFile } = await import("../config/config.js");
await writeConfigFile({
tools: { profile: "minimal", alsoAllow: ["agents_list"] },
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
const port = await getFreePort();
@ -88,6 +91,7 @@ describe("POST /tools/invoke", () => {
it("supports tools.alsoAllow without allow/profile (implicit allow-all)", async () => {
testState.agentsConfig = {
list: [{ id: "main" }],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const { CONFIG_PATH } = await import("../config/config.js");
@ -125,6 +129,7 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const port = await getFreePort();
@ -175,6 +180,7 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const port = await getFreePort();
@ -210,6 +216,7 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const port = await getFreePort();
@ -239,6 +246,7 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const port = await getFreePort();
@ -266,11 +274,13 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const { writeConfigFile } = await import("../config/config.js");
await writeConfigFile({
tools: { profile: "minimal" },
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
const port = await getFreePort();
@ -305,6 +315,7 @@ describe("POST /tools/invoke", () => {
},
},
],
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
testState.sessionConfig = { mainKey: "primary" };

View File

@ -230,12 +230,14 @@ export async function handleToolsInvokeHttpRequest(
const coreToolNames = new Set(
allTools
// oxlint-disable-next-line typescript/no-explicit-any
.filter((tool) => !getPluginToolMeta(tool as any))
.map((tool) => normalizeToolName(tool.name))
.filter(Boolean),
);
const pluginGroups = buildPluginToolGroups({
tools: allTools,
// oxlint-disable-next-line typescript/no-explicit-any
toolMeta: (tool) => getPluginToolMeta(tool as any),
});
const resolvePolicy = (policy: typeof profilePolicy, label: string) => {
@ -306,10 +308,12 @@ export async function handleToolsInvokeHttpRequest(
try {
const toolArgs = mergeActionIntoArgsIfSupported({
// oxlint-disable-next-line typescript/no-explicit-any
toolSchema: (tool as any).parameters,
action,
args,
});
// oxlint-disable-next-line typescript/no-explicit-any
const result = await (tool as any).execute?.(`http-${Date.now()}`, toolArgs);
sendJson(res, 200, { ok: true, result });
} catch (err) {

View File

@ -38,7 +38,8 @@ async function getRecentSessionContent(
if ((role === "user" || role === "assistant") && msg.content) {
// Extract text content
const text = Array.isArray(msg.content)
? msg.content.find((c: any) => c.type === "text")?.text
? // oxlint-disable-next-line typescript/no-explicit-any
msg.content.find((c: any) => c.type === "text")?.text
: msg.content;
if (text && !text.startsWith("/")) {
allMessages.push(`${role}: ${text}`);

View File

@ -10,6 +10,7 @@ const createRes = () => {
status: vi.fn(),
json: vi.fn(),
headersSent: false,
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
res.status.mockReturnValue(res);
res.json.mockReturnValue(res);
@ -26,9 +27,11 @@ describe("createLineWebhookMiddleware", () => {
const req = {
headers: { "x-line-signature": sign(rawBody, secret) },
body: rawBody,
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const res = createRes();
// oxlint-disable-next-line typescript/no-explicit-any
await middleware(req, res, {} as any);
expect(res.status).toHaveBeenCalledWith(200);
@ -44,9 +47,11 @@ describe("createLineWebhookMiddleware", () => {
const req = {
headers: { "x-line-signature": sign(rawBody, secret) },
body: Buffer.from(rawBody, "utf-8"),
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const res = createRes();
// oxlint-disable-next-line typescript/no-explicit-any
await middleware(req, res, {} as any);
expect(res.status).toHaveBeenCalledWith(200);
@ -62,9 +67,11 @@ describe("createLineWebhookMiddleware", () => {
const req = {
headers: { "x-line-signature": sign(rawBody, secret) },
body: rawBody,
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const res = createRes();
// oxlint-disable-next-line typescript/no-explicit-any
await middleware(req, res, {} as any);
expect(res.status).toHaveBeenCalledWith(400);
@ -80,9 +87,11 @@ describe("createLineWebhookMiddleware", () => {
const req = {
headers: { "x-line-signature": "invalid-signature" },
body: rawBody,
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const res = createRes();
// oxlint-disable-next-line typescript/no-explicit-any
await middleware(req, res, {} as any);
expect(res.status).toHaveBeenCalledWith(401);
@ -99,9 +108,11 @@ describe("createLineWebhookMiddleware", () => {
const req = {
headers: { "x-line-signature": sign(rawBody, wrongSecret) },
body: rawBody,
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
const res = createRes();
// oxlint-disable-next-line typescript/no-explicit-any
await middleware(req, res, {} as any);
expect(res.status).toHaveBeenCalledWith(401);

View File

@ -37,6 +37,7 @@ describe("registerPluginCliCommands", () => {
const program = new Command();
program.command("memory");
// oxlint-disable-next-line typescript/no-explicit-any
registerPluginCliCommands(program, {} as any);
expect(mocks.memoryRegister).not.toHaveBeenCalled();

View File

@ -335,12 +335,14 @@ export function createHookRunner(registry: PluginRegistry, options: HookRunnerOp
for (const hook of hooks) {
try {
// oxlint-disable-next-line typescript/no-explicit-any
const out = (hook.handler as any)({ ...event, message: current }, ctx) as
| PluginHookToolResultPersistResult
| void
| Promise<unknown>;
// Guard against accidental async handlers (this hook is sync-only).
// oxlint-disable-next-line typescript/no-explicit-any
if (out && typeof (out as any).then === "function") {
const msg =
`[hooks] tool_result_persist handler from ${hook.pluginId} returned a Promise; ` +

View File

@ -826,6 +826,7 @@ async function collectChannelSecurityFindings(params: {
if (!hasAnySenderAllowlist) {
const providerSetting = (telegramCfg.commands as { nativeSkills?: unknown } | undefined)
// oxlint-disable-next-line typescript/no-explicit-any
?.nativeSkills as any;
const skillsEnabled = resolveNativeSkillsEnabled({
providerId: "telegram",

View File

@ -41,10 +41,12 @@ describe("signal event handler typing + read receipts", () => {
vi.resetModules();
const { createSignalEventHandler } = await import("./monitor/event-handler.js");
const handler = createSignalEventHandler({
// oxlint-disable-next-line typescript/no-explicit-any
runtime: { log: () => {}, error: () => {} } as any,
cfg: {
messages: { inbound: { debounceMs: 0 } },
channels: { signal: { dmPolicy: "open", allowFrom: ["*"] } },
// oxlint-disable-next-line typescript/no-explicit-any
} as any,
baseUrl: "http://localhost",
account: "+15550009999",
@ -66,6 +68,7 @@ describe("signal event handler typing + read receipts", () => {
fetchAttachment: async () => null,
deliverReplies: async () => {},
resolveSignalReactionTargets: () => [],
// oxlint-disable-next-line typescript/no-explicit-any
isSignalReactionMessage: () => false as any,
shouldEmitSignalReactionNotification: () => false,
buildSignalReactionSystemEventText: () => "reaction",

View File

@ -25,7 +25,9 @@ describe("signal createSignalEventHandler inbound contract", () => {
capturedCtx = undefined;
const handler = createSignalEventHandler({
// oxlint-disable-next-line typescript/no-explicit-any
runtime: { log: () => {}, error: () => {} } as any,
// oxlint-disable-next-line typescript/no-explicit-any
cfg: { messages: { inbound: { debounceMs: 0 } } } as any,
baseUrl: "http://localhost",
accountId: "default",
@ -45,6 +47,7 @@ describe("signal createSignalEventHandler inbound contract", () => {
fetchAttachment: async () => null,
deliverReplies: async () => {},
resolveSignalReactionTargets: () => [],
// oxlint-disable-next-line typescript/no-explicit-any
isSignalReactionMessage: () => false as any,
shouldEmitSignalReactionNotification: () => false,
buildSignalReactionSystemEventText: () => "reaction",

View File

@ -48,6 +48,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
mediaMaxBytes: 1024,
removeAckAfterReply: false,
});
// oxlint-disable-next-line typescript/no-explicit-any
slackCtx.resolveUserName = async () => ({ name: "Alice" }) as any;
const account: ResolvedSlackAccount = {
@ -74,6 +75,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
});
expect(prepared).toBeTruthy();
// oxlint-disable-next-line typescript/no-explicit-any
expectInboundContextContract(prepared!.ctxPayload as any);
});
@ -116,6 +118,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
mediaMaxBytes: 1024,
removeAckAfterReply: false,
});
// oxlint-disable-next-line typescript/no-explicit-any
slackCtx.resolveUserName = async () => ({ name: "Alice" }) as any;
const account: ResolvedSlackAccount = {

View File

@ -8,6 +8,7 @@ describe("createSlackThreadTsResolver", () => {
messages: [{ ts: "1", thread_ts: "9" }],
});
const resolver = createSlackThreadTsResolver({
// oxlint-disable-next-line typescript/no-explicit-any
client: { conversations: { history: historyMock } } as any,
cacheTtlMs: 60_000,
maxSize: 5,

View File

@ -49,6 +49,7 @@ export const dispatchTelegramMessage = async ({
telegramCfg,
opts,
resolveBotTopicsEnabled,
// oxlint-disable-next-line typescript/no-explicit-any
}: any) => {
const {
ctxPayload,

View File

@ -446,7 +446,9 @@ export function createTelegramBot(opts: TelegramBotOptions) {
senderLabel = senderLabel || "unknown";
// Extract forum thread info (similar to message processing)
// oxlint-disable-next-line typescript/no-explicit-any
const messageThreadId = (reaction as any).message_thread_id;
// oxlint-disable-next-line typescript/no-explicit-any
const isForum = (reaction.chat as any).is_forum === true;
const resolvedThreadId = resolveTelegramForumThreadId({
isForum,

View File

@ -78,6 +78,7 @@ describe("normalizeForwardedContext", () => {
sender_user: { first_name: "Ada", last_name: "Lovelace", username: "ada", id: 42 },
date: 123,
},
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Ada Lovelace (@ada)");
@ -91,6 +92,7 @@ describe("normalizeForwardedContext", () => {
it("handles hidden forward_origin names", () => {
const ctx = normalizeForwardedContext({
forward_origin: { type: "hidden_user", sender_user_name: "Hidden Name", date: 456 },
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Hidden Name");
@ -109,6 +111,7 @@ describe("normalizeForwardedContext", () => {
},
forward_signature: "Stan",
forward_date: 789,
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("OpenClaw Updates (Stan)");
@ -124,6 +127,7 @@ describe("normalizeForwardedContext", () => {
const ctx = normalizeForwardedContext({
forward_sender_name: "Legacy Hidden",
forward_date: 111,
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Legacy Hidden");

View File

@ -5,6 +5,7 @@ describe("createTelegramDraftStream", () => {
it("passes message_thread_id when provided", () => {
const api = { sendMessageDraft: vi.fn().mockResolvedValue(true) };
const stream = createTelegramDraftStream({
// oxlint-disable-next-line typescript/no-explicit-any
api: api as any,
chatId: 123,
draftId: 42,
@ -21,6 +22,7 @@ describe("createTelegramDraftStream", () => {
it("omits message_thread_id for general topic id", () => {
const api = { sendMessageDraft: vi.fn().mockResolvedValue(true) };
const stream = createTelegramDraftStream({
// oxlint-disable-next-line typescript/no-explicit-any
api: api as any,
chatId: 123,
draftId: 42,
@ -35,6 +37,7 @@ describe("createTelegramDraftStream", () => {
it("keeps message_thread_id for dm threads", () => {
const api = { sendMessageDraft: vi.fn().mockResolvedValue(true) };
const stream = createTelegramDraftStream({
// oxlint-disable-next-line typescript/no-explicit-any
api: api as any,
chatId: 123,
draftId: 42,

View File

@ -53,7 +53,9 @@ describe("tui-event-handlers: handleAgentEvent", () => {
const { chatLog, tui, setActivityStatus } = makeContext(state);
const { handleAgentEvent } = createEventHandlers({
// Casts are fine here: TUI runtime shape is larger than we need in unit tests.
// oxlint-disable-next-line typescript/no-explicit-any
chatLog: chatLog as any,
// oxlint-disable-next-line typescript/no-explicit-any
tui: tui as any,
state,
setActivityStatus,
@ -80,7 +82,9 @@ describe("tui-event-handlers: handleAgentEvent", () => {
const state = makeState({ activeChatRunId: "run-1" });
const { chatLog, tui, setActivityStatus } = makeContext(state);
const { handleAgentEvent } = createEventHandlers({
// oxlint-disable-next-line typescript/no-explicit-any
chatLog: chatLog as any,
// oxlint-disable-next-line typescript/no-explicit-any
tui: tui as any,
state,
setActivityStatus,
@ -103,7 +107,9 @@ describe("tui-event-handlers: handleAgentEvent", () => {
const state = makeState({ activeChatRunId: "run-9" });
const { tui, setActivityStatus } = makeContext(state);
const { handleAgentEvent } = createEventHandlers({
// oxlint-disable-next-line typescript/no-explicit-any
chatLog: { startTool: vi.fn(), updateToolResult: vi.fn() } as any,
// oxlint-disable-next-line typescript/no-explicit-any
tui: tui as any,
state,
setActivityStatus,
@ -125,7 +131,9 @@ describe("tui-event-handlers: handleAgentEvent", () => {
const state = makeState({ activeChatRunId: null });
const { chatLog, tui, setActivityStatus } = makeContext(state);
const { handleChatEvent, handleAgentEvent } = createEventHandlers({
// oxlint-disable-next-line typescript/no-explicit-any
chatLog: chatLog as any,
// oxlint-disable-next-line typescript/no-explicit-any
tui: tui as any,
state,
setActivityStatus,
@ -157,7 +165,9 @@ describe("tui-event-handlers: handleAgentEvent", () => {
const state = makeState({ activeChatRunId: null });
const { chatLog, tui, setActivityStatus } = makeContext(state);
const { handleChatEvent, handleAgentEvent } = createEventHandlers({
// oxlint-disable-next-line typescript/no-explicit-any
chatLog: chatLog as any,
// oxlint-disable-next-line typescript/no-explicit-any
tui: tui as any,
state,
setActivityStatus,
@ -188,7 +198,9 @@ describe("tui-event-handlers: handleAgentEvent", () => {
const state = makeState({ activeChatRunId: "run-active" });
const { chatLog, tui, setActivityStatus } = makeContext(state);
const { handleChatEvent, handleAgentEvent } = createEventHandlers({
// oxlint-disable-next-line typescript/no-explicit-any
chatLog: chatLog as any,
// oxlint-disable-next-line typescript/no-explicit-any
tui: tui as any,
state,
setActivityStatus,

View File

@ -5,6 +5,7 @@ const theme = {
dim: (s: string) => `<d>${s}</d>`,
bold: (s: string) => `<b>${s}</b>`,
accentSoft: (s: string) => `<a>${s}</a>`,
// oxlint-disable-next-line typescript/no-explicit-any
} as any;
describe("tui-waiting", () => {

View File

@ -81,7 +81,7 @@ describe("jidToE164", () => {
const original = fs.readFileSync;
const spy = vi
.spyOn(fs, "readFileSync")
// biome-ignore lint/suspicious/noExplicitAny: forwarding to native signature
// oxlint-disable-next-line typescript/no-explicit-any
.mockImplementation((path: any, encoding?: any) => {
if (path === mappingPath) {
return `"5551234"`;

View File

@ -17,6 +17,7 @@ describe("web processMessage inbound contract", () => {
capturedCtx = undefined;
await processMessage({
// oxlint-disable-next-line typescript/no-explicit-any
cfg: { messages: {} } as any,
msg: {
id: "msg1",
@ -29,11 +30,13 @@ describe("web processMessage inbound contract", () => {
senderE164: "+15550002222",
groupSubject: "Test Group",
groupParticipants: [],
// oxlint-disable-next-line typescript/no-explicit-any
} as any,
route: {
agentId: "main",
accountId: "default",
sessionKey: "agent:main:whatsapp:group:123",
// oxlint-disable-next-line typescript/no-explicit-any
} as any,
groupHistoryKey: "123@g.us",
groupHistories: new Map(),
@ -41,7 +44,9 @@ describe("web processMessage inbound contract", () => {
connectionId: "conn",
verbose: false,
maxMediaBytes: 1,
// oxlint-disable-next-line typescript/no-explicit-any
replyResolver: (async () => undefined) as any,
// oxlint-disable-next-line typescript/no-explicit-any
replyLogger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as any,
backgroundTasks: new Set(),
rememberSentText: (_text: string | undefined, _opts: unknown) => {},
@ -49,9 +54,11 @@ describe("web processMessage inbound contract", () => {
echoForget: () => {},
buildCombinedEchoKey: () => "echo",
groupHistory: [],
// oxlint-disable-next-line typescript/no-explicit-any
} as any);
expect(capturedCtx).toBeTruthy();
// oxlint-disable-next-line typescript/no-explicit-any
expectInboundContextContract(capturedCtx as any);
});
});