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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,7 +15,7 @@ export async function fetchGroupChanges(
return changes; return changes;
} }
return null; return null;
} catch (error: any) { } catch (error) {
runtime.log?.( runtime.log?.(
`[tlon] Failed to fetch changes (falling back to full init): ${error?.message ?? String(error)}`, `[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..."); runtime.log?.("[tlon] Attempting auto-discovery of group channels...");
const changes = await fetchGroupChanges(api, runtime, 5); const changes = await fetchGroupChanges(api, runtime, 5);
// oxlint-disable-next-line typescript/no-explicit-any
let initData: any; let initData: any;
if (changes) { if (changes) {
runtime.log?.("[tlon] Changes data received, using full init for channel extraction"); runtime.log?.("[tlon] Changes data received, using full init for channel extraction");
@@ -41,6 +42,7 @@ export async function fetchAllChannels(
const channels: string[] = []; const channels: string[] = [];
if (initData && initData.groups) { if (initData && initData.groups) {
// oxlint-disable-next-line typescript/no-explicit-any
for (const groupData of Object.values(initData.groups as Record<string, any>)) { for (const groupData of Object.values(initData.groups as Record<string, any>)) {
if (groupData && typeof groupData === "object" && groupData.channels) { if (groupData && typeof groupData === "object" && groupData.channels) {
for (const channelNest of Object.keys(groupData.channels)) { for (const channelNest of Object.keys(groupData.channels)) {
@@ -63,7 +65,7 @@ export async function fetchAllChannels(
} }
return channels; return channels;
} catch (error: any) { } catch (error) {
runtime.log?.(`[tlon] Auto-discovery failed: ${error?.message ?? String(error)}`); runtime.log?.(`[tlon] Auto-discovery failed: ${error?.message ?? String(error)}`);
runtime.log?.( runtime.log?.(
"[tlon] To monitor group channels, add them to config: channels.tlon.groupChannels", "[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`; const scryPath = `/channels/v4/${channelNest}/posts/newest/${count}/outline.json`;
runtime?.log?.(`[tlon] Fetching history: ${scryPath}`); runtime?.log?.(`[tlon] Fetching history: ${scryPath}`);
// oxlint-disable-next-line typescript/no-explicit-any
const data: any = await api.scry(scryPath); const data: any = await api.scry(scryPath);
if (!data) { if (!data) {
return []; return [];
} }
// oxlint-disable-next-line typescript/no-explicit-any
let posts: any[] = []; let posts: any[] = [];
if (Array.isArray(data)) { if (Array.isArray(data)) {
posts = data; posts = data;
@@ -65,7 +67,7 @@ export async function fetchChannelHistory(
runtime?.log?.(`[tlon] Extracted ${messages.length} messages from history`); runtime?.log?.(`[tlon] Extracted ${messages.length} messages from history`);
return messages; return messages;
} catch (error: any) { } catch (error) {
runtime?.log?.(`[tlon] Error fetching channel history: ${error?.message ?? String(error)}`); runtime?.log?.(`[tlon] Error fetching channel history: ${error?.message ?? String(error)}`);
return []; return [];
} }

View File

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

View File

@@ -49,10 +49,14 @@ export function extractMessageText(content: unknown): string {
return ""; return "";
} }
return content return (
content
// oxlint-disable-next-line typescript/no-explicit-any
.map((block: any) => { .map((block: any) => {
if (block.inline && Array.isArray(block.inline)) { if (block.inline && Array.isArray(block.inline)) {
return block.inline return (
block.inline
// oxlint-disable-next-line typescript/no-explicit-any
.map((item: any) => { .map((item: any) => {
if (typeof item === "string") { if (typeof item === "string") {
return item; return item;
@@ -70,12 +74,14 @@ export function extractMessageText(content: unknown): string {
} }
return ""; return "";
}) })
.join(""); .join("")
);
} }
return ""; return "";
}) })
.join("\n") .join("\n")
.trim(); .trim()
);
} }
export function isSummarizationRequest(messageText: string): boolean { export function isSummarizationRequest(messageText: string): boolean {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -73,7 +73,7 @@ const applyPatchSchema = Type.Object({
export function createApplyPatchTool( export function createApplyPatchTool(
options: { cwd?: string; sandboxRoot?: string } = {}, 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> { ): AgentTool<any, ApplyPatchToolDetails> {
const cwd = options.cwd ?? process.cwd(); const cwd = options.cwd ?? process.cwd();
const sandboxRoot = options.sandboxRoot; const sandboxRoot = options.sandboxRoot;

View File

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

View File

@@ -799,7 +799,7 @@ async function runExecProcess(opts: {
export function createExecTool( export function createExecTool(
defaults?: ExecToolDefaults, 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> { ): AgentTool<any, ExecToolDetails> {
const defaultBackgroundMs = clampNumber( const defaultBackgroundMs = clampNumber(
defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"), defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"),

View File

@@ -43,7 +43,7 @@ const processSchema = Type.Object({
export function createProcessTool( export function createProcessTool(
defaults?: ProcessToolDefaults, 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> { ): AgentTool<any> {
if (defaults?.cleanupMs !== undefined) { if (defaults?.cleanupMs !== undefined) {
setJobTtlMs(defaults.cleanupMs); 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); expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual(input);
}); });
@@ -34,6 +35,7 @@ describe("downgradeOpenAIReasoningBlocks", () => {
{ role: "user", content: "next" }, { role: "user", content: "next" },
]; ];
// oxlint-disable-next-line typescript/no-explicit-any
expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual([ expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual([
{ role: "user", content: "next" }, { role: "user", content: "next" },
]); ]);
@@ -52,6 +54,7 @@ describe("downgradeOpenAIReasoningBlocks", () => {
}, },
]; ];
// oxlint-disable-next-line typescript/no-explicit-any
expect(downgradeOpenAIReasoningBlocks(input as any)).toEqual([]); 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); 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 { normalizeToolName } from "./tool-policy.js";
import { jsonResult } from "./tools/common.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>; type AnyAgentTool = AgentTool<any, unknown>;
function isPlainObject(value: unknown): value is Record<string, unknown> { function isPlainObject(value: unknown): value is Record<string, unknown> {
@@ -36,7 +36,6 @@ export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] {
name, name,
label: tool.label ?? name, label: tool.label ?? name,
description: tool.description ?? "", description: tool.description ?? "",
// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema from pi-agent-core uses a different module instance.
parameters: tool.parameters, parameters: tool.parameters,
execute: async ( execute: async (
toolCallId, toolCallId,
@@ -87,6 +86,7 @@ export function toClientToolDefinitions(
name: func.name, name: func.name,
label: func.name, label: func.name,
description: func.description ?? "", description: func.description ?? "",
// oxlint-disable-next-line typescript/no-explicit-any
parameters: func.parameters as any, parameters: func.parameters as any,
execute: async ( execute: async (
toolCallId, toolCallId,

View File

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

View File

@@ -1,4 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core"; 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>; export type AnyAgentTool = AgentTool<any, unknown>;

View File

@@ -25,7 +25,8 @@ export function guardSessionManager(
const hookRunner = getGlobalHookRunner(); const hookRunner = getGlobalHookRunner();
const transform = hookRunner?.hasHooks("tool_result_persist") 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( const out = hookRunner.runToolResultPersist(
{ {
toolName: meta.toolName, toolName: meta.toolName,

View File

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

View File

@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
import { detectMime } from "../../media/mime.js"; import { detectMime } from "../../media/mime.js";
import { sanitizeToolResultImages } from "../tool-images.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 AnyAgentTool = AgentTool<any, unknown>;
export type StringParamOptions = { export type StringParamOptions = {

View File

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

View File

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

View File

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

View File

@@ -181,18 +181,14 @@ describe("color allocation", () => {
}); });
it("allocates next unused color from palette", () => { 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()]); const usedColors = new Set([PROFILE_COLORS[0].toUpperCase()]);
expect(allocateColor(usedColors)).toBe(PROFILE_COLORS[1]); expect(allocateColor(usedColors)).toBe(PROFILE_COLORS[1]);
}); });
it("skips multiple used colors", () => { it("skips multiple used colors", () => {
const usedColors = new Set([ const usedColors = new Set([
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
PROFILE_COLORS[0].toUpperCase(), PROFILE_COLORS[0].toUpperCase(),
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
PROFILE_COLORS[1].toUpperCase(), PROFILE_COLORS[1].toUpperCase(),
// biome-ignore lint/style/noNonNullAssertion: Test file with known array
PROFILE_COLORS[2].toUpperCase(), PROFILE_COLORS[2].toUpperCase(),
]); ]);
expect(allocateColor(usedColors)).toBe(PROFILE_COLORS[3]); 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 // All colors used, cycle based on count
const index = usedColors.size % PROFILE_COLORS.length; const index = usedColors.size % PROFILE_COLORS.length;
// biome-ignore lint/style/noNonNullAssertion: Array is non-empty constant
return PROFILE_COLORS[index] ?? PROFILE_COLORS[0]; return PROFILE_COLORS[index] ?? PROFILE_COLORS[0];
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,7 +38,8 @@ async function getRecentSessionContent(
if ((role === "user" || role === "assistant") && msg.content) { if ((role === "user" || role === "assistant") && msg.content) {
// Extract text content // Extract text content
const text = Array.isArray(msg.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; : msg.content;
if (text && !text.startsWith("/")) { if (text && !text.startsWith("/")) {
allMessages.push(`${role}: ${text}`); allMessages.push(`${role}: ${text}`);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -81,7 +81,7 @@ describe("jidToE164", () => {
const original = fs.readFileSync; const original = fs.readFileSync;
const spy = vi const spy = vi
.spyOn(fs, "readFileSync") .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) => { .mockImplementation((path: any, encoding?: any) => {
if (path === mappingPath) { if (path === mappingPath) {
return `"5551234"`; return `"5551234"`;

View File

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