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

This commit is contained in:
cpojer
2026-02-02 15:45:05 +09:00
parent baa1e95b9d
commit 935a0e5708
65 changed files with 248 additions and 80 deletions

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