diff --git a/src/cli/cron-cli.test.ts b/src/cli/cron-cli.test.ts index aa0e49cdfc3..b4e6fbc7eda 100644 --- a/src/cli/cron-cli.test.ts +++ b/src/cli/cron-cli.test.ts @@ -1,12 +1,14 @@ import { Command } from "commander"; import { describe, expect, it, vi } from "vitest"; -const callGatewayFromCli = vi.fn(async (method: string, _opts: unknown, params?: unknown) => { - if (method === "cron.status") { - return { enabled: true }; - } - return { ok: true, params }; -}); +const callGatewayFromCli = vi.fn( + async (method: string, _opts: unknown, params?: unknown, _timeoutMs?: number) => { + if (method === "cron.status") { + return { enabled: true }; + } + return { ok: true, params }; + }, +); vi.mock("./gateway-rpc.js", async () => { const actual = await vi.importActual("./gateway-rpc.js"); diff --git a/src/cli/daemon-cli.coverage.e2e.test.ts b/src/cli/daemon-cli.coverage.e2e.test.ts index 59adbf74e9c..6197e947920 100644 --- a/src/cli/daemon-cli.coverage.e2e.test.ts +++ b/src/cli/daemon-cli.coverage.e2e.test.ts @@ -1,8 +1,8 @@ import { Command } from "commander"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -const callGateway = vi.fn(async () => ({ ok: true })); -const resolveGatewayProgramArguments = vi.fn(async () => ({ +const callGateway = vi.fn(async (..._args: unknown[]) => ({ ok: true })); +const resolveGatewayProgramArguments = vi.fn(async (_opts?: unknown) => ({ programArguments: ["/bin/node", "cli", "gateway", "--port", "18789"], })); const serviceInstall = vi.fn().mockResolvedValue(undefined); @@ -12,7 +12,7 @@ const serviceRestart = vi.fn().mockResolvedValue(undefined); const serviceIsLoaded = vi.fn().mockResolvedValue(false); const serviceReadCommand = vi.fn().mockResolvedValue(null); const serviceReadRuntime = vi.fn().mockResolvedValue({ status: "running" }); -const findExtraGatewayServices = vi.fn(async () => []); +const findExtraGatewayServices = vi.fn(async (_env: unknown, _opts?: unknown) => []); const inspectPortUsage = vi.fn(async (port: number) => ({ port, status: "free", diff --git a/src/cli/gateway-cli/run-loop.test.ts b/src/cli/gateway-cli/run-loop.test.ts index 3bea291e24f..2740e1956e5 100644 --- a/src/cli/gateway-cli/run-loop.test.ts +++ b/src/cli/gateway-cli/run-loop.test.ts @@ -9,7 +9,7 @@ const consumeGatewaySigusr1RestartAuthorization = vi.fn(() => true); const isGatewaySigusr1RestartExternallyAllowed = vi.fn(() => false); const markGatewaySigusr1RestartHandled = vi.fn(); const getActiveTaskCount = vi.fn(() => 0); -const waitForActiveTasks = vi.fn(async () => ({ drained: true })); +const waitForActiveTasks = vi.fn(async (_timeoutMs: number) => ({ drained: true })); const resetAllLanes = vi.fn(); const DRAIN_TIMEOUT_LOG = "drain timeout reached; proceeding with restart"; const gatewayLog = { @@ -103,7 +103,7 @@ describe("runGatewayLoop", () => { start, runtime: { exit: vi.fn(), - } as { exit: (code: number) => never }, + } as unknown as { exit: (code: number) => never }, }); try { diff --git a/src/cli/program/message/helpers.test.ts b/src/cli/program/message/helpers.test.ts index bee38e1e34d..9ade2278a96 100644 --- a/src/cli/program/message/helpers.test.ts +++ b/src/cli/program/message/helpers.test.ts @@ -14,8 +14,10 @@ vi.mock("../../plugin-registry.js", () => ({ ensurePluginRegistryLoaded: vi.fn(), })); -const hasHooksMock = vi.fn(() => false); -const runGatewayStopMock = vi.fn(async () => {}); +const hasHooksMock = vi.fn((_hookName: string) => false); +const runGatewayStopMock = vi.fn( + async (_event: { reason?: string }, _ctx: Record) => {}, +); const runGlobalGatewayStopSafelyMock = vi.fn( async (params: { event: { reason?: string }; @@ -201,7 +203,13 @@ describe("runMessageAction", () => { expect.anything(), ); // account key should be stripped in favor of accountId - const passedOpts = messageCommandMock.mock.calls[0][0] as Record; + const passedOpts = ( + messageCommandMock.mock.calls as unknown as Array<[Record]> + )?.[0]?.[0]; + expect(passedOpts).toBeTruthy(); + if (!passedOpts) { + throw new Error("expected message command call"); + } expect(passedOpts).not.toHaveProperty("account"); }); }); diff --git a/src/cli/prompt.test.ts b/src/cli/prompt.test.ts index efeb1807a94..da5843dcbda 100644 --- a/src/cli/prompt.test.ts +++ b/src/cli/prompt.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it, vi } from "vitest"; import { isYes, setVerbose, setYes } from "../globals.js"; vi.mock("node:readline/promises", () => { - const question = vi.fn<[], Promise>(); + const question = vi.fn(async () => ""); const close = vi.fn(); const createInterface = vi.fn(() => ({ question, close })); return { default: { createInterface } }; @@ -11,14 +11,14 @@ vi.mock("node:readline/promises", () => { type ReadlineMock = { default: { createInterface: () => { - question: ReturnType>>; + question: ReturnType; close: ReturnType; }; }; }; const { promptYesNo } = await import("./prompt.js"); -const readline = (await import("node:readline/promises")) as ReadlineMock; +const readline = (await import("node:readline/promises")) as unknown as ReadlineMock; describe("promptYesNo", () => { it("returns true when global --yes is set", async () => { diff --git a/src/discord/monitor.test.ts b/src/discord/monitor.test.ts index a9042db8011..325138876e9 100644 --- a/src/discord/monitor.test.ts +++ b/src/discord/monitor.test.ts @@ -87,8 +87,9 @@ describe("DiscordMessageListener", () => { expect(handler).toHaveBeenCalledOnce(); expect(handlerResolved).toBe(false); - if (resolveHandler) { - resolveHandler(); + const release = resolveHandler; + if (typeof release === "function") { + (release as () => void)(); } await handlerPromise; }); @@ -134,8 +135,9 @@ describe("DiscordMessageListener", () => { ); vi.setSystemTime(31_000); - if (resolveHandler) { - resolveHandler(); + const release = resolveHandler; + if (typeof release === "function") { + (release as () => void)(); } await handlerPromise; await Promise.resolve(); @@ -143,7 +145,8 @@ describe("DiscordMessageListener", () => { expect(logger.warn).toHaveBeenCalled(); const warnMock = logger.warn as unknown as { mock: { calls: unknown[][] } }; const [, meta] = warnMock.mock.calls[0] ?? []; - expect(meta?.durationMs).toBeGreaterThanOrEqual(30_000); + const durationMs = (meta as { durationMs?: number } | undefined)?.durationMs; + expect(durationMs).toBeGreaterThanOrEqual(30_000); } finally { vi.useRealTimers(); } @@ -756,11 +759,12 @@ describe("discord media payload", () => { const { enqueueSystemEventSpy, resolveAgentRouteMock } = vi.hoisted(() => ({ enqueueSystemEventSpy: vi.fn(), - resolveAgentRouteMock: vi.fn(() => ({ + resolveAgentRouteMock: vi.fn((params: unknown) => ({ agentId: "default", channel: "discord", accountId: "acc-1", sessionKey: "discord:acc-1:dm:user-1", + ...(typeof params === "object" && params !== null ? { _params: params } : {}), })), })); @@ -940,7 +944,9 @@ describe("discord DM reaction handling", () => { await listener.handle(data, client); expect(resolveAgentRouteMock).toHaveBeenCalledOnce(); - const [routeArgs] = resolveAgentRouteMock.mock.calls[0] ?? []; + const routeArgs = (resolveAgentRouteMock.mock.calls[0]?.[0] ?? {}) as { + peer?: unknown; + }; if (!routeArgs) { throw new Error("expected route arguments"); } @@ -958,7 +964,9 @@ describe("discord DM reaction handling", () => { await listener.handle(data, client); expect(resolveAgentRouteMock).toHaveBeenCalledOnce(); - const [routeArgs] = resolveAgentRouteMock.mock.calls[0] ?? []; + const routeArgs = (resolveAgentRouteMock.mock.calls[0]?.[0] ?? {}) as { + peer?: unknown; + }; if (!routeArgs) { throw new Error("expected route arguments"); } diff --git a/src/discord/monitor/message-handler.process.test.ts b/src/discord/monitor/message-handler.process.test.ts index a5cd599ace9..0a88aa08328 100644 --- a/src/discord/monitor/message-handler.process.test.ts +++ b/src/discord/monitor/message-handler.process.test.ts @@ -132,7 +132,9 @@ describe("processDiscordMessage ack reactions", () => { // oxlint-disable-next-line typescript/no-explicit-any await processDiscordMessage(ctx as any); - const emojis = reactMessageDiscord.mock.calls.map((call) => call[2]); + const emojis = ( + reactMessageDiscord.mock.calls as unknown as Array<[unknown, unknown, string]> + ).map((call) => call[2]); expect(emojis).toContain("👀"); expect(emojis).toContain("✅"); expect(emojis).not.toContain("🧠"); @@ -161,7 +163,9 @@ describe("processDiscordMessage ack reactions", () => { } await runPromise; - const emojis = reactMessageDiscord.mock.calls.map((call) => call[2]); + const emojis = ( + reactMessageDiscord.mock.calls as unknown as Array<[unknown, unknown, string]> + ).map((call) => call[2]); expect(emojis).toContain("⏳"); expect(emojis).toContain("⚠️"); expect(emojis).toContain("✅"); diff --git a/src/discord/monitor/message-utils.test.ts b/src/discord/monitor/message-utils.test.ts index 96041732484..c57eac93dc1 100644 --- a/src/discord/monitor/message-utils.test.ts +++ b/src/discord/monitor/message-utils.test.ts @@ -20,7 +20,7 @@ const { resolveDiscordMessageChannelId, resolveForwardedMediaList } = await import("./message-utils.js"); function asMessage(payload: Record): Message { - return payload as Message; + return payload as unknown as Message; } describe("resolveDiscordMessageChannelId", () => { diff --git a/src/discord/resolve-channels.test.ts b/src/discord/resolve-channels.test.ts index e3eaa55db44..5f5163f0705 100644 --- a/src/discord/resolve-channels.test.ts +++ b/src/discord/resolve-channels.test.ts @@ -5,9 +5,17 @@ function jsonResponse(body: unknown) { return new Response(JSON.stringify(body), { status: 200 }); } +const urlToString = (url: Request | URL | string): string => { + if (typeof url === "string") { + return url; + } + return "url" in url ? url.url : String(url); +}; + describe("resolveDiscordChannelAllowlist", () => { it("resolves guild/channel by name", async () => { - const fetcher = async (url: string) => { + const fetcher = async (input: RequestInfo | URL) => { + const url = urlToString(input); if (url.endsWith("/users/@me/guilds")) { return jsonResponse([{ id: "g1", name: "My Guild" }]); } @@ -32,7 +40,8 @@ describe("resolveDiscordChannelAllowlist", () => { }); it("resolves channel id to guild", async () => { - const fetcher = async (url: string) => { + const fetcher = async (input: RequestInfo | URL) => { + const url = urlToString(input); if (url.endsWith("/users/@me/guilds")) { return jsonResponse([{ id: "g1", name: "Guild One" }]); } @@ -54,7 +63,8 @@ describe("resolveDiscordChannelAllowlist", () => { }); it("resolves guild: prefixed id as guild (not channel)", async () => { - const fetcher = async (url: string) => { + const fetcher = async (input: RequestInfo | URL) => { + const url = urlToString(input); if (url.endsWith("/users/@me/guilds")) { return jsonResponse([{ id: "111222333444555666", name: "Guild One" }]); } @@ -80,7 +90,8 @@ describe("resolveDiscordChannelAllowlist", () => { // Demonstrates why provider.ts must prefix guild-only entries with "guild:" // In reality, Discord returns 404 when a guild ID is sent to /channels/, // which causes fetchDiscord to throw and the entire resolver to crash. - const fetcher = async (url: string) => { + const fetcher = async (input: RequestInfo | URL) => { + const url = urlToString(input); if (url.endsWith("/users/@me/guilds")) { return jsonResponse([{ id: "999", name: "My Server" }]); }