From df525b90f29f2dd5f237f6aa679799be4c7ce9ef Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 18 Apr 2026 18:28:20 +0100 Subject: [PATCH] chore(lint): enable unnecessary type parameter rule --- .oxlintrc.json | 2 +- .../register.files-downloads.ts | 1 + .../browser/src/node-host/invoke-browser.ts | 1 + .../discord/src/actions/runtime.messaging.ts | 2 +- .../src/monitor.tool-result.test-helpers.ts | 1 + .../src/monitor/message-handler.batch-gate.ts | 6 ++--- .../src/outbound-adapter.test-harness.ts | 1 + .../src/test-support/provider.test-support.ts | 1 + extensions/feishu/src/bitable.ts | 5 +++- .../test-support/lifecycle-test-support.ts | 4 +-- extensions/github-copilot/login.ts | 8 +++--- extensions/lmstudio/src/models.test.ts | 14 +++++----- .../matrix/src/onboarding.test-harness.ts | 1 + .../src/memory/manager-embedding-policy.ts | 4 +-- extensions/mistral/api.test.ts | 1 + extensions/msteams/src/attachments/graph.ts | 10 +++---- extensions/msteams/src/graph.test.ts | 2 +- .../qa-matrix/src/runners/contract/runtime.ts | 2 +- extensions/slack/src/channel.ts | 6 ++--- extensions/slack/src/monitor/provider.ts | 5 +++- extensions/xai/src/code-execution-shared.ts | 2 +- extensions/xai/src/tool-config-shared.ts | 10 +++---- extensions/xai/src/x-search-shared.ts | 2 +- scripts/lib/extension-package-boundary.ts | 1 + scripts/lib/plugin-npm-release.ts | 1 + src/agents/openai-tool-schema.ts | 4 +-- .../attempt.spawn-workspace.test-support.ts | 2 +- src/agents/tools/media-tool-shared.ts | 8 +++--- src/agents/tools/web-fetch.ts | 2 +- ...ge-summary-current-model-provider.cases.ts | 6 ++--- src/auto-reply/reply/reply-utils.test.ts | 6 ++--- src/channels/plugins/account-helpers.ts | 26 +++++++------------ .../plugins/channel-runtime-surface.types.ts | 1 + src/channels/plugins/chat-target-prefixes.ts | 8 +++--- src/channels/plugins/config-schema.ts | 4 +-- .../plugins/config-write-policy-shared.ts | 8 +++--- .../plugins/contracts/test-helpers.ts | 1 + src/cli/cli-utils.ts | 1 + src/cli/command-options.ts | 1 + src/cli/cron-cli.test.ts | 1 + src/cli/daemon-cli.coverage.test.ts | 1 + src/cli/daemon-cli/lifecycle-core.test.ts | 1 + src/cli/gateway-cli/run.ts | 4 +-- src/cli/plugins-cli-test-helpers.ts | 1 + src/cli/program/command-descriptor-utils.ts | 12 ++++----- src/cli/program/command-group-descriptors.ts | 4 +-- src/cli/program/json-mode.ts | 4 +-- src/cli/test-runtime-capture.ts | 1 + ....adds-non-default-telegram-account.test.ts | 1 + .../onboard-non-interactive.gateway.test.ts | 1 + src/commands/sandbox-formatters.ts | 4 +-- src/config/schema-base.ts | 2 +- src/config/schema.shared.ts | 4 +-- src/config/schema.ts | 2 +- src/gateway/test-helpers.server.ts | 1 + src/hooks/module-loader.ts | 1 + src/infra/channel-runtime-context.ts | 1 + src/infra/exec-approvals-effective.ts | 5 +++- src/infra/json-file.ts | 1 + src/infra/outbound/send-deps.ts | 1 + src/node-host/invoke.ts | 1 + src/plugin-sdk/allow-from.ts | 4 +-- src/plugin-sdk/channel-config-helpers.ts | 1 + src/plugin-sdk/channel-entry-contract.ts | 1 + src/plugin-sdk/extension-shared.ts | 4 +-- src/plugin-sdk/facade-loader.ts | 1 + src/plugin-sdk/facade-runtime.ts | 3 +++ src/plugin-sdk/qa-runner-runtime.ts | 1 + src/plugins/bundled-plugin-naming.test.ts | 1 + src/plugins/config-activation-shared.ts | 15 ++++------- ...tension-package-project-boundaries.test.ts | 1 + src/plugins/hooks.ts | 1 + src/plugins/lazy-service-module.ts | 1 + src/plugins/public-surface-loader.ts | 1 + src/plugins/registry.ts | 9 +++---- src/plugins/runtime/runtime-cache.ts | 6 +---- src/plugins/runtime/runtime-channel.ts | 1 + .../runtime/runtime-plugin-boundary.ts | 2 ++ src/plugins/runtime/types-channel.ts | 1 + src/plugins/web-provider-resolution-shared.ts | 7 ++--- src/secrets/runtime-web-tools.shared.ts | 4 +-- src/tasks/task-flow-registry.store.sqlite.ts | 1 + src/tasks/task-registry.store.sqlite.ts | 1 + .../bundled-plugin-public-surface.ts | 5 ++++ src/utils.ts | 1 + src/web-fetch/runtime.ts | 9 +++---- src/web-search/runtime.ts | 2 +- src/web/provider-runtime-shared.ts | 10 +++---- test/helpers/node-builtin-mocks.ts | 4 +-- .../plugins/package-manifest-contract.ts | 5 ++-- test/helpers/plugins/runtime-env.ts | 2 ++ test/helpers/plugins/setup-wizard.ts | 3 +++ test/helpers/plugins/subagent-hooks.ts | 1 + test/scripts/oxlint-config.test.ts | 4 +-- 94 files changed, 186 insertions(+), 152 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index bd335386f6c..062867ca09f 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -23,7 +23,7 @@ "typescript/no-meaningless-void-operator": "error", "typescript/no-unnecessary-type-assertion": "error", "typescript/no-unnecessary-type-conversion": "error", - "typescript/no-unnecessary-type-parameters": "off", + "typescript/no-unnecessary-type-parameters": "error", "typescript/no-unsafe-type-assertion": "off", "typescript/no-useless-default-assignment": "error", "unicorn/consistent-function-scoping": "off", diff --git a/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts b/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts index cf9188a84fe..d43674592f7 100644 --- a/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts +++ b/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts @@ -22,6 +22,7 @@ async function normalizeUploadPaths(paths: string[]): Promise { return result.paths; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Browser request result type is shared between request and success formatter. async function runBrowserPostAction(params: { parent: BrowserParentOpts; profile: string | undefined; diff --git a/extensions/browser/src/node-host/invoke-browser.ts b/extensions/browser/src/node-host/invoke-browser.ts index b7f05084c37..198ea6d9ef1 100644 --- a/extensions/browser/src/node-host/invoke-browser.ts +++ b/extensions/browser/src/node-host/invoke-browser.ts @@ -126,6 +126,7 @@ async function readBrowserProxyFile(filePath: string): Promise(raw?: string | null): T { if (!raw) { throw new Error("INVALID_REQUEST: paramsJSON required"); diff --git a/extensions/discord/src/actions/runtime.messaging.ts b/extensions/discord/src/actions/runtime.messaging.ts index 58cc9f533ea..51248a23ddd 100644 --- a/extensions/discord/src/actions/runtime.messaging.ts +++ b/extensions/discord/src/actions/runtime.messaging.ts @@ -118,7 +118,7 @@ export async function handleDiscordMessagingAction( : accountId ? { accountId } : undefined; - const withReactionRuntimeOptions = >(extra?: T) => ({ + const withReactionRuntimeOptions = (extra?: Record) => ({ ...(reactionRuntimeOptions ?? cfgOptions), ...extra, }); diff --git a/extensions/discord/src/monitor.tool-result.test-helpers.ts b/extensions/discord/src/monitor.tool-result.test-helpers.ts index 67b5637a7b6..1dca85e7e5e 100644 --- a/extensions/discord/src/monitor.tool-result.test-helpers.ts +++ b/extensions/discord/src/monitor.tool-result.test-helpers.ts @@ -311,6 +311,7 @@ export function createMentionRequiredGuildConfig(overrides?: Partial): C } export function captureNextDispatchCtx< + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe captured dispatch context shape. T extends { SessionKey?: string; ParentSessionKey?: string; diff --git a/extensions/discord/src/monitor/message-handler.batch-gate.ts b/extensions/discord/src/monitor/message-handler.batch-gate.ts index 95525d270dd..417b7e86fcc 100644 --- a/extensions/discord/src/monitor/message-handler.batch-gate.ts +++ b/extensions/discord/src/monitor/message-handler.batch-gate.ts @@ -6,8 +6,8 @@ type ReplyThreadingContext = { ReplyThreading?: ReplyThreadingPolicy; }; -export function applyImplicitReplyBatchGate( - ctx: T, +export function applyImplicitReplyBatchGate( + ctx: object, replyToMode: ReplyToMode, isBatched: boolean, ) { @@ -15,5 +15,5 @@ export function applyImplicitReplyBatchGate( if (!replyThreading) { return; } - (ctx as T & ReplyThreadingContext).ReplyThreading = replyThreading; + (ctx as ReplyThreadingContext).ReplyThreading = replyThreading; } diff --git a/extensions/discord/src/outbound-adapter.test-harness.ts b/extensions/discord/src/outbound-adapter.test-harness.ts index b6022f48bcb..338644fe7bb 100644 --- a/extensions/discord/src/outbound-adapter.test-harness.ts +++ b/extensions/discord/src/outbound-adapter.test-harness.ts @@ -15,6 +15,7 @@ type DiscordSendModule = typeof import("./send.js"); type DiscordSendComponentsModule = typeof import("./send.components.js"); type DiscordThreadBindingsModule = typeof import("./monitor/thread-bindings.js"); +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper preserves mock call and result types. function invokeMock( mock: (...args: unknown[]) => unknown, ...args: TArgs diff --git a/extensions/discord/src/test-support/provider.test-support.ts b/extensions/discord/src/test-support/provider.test-support.ts index 3fe9ed8409b..ae1821dffbb 100644 --- a/extensions/discord/src/test-support/provider.test-support.ts +++ b/extensions/discord/src/test-support/provider.test-support.ts @@ -205,6 +205,7 @@ export function mockResolvedDiscordAccountConfig(overrides: Record() { expect(createDiscordMessageHandlerMock).toHaveBeenCalledTimes(1); const firstCall = createDiscordMessageHandlerMock.mock.calls.at(0) as [T] | undefined; diff --git a/extensions/feishu/src/bitable.ts b/extensions/feishu/src/bitable.ts index b2cb8ea107f..77a234d7cd1 100644 --- a/extensions/feishu/src/bitable.ts +++ b/extensions/feishu/src/bitable.ts @@ -558,7 +558,10 @@ export function registerFeishuBitableTools(api: OpenClawPluginApi) { const getClient = (params: AccountAwareParams | undefined, defaultAccountId?: string) => createFeishuToolClient({ api, executeParams: params, defaultAccountId }); - const registerBitableTool = (params: { + const registerBitableTool = < + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Tool params bind each schema-specific executor to its registered tool. + TParams extends AccountAwareParams, + >(params: { name: string; label: string; description: string; diff --git a/extensions/feishu/src/test-support/lifecycle-test-support.ts b/extensions/feishu/src/test-support/lifecycle-test-support.ts index 60ac6360126..023b011e238 100644 --- a/extensions/feishu/src/test-support/lifecycle-test-support.ts +++ b/extensions/feishu/src/test-support/lifecycle-test-support.ts @@ -413,13 +413,13 @@ async function loadMonitorSingleAccount() { return module.monitorSingleAccount; } -export async function setupFeishuLifecycleHandler(params: { +export async function setupFeishuLifecycleHandler(params: { createEventDispatcherMock: { mockReturnValue: (value: unknown) => unknown; mockReturnValueOnce: (value: unknown) => unknown; }; onRegister: (registered: Record Promise>) => void; - runtime: T; + runtime: RuntimeEnv; cfg: ClawdbotConfig; account: ResolvedFeishuAccount; handlerKey: string; diff --git a/extensions/github-copilot/login.ts b/extensions/github-copilot/login.ts index b1cd01ec833..263b97ddcaf 100644 --- a/extensions/github-copilot/login.ts +++ b/extensions/github-copilot/login.ts @@ -32,11 +32,11 @@ type DeviceTokenResponse = error_uri?: string; }; -function parseJsonResponse(value: unknown): T { +function parseJsonResponse(value: unknown): Record { if (!value || typeof value !== "object") { throw new Error("Unexpected response from GitHub"); } - return value as T; + return value as Record; } async function requestDeviceCode(params: { scope: string }): Promise { @@ -58,7 +58,7 @@ async function requestDeviceCode(params: { scope: string }): Promise(await res.json()); + const json = parseJsonResponse(await res.json()) as DeviceCodeResponse; if (!json.device_code || !json.user_code || !json.verification_uri) { throw new Error("GitHub device code response missing fields"); } @@ -90,7 +90,7 @@ async function pollForAccessToken(params: { throw new Error(`GitHub device token failed: HTTP ${res.status}`); } - const json = parseJsonResponse(await res.json()); + const json = parseJsonResponse(await res.json()) as DeviceTokenResponse; if ("access_token" in json && typeof json.access_token === "string") { return json.access_token; } diff --git a/extensions/lmstudio/src/models.test.ts b/extensions/lmstudio/src/models.test.ts index bbf293ebc6b..df01a50b60a 100644 --- a/extensions/lmstudio/src/models.test.ts +++ b/extensions/lmstudio/src/models.test.ts @@ -22,12 +22,12 @@ vi.mock("openclaw/plugin-sdk/ssrf-runtime", async (importOriginal) => { }); describe("lmstudio-models", () => { - const asFetch = (mock: T) => mock as unknown as typeof fetch; - const parseJsonRequestBody = (init: RequestInit | undefined): T => { + const asFetch = (mock: unknown) => mock as typeof fetch; + const parseJsonRequestBody = (init: RequestInit | undefined): unknown => { if (typeof init?.body !== "string") { throw new Error("Expected request body to be a JSON string"); } - return JSON.parse(init.body) as T; + return JSON.parse(init.body) as unknown; }; afterEach(() => { @@ -215,7 +215,7 @@ describe("lmstudio-models", () => { const loadCall = fetchMock.mock.calls.find((call) => String(call[0]).endsWith("/models/load")); expect(loadCall).toBeDefined(); const loadInit = loadCall?.[1] as RequestInit; - const loadBody = parseJsonRequestBody<{ context_length: number }>(loadInit); + const loadBody = parseJsonRequestBody(loadInit) as { context_length: number }; expect(loadBody.context_length).toBe(8192); }); @@ -258,7 +258,7 @@ describe("lmstudio-models", () => { const loadCall = fetchMock.mock.calls.find((call) => String(call[0]).endsWith("/models/load")); expect(loadCall).toBeDefined(); const loadInit = loadCall?.[1] as RequestInit; - const loadBody = parseJsonRequestBody<{ context_length: number }>(loadInit); + const loadBody = parseJsonRequestBody(loadInit) as { context_length: number }; expect(loadBody.context_length).toBe(32768); }); @@ -318,7 +318,7 @@ describe("lmstudio-models", () => { }), }); const loadInit = loadCall![1] as RequestInit; - const loadBody = parseJsonRequestBody<{ context_length: number }>(loadInit); + const loadBody = parseJsonRequestBody(loadInit) as { context_length: number }; expect(loadBody.context_length).not.toBe(LMSTUDIO_DEFAULT_LOAD_CONTEXT_LENGTH); }); @@ -360,7 +360,7 @@ describe("lmstudio-models", () => { const loadCall = fetchMock.mock.calls.find((call) => String(call[0]).endsWith("/models/load")); expect(loadCall).toBeDefined(); const loadInit = loadCall?.[1] as unknown as RequestInit; - const loadBody = parseJsonRequestBody<{ context_length: number }>(loadInit); + const loadBody = parseJsonRequestBody(loadInit) as { context_length: number }; expect(loadBody.context_length).toBe(8192); }); diff --git a/extensions/matrix/src/onboarding.test-harness.ts b/extensions/matrix/src/onboarding.test-harness.ts index 64203d1f4fe..8c3dc3f925a 100644 --- a/extensions/matrix/src/onboarding.test-harness.ts +++ b/extensions/matrix/src/onboarding.test-harness.ts @@ -23,6 +23,7 @@ const previousMatrixEnv = Object.fromEntries( MATRIX_ENV_KEYS.map((key) => [key, process.env[key]]), ) as Record<(typeof MATRIX_ENV_KEYS)[number], string | undefined>; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets callers ascribe plugin runtime shape. function createNonExitingTypedRuntimeEnv(): TRuntime { return { log: vi.fn(), diff --git a/extensions/memory-core/src/memory/manager-embedding-policy.ts b/extensions/memory-core/src/memory/manager-embedding-policy.ts index 1d654f511fb..516bc9e1fc7 100644 --- a/extensions/memory-core/src/memory/manager-embedding-policy.ts +++ b/extensions/memory-core/src/memory/manager-embedding-policy.ts @@ -124,8 +124,6 @@ export async function runMemoryEmbeddingRetryLoop(params: { } } -export function buildTextEmbeddingInputs( - chunks: T[], -): MemoryEmbeddingInput[] { +export function buildTextEmbeddingInputs(chunks: MemoryEmbeddingChunk[]): MemoryEmbeddingInput[] { return chunks.map((chunk) => chunk.embeddingInput ?? { text: chunk.text }); } diff --git a/extensions/mistral/api.test.ts b/extensions/mistral/api.test.ts index 7ef4ae6cd36..a4671c4fab6 100644 --- a/extensions/mistral/api.test.ts +++ b/extensions/mistral/api.test.ts @@ -7,6 +7,7 @@ import { } from "./api.js"; import { contributeMistralResolvedModelCompat } from "./provider-compat.js"; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe provider compat shape. function readCompat(model: unknown): T | undefined { return (model as { compat?: T }).compat; } diff --git a/extensions/msteams/src/attachments/graph.ts b/extensions/msteams/src/attachments/graph.ts index 86d6247a0d7..a52b574bf26 100644 --- a/extensions/msteams/src/attachments/graph.ts +++ b/extensions/msteams/src/attachments/graph.ts @@ -119,12 +119,12 @@ export function buildMSTeamsGraphMessageUrls(params: { return Array.from(new Set(urls)); } -async function fetchGraphCollection(params: { +async function fetchGraphCollection(params: { url: string; accessToken: string; fetchFn?: typeof fetch; ssrfPolicy?: SsrFPolicy; -}): Promise<{ status: number; items: T[] }> { +}): Promise<{ status: number; items: unknown[] }> { const fetchFn = params.fetchFn ?? fetch; const { response, release } = await fetchWithSsrFGuard({ url: params.url, @@ -141,7 +141,7 @@ async function fetchGraphCollection(params: { return { status, items: [] }; } try { - const data = (await response.json()) as { value?: T[] }; + const data = (await response.json()) as { value?: unknown[] }; return { status, items: Array.isArray(data.value) ? data.value : [] }; } catch { return { status, items: [] }; @@ -182,12 +182,12 @@ async function downloadGraphHostedContent(params: { ssrfPolicy?: SsrFPolicy; logger?: MSTeamsAttachmentDownloadLogger; }): Promise<{ media: MSTeamsInboundMedia[]; status: number; count: number }> { - const hosted = await fetchGraphCollection({ + const hosted = (await fetchGraphCollection({ url: `${params.messageUrl}/hostedContents`, accessToken: params.accessToken, fetchFn: params.fetchFn, ssrfPolicy: params.ssrfPolicy, - }); + })) as { status: number; items: GraphHostedContent[] }; if (hosted.items.length === 0) { return { media: [], status: hosted.status, count: 0 }; } diff --git a/extensions/msteams/src/graph.test.ts b/extensions/msteams/src/graph.test.ts index 9e315f4432d..91e59dc7112 100644 --- a/extensions/msteams/src/graph.test.ts +++ b/extensions/msteams/src/graph.test.ts @@ -83,7 +83,7 @@ function graphCollection(...items: T[]) { return { value: items }; } -function mockGraphCollection(...items: T[]) { +function mockGraphCollection(...items: unknown[]) { mockJsonFetchResponse(graphCollection(...items)); } diff --git a/extensions/qa-matrix/src/runners/contract/runtime.ts b/extensions/qa-matrix/src/runners/contract/runtime.ts index 6deb35198a5..3a26a6fbcf1 100644 --- a/extensions/qa-matrix/src/runners/contract/runtime.ts +++ b/extensions/qa-matrix/src/runners/contract/runtime.ts @@ -160,7 +160,7 @@ function writeMatrixQaProgress(message: string) { process.stderr.write(`[matrix-qa] ${message}\n`); } -function countMatrixQaStatuses(entries: T[]) { +function countMatrixQaStatuses(entries: Array<{ status: "fail" | "pass" | "skip" }>) { return { failed: entries.filter((entry) => entry.status === "fail").length, passed: entries.filter((entry) => entry.status === "pass").length, diff --git a/extensions/slack/src/channel.ts b/extensions/slack/src/channel.ts index 7a423a8a6a2..9e22b3ee91e 100644 --- a/extensions/slack/src/channel.ts +++ b/extensions/slack/src/channel.ts @@ -379,10 +379,8 @@ export const slackPlugin: ChannelPlugin = crea }), resolver: { resolveTargets: async ({ cfg, accountId, inputs, kind }) => { - const toResolvedTarget = < - T extends { input: string; resolved: boolean; id?: string; name?: string }, - >( - entry: T, + const toResolvedTarget = ( + entry: { input: string; resolved: boolean; id?: string; name?: string }, note?: string, ) => ({ input: entry.input, diff --git a/extensions/slack/src/monitor/provider.ts b/extensions/slack/src/monitor/provider.ts index bf4f481d557..64afeb0c9fc 100644 --- a/extensions/slack/src/monitor/provider.ts +++ b/extensions/slack/src/monitor/provider.ts @@ -65,7 +65,10 @@ type SlackSocketShutdownClient = { }; type Constructor = abstract new (...args: never[]) => unknown; -function isConstructorFunction(value: unknown): value is T { +function isConstructorFunction< + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Constructor guard preserves the requested concrete Slack constructor type. + T extends Constructor, +>(value: unknown): value is T { return typeof value === "function"; } diff --git a/extensions/xai/src/code-execution-shared.ts b/extensions/xai/src/code-execution-shared.ts index f274348eba5..2c14a14d2b2 100644 --- a/extensions/xai/src/code-execution-shared.ts +++ b/extensions/xai/src/code-execution-shared.ts @@ -36,7 +36,7 @@ export type XaiCodeExecutionResult = { export function resolveXaiCodeExecutionConfig( config?: Record, ): XaiCodeExecutionConfig { - return coerceXaiToolConfig(config); + return coerceXaiToolConfig(config) as XaiCodeExecutionConfig; } export function resolveXaiCodeExecutionModel(config?: Record): string { diff --git a/extensions/xai/src/tool-config-shared.ts b/extensions/xai/src/tool-config-shared.ts index a81a9ac4167..9eda17fac6a 100644 --- a/extensions/xai/src/tool-config-shared.ts +++ b/extensions/xai/src/tool-config-shared.ts @@ -3,17 +3,17 @@ import { normalizeXaiModelId } from "../model-id.js"; export { isRecord }; -export function coerceXaiToolConfig>( +export function coerceXaiToolConfig( config: Record | undefined, -): TConfig { - return isRecord(config) ? (config as TConfig) : ({} as TConfig); +): Record { + return isRecord(config) ? config : {}; } export function resolveNormalizedXaiToolModel(params: { config?: Record; defaultModel: string; }): string { - const value = coerceXaiToolConfig<{ model?: unknown }>(params.config).model; + const value = coerceXaiToolConfig(params.config).model; return typeof value === "string" && value.trim() ? normalizeXaiModelId(value.trim()) : params.defaultModel; @@ -23,7 +23,7 @@ export function resolvePositiveIntegerToolConfig( config: Record | undefined, key: string, ): number | undefined { - const raw = coerceXaiToolConfig>(config)[key]; + const raw = coerceXaiToolConfig(config)[key]; if (typeof raw !== "number" || !Number.isFinite(raw)) { return undefined; } diff --git a/extensions/xai/src/x-search-shared.ts b/extensions/xai/src/x-search-shared.ts index 53a41f4ed10..e0178ef034b 100644 --- a/extensions/xai/src/x-search-shared.ts +++ b/extensions/xai/src/x-search-shared.ts @@ -38,7 +38,7 @@ export type XaiXSearchResult = { }; export function resolveXaiXSearchConfig(config?: Record): XaiXSearchConfig { - return coerceXaiToolConfig(config); + return coerceXaiToolConfig(config) as XaiXSearchConfig; } export function resolveXaiXSearchModel(config?: Record): string { diff --git a/scripts/lib/extension-package-boundary.ts b/scripts/lib/extension-package-boundary.ts index 831e9892aec..8cadd0df2ce 100644 --- a/scripts/lib/extension-package-boundary.ts +++ b/scripts/lib/extension-package-boundary.ts @@ -130,6 +130,7 @@ export type ExtensionPackageBoundaryPackageJson = { devDependencies?: Record; }; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Boundary helper lets callers ascribe JSON file shape. function readJsonFile(filePath: string): T { return JSON.parse(readFileSync(filePath, "utf8")) as T; } diff --git a/scripts/lib/plugin-npm-release.ts b/scripts/lib/plugin-npm-release.ts index f93f005bfe9..c4f16c6504d 100644 --- a/scripts/lib/plugin-npm-release.ts +++ b/scripts/lib/plugin-npm-release.ts @@ -64,6 +64,7 @@ export type PublishablePluginPackageCandidate< packageJson: TPackageJson; }; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Release helper preserves caller-specific package.json shape. function readPluginPackageJson( path: string, ): TPackageJson { diff --git a/src/agents/openai-tool-schema.ts b/src/agents/openai-tool-schema.ts index 34937230b5d..24d536b6b3c 100644 --- a/src/agents/openai-tool-schema.ts +++ b/src/agents/openai-tool-schema.ts @@ -119,8 +119,8 @@ function isStrictOpenAIJsonSchemaCompatibleRecursive(schema: unknown): boolean { }); } -export function resolveOpenAIStrictToolFlagForInventory( - tools: readonly T[], +export function resolveOpenAIStrictToolFlagForInventory( + tools: readonly ToolWithParameters[], strict: boolean | null | undefined, ): boolean | undefined { if (strict !== true) { diff --git a/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts b/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts index c01ccf9581a..22660fc64d6 100644 --- a/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts +++ b/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts @@ -555,7 +555,7 @@ vi.mock("../compaction-safety-timeout.js", () => ({ vi.mock("../history.js", () => ({ getDmHistoryLimitFromSessionKey: (sessionKey: string | undefined, config: unknown) => hoisted.getDmHistoryLimitFromSessionKeyMock(sessionKey, config), - limitHistoryTurns: (messages: T, limit: number | undefined) => + limitHistoryTurns: (messages: unknown, limit: number | undefined) => hoisted.limitHistoryTurnsMock(messages, limit), })); diff --git a/src/agents/tools/media-tool-shared.ts b/src/agents/tools/media-tool-shared.ts index b2c1d83c6b8..4d7d54191ea 100644 --- a/src/agents/tools/media-tool-shared.ts +++ b/src/agents/tools/media-tool-shared.ts @@ -161,10 +161,10 @@ export function resolveSelectedCapabilityProvider( }); } -export function resolveCapabilityModelCandidatesForTool(params: { +export function resolveCapabilityModelCandidatesForTool(params: { cfg?: OpenClawConfig; agentDir?: string; - providers: T[]; + providers: CapabilityProvider[]; }): string[] { const providerDefaults = new Map(); for (const provider of params.providers) { @@ -206,11 +206,11 @@ export function resolveCapabilityModelCandidatesForTool(params: { +export function resolveCapabilityModelConfigForTool(params: { cfg?: OpenClawConfig; agentDir?: string; modelConfig?: AgentModelConfig; - providers: T[]; + providers: CapabilityProvider[]; }): ToolModelConfig | null { const explicit = coerceToolModelConfig(params.modelConfig); if (hasToolModelConfig(explicit)) { diff --git a/src/agents/tools/web-fetch.ts b/src/agents/tools/web-fetch.ts index 0a640fd3e3c..61675743b03 100644 --- a/src/agents/tools/web-fetch.ts +++ b/src/agents/tools/web-fetch.ts @@ -75,7 +75,7 @@ type WebFetchConfig = NonNullable["web"] extends infer : undefined; function resolveFetchConfig(cfg?: OpenClawConfig): WebFetchConfig { - return resolveWebProviderConfig<"fetch", NonNullable>(cfg, "fetch"); + return resolveWebProviderConfig(cfg, "fetch") as NonNullable | undefined; } function resolveFetchEnabled(params: { fetch?: WebFetchConfig; sandboxed?: boolean }): boolean { diff --git a/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts b/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts index 8b12d78f73f..d0f6d3edb1f 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts @@ -18,8 +18,8 @@ async function readSessionStore(storePath: string): Promise; } -function pickFirstStoreEntry(store: Record): T | undefined { - const entries = Object.values(store) as T[]; +function pickFirstStoreEntry(store: Record): unknown { + const entries = Object.values(store); return entries[0]; } @@ -145,7 +145,7 @@ export function registerTriggerHandlingUsageSummaryCases(params: { expect(replyText(r3)).toContain("Usage footer: tokens"); const finalStore = await readSessionStore(usageStorePath); - expect(pickFirstStoreEntry<{ responseUsage?: string }>(finalStore)?.responseUsage).toBe( + expect((pickFirstStoreEntry(finalStore) as { responseUsage?: string })?.responseUsage).toBe( "tokens", ); expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled(); diff --git a/src/auto-reply/reply/reply-utils.test.ts b/src/auto-reply/reply/reply-utils.test.ts index 0efe300255d..76a877fdae4 100644 --- a/src/auto-reply/reply/reply-utils.test.ts +++ b/src/auto-reply/reply/reply-utils.test.ts @@ -467,14 +467,14 @@ describe("parseAudioTag", () => { }); describe("resolveResponsePrefixTemplate", () => { - function expectResolvedTemplateCases< - T extends ReadonlyArray<{ + function expectResolvedTemplateCases( + cases: ReadonlyArray<{ name: string; template: string | undefined; values: Parameters[1]; expected: string | undefined; }>, - >(cases: T) { + ) { for (const testCase of cases) { expect(resolveResponsePrefixTemplate(testCase.template, testCase.values), testCase.name).toBe( testCase.expected, diff --git a/src/channels/plugins/account-helpers.ts b/src/channels/plugins/account-helpers.ts index ed3b2ad3984..9fc06862d35 100644 --- a/src/channels/plugins/account-helpers.ts +++ b/src/channels/plugins/account-helpers.ts @@ -176,14 +176,14 @@ export function resolveMergedAccountConfig(params: { - account: TAccount; +type AccountSnapshotInput = { + accountId?: string | null; + enabled?: boolean | null; + name?: string | null | undefined; +}; + +export function describeAccountSnapshot(params: { + account: AccountSnapshotInput; configured?: boolean | undefined; extra?: Record | undefined; }): ChannelAccountSnapshot { @@ -196,14 +196,8 @@ export function describeAccountSnapshot< }; } -export function describeWebhookAccountSnapshot< - TAccount extends { - accountId?: string | null; - enabled?: boolean | null; - name?: string | null | undefined; - }, ->(params: { - account: TAccount; +export function describeWebhookAccountSnapshot(params: { + account: AccountSnapshotInput; configured?: boolean | undefined; mode?: string | undefined; extra?: Record | undefined; diff --git a/src/channels/plugins/channel-runtime-surface.types.ts b/src/channels/plugins/channel-runtime-surface.types.ts index aea0d1ae721..b06eab1be1a 100644 --- a/src/channels/plugins/channel-runtime-surface.types.ts +++ b/src/channels/plugins/channel-runtime-surface.types.ts @@ -21,6 +21,7 @@ export type ChannelRuntimeContextRegistry = { abortSignal?: AbortSignal; }, ) => { dispose: () => void }; + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Runtime context values are caller-typed by key. get: (params: ChannelRuntimeContextKey) => T | undefined; watch: (params: { channelId?: string; diff --git a/src/channels/plugins/chat-target-prefixes.ts b/src/channels/plugins/chat-target-prefixes.ts index ea95a65feff..3f79b6ea4e9 100644 --- a/src/channels/plugins/chat-target-prefixes.ts +++ b/src/channels/plugins/chat-target-prefixes.ts @@ -29,14 +29,14 @@ export type ChatSenderAllowParams = { chatIdentifier?: string | null; }; -function isAllowedParsedChatSender(params: { +function isAllowedParsedChatSender(params: { allowFrom: Array; sender: string; chatId?: number | null; chatGuid?: string | null; chatIdentifier?: string | null; normalizeSender: (sender: string) => string; - parseAllowTarget: (entry: string) => TParsed; + parseAllowTarget: (entry: string) => ParsedChatAllowTarget; }): boolean { const allowFrom = normalizeStringEntries(params.allowFrom); if (allowFrom.length === 0) { @@ -224,9 +224,9 @@ export function resolveServicePrefixedOrChatAllowTarget< return null; } -export function createAllowedChatSenderMatcher(params: { +export function createAllowedChatSenderMatcher(params: { normalizeSender: (sender: string) => string; - parseAllowTarget: (entry: string) => TParsed; + parseAllowTarget: (entry: string) => ParsedChatAllowTarget; }): (input: ChatSenderAllowParams) => boolean { return (input) => isAllowedParsedChatSender({ diff --git a/src/channels/plugins/config-schema.ts b/src/channels/plugins/config-schema.ts index 032832901e1..8bbecf9a31e 100644 --- a/src/channels/plugins/config-schema.ts +++ b/src/channels/plugins/config-schema.ts @@ -18,9 +18,7 @@ type ExtendableZodObject = ZodTypeAny & { export const AllowFromEntrySchema = z.union([z.string(), z.number()]); export const AllowFromListSchema = z.array(AllowFromEntrySchema).optional(); -export function buildNestedDmConfigSchema( - extraShape?: TExtraShape, -) { +export function buildNestedDmConfigSchema(extraShape?: ZodRawShape) { const baseShape = { enabled: z.boolean().optional(), policy: DmPolicySchema.optional(), diff --git a/src/channels/plugins/config-write-policy-shared.ts b/src/channels/plugins/config-write-policy-shared.ts index c6bae507b97..17f2ebc6c64 100644 --- a/src/channels/plugins/config-write-policy-shared.ts +++ b/src/channels/plugins/config-write-policy-shared.ts @@ -48,9 +48,9 @@ function listConfigWriteTargetScopes( return [target.scope]; } -function resolveChannelConfig( +function resolveChannelConfig( cfg: ConfigWritePolicyConfig, - channelId?: TChannelId | null, + channelId?: string | null, ): ChannelConfigWithAccounts | undefined { if (!channelId) { return undefined; @@ -65,9 +65,9 @@ function resolveChannelAccountConfig( return resolveAccountEntry(channelConfig.accounts, normalizeAccountId(accountId)); } -export function resolveChannelConfigWritesShared(params: { +export function resolveChannelConfigWritesShared(params: { cfg: ConfigWritePolicyConfig; - channelId?: TChannelId | null; + channelId?: string | null; accountId?: string | null; }): boolean { const channelConfig = resolveChannelConfig(params.cfg, params.channelId); diff --git a/src/channels/plugins/contracts/test-helpers.ts b/src/channels/plugins/contracts/test-helpers.ts index 76ef640a93f..742c515e08b 100644 --- a/src/channels/plugins/contracts/test-helpers.ts +++ b/src/channels/plugins/contracts/test-helpers.ts @@ -4,6 +4,7 @@ import { normalizeChatType } from "../../chat-type.js"; import { resolveConversationLabel } from "../../conversation-label.js"; import { validateSenderIdentity } from "../../sender-identity.js"; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper preserves channel send mock arg types. export function primeChannelOutboundSendMock( sendMock: Mock<(...args: TArgs) => Promise>, fallbackResult: Record, diff --git a/src/cli/cli-utils.ts b/src/cli/cli-utils.ts index d91b9a3331b..c759223ea2d 100644 --- a/src/cli/cli-utils.ts +++ b/src/cli/cli-utils.ts @@ -48,6 +48,7 @@ export async function runCommandWithRuntime( } } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Commander option values are typed by the caller. export function resolveOptionFromCommand( command: Command | undefined, key: string, diff --git a/src/cli/command-options.ts b/src/cli/command-options.ts index 0f1830c95c1..7a0849e0500 100644 --- a/src/cli/command-options.ts +++ b/src/cli/command-options.ts @@ -17,6 +17,7 @@ function getOptionSource(command: Command, name: string): string | undefined { // Defensive guardrail: allow expected parent/grandparent inheritance without unbounded deep traversal. const MAX_INHERIT_DEPTH = 2; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Commander option values are typed by the caller. export function inheritOptionFromParent( command: Command | undefined, name: string, diff --git a/src/cli/cron-cli.test.ts b/src/cli/cron-cli.test.ts index fc2ed26b96a..96c7ec5fbea 100644 --- a/src/cli/cron-cli.test.ts +++ b/src/cli/cron-cli.test.ts @@ -147,6 +147,7 @@ function mockCronEditJobLookup(schedule: unknown): void { ); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets each assertion ascribe expected RPC params. function getGatewayCallParams(method: string): T { const call = callGatewayFromCli.mock.calls.find((entry) => entry[0] === method); return (call?.[2] ?? {}) as T; diff --git a/src/cli/daemon-cli.coverage.test.ts b/src/cli/daemon-cli.coverage.test.ts index 36a9e24e061..fb7c8972b71 100644 --- a/src/cli/daemon-cli.coverage.test.ts +++ b/src/cli/daemon-cli.coverage.test.ts @@ -147,6 +147,7 @@ async function runDaemonCommand(args: string[]) { await daemonProgram.parseAsync(args, { from: "user" }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe logged JSON shape. function parseFirstJsonRuntimeLine() { const jsonLine = runtimeLogs.find((line) => line.trim().startsWith("{")); return JSON.parse(jsonLine ?? "{}") as T; diff --git a/src/cli/daemon-cli/lifecycle-core.test.ts b/src/cli/daemon-cli/lifecycle-core.test.ts index a9bcf37d4d3..5416a36946e 100644 --- a/src/cli/daemon-cli/lifecycle-core.test.ts +++ b/src/cli/daemon-cli/lifecycle-core.test.ts @@ -30,6 +30,7 @@ let runServiceRestart: typeof import("./lifecycle-core.js").runServiceRestart; let runServiceStart: typeof import("./lifecycle-core.js").runServiceStart; let runServiceStop: typeof import("./lifecycle-core.js").runServiceStop; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe logged JSON shape. function readJsonLog() { const jsonLine = runtimeLogs.find((line) => line.trim().startsWith("{")); return JSON.parse(jsonLine ?? "{}") as T; diff --git a/src/cli/gateway-cli/run.ts b/src/cli/gateway-cli/run.ts index 8497d2d85a6..a548aa2964c 100644 --- a/src/cli/gateway-cli/run.ts +++ b/src/cli/gateway-cli/run.ts @@ -141,11 +141,11 @@ function parseEnumOption( return (allowed as readonly string[]).includes(raw) ? (raw as T) : null; } -function formatModeChoices(modes: readonly T[]): string { +function formatModeChoices(modes: readonly string[]): string { return modes.map((mode) => `"${mode}"`).join("|"); } -function formatModeErrorList(modes: readonly T[]): string { +function formatModeErrorList(modes: readonly string[]): string { const quoted = modes.map((mode) => `"${mode}"`); if (quoted.length === 0) { return ""; diff --git a/src/cli/plugins-cli-test-helpers.ts b/src/cli/plugins-cli-test-helpers.ts index 5ff154f612f..70990755210 100644 --- a/src/cli/plugins-cli-test-helpers.ts +++ b/src/cli/plugins-cli-test-helpers.ts @@ -15,6 +15,7 @@ type ListMarketplacePluginsFn = type ResolveMarketplaceInstallShortcutFn = (typeof import("../plugins/marketplace.js"))["resolveMarketplaceInstallShortcut"]; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper preserves mock call and result types. function invokeMock(mock: unknown, ...args: TArgs): TResult { return (mock as (...args: TArgs) => TResult)(...args); } diff --git a/src/cli/program/command-descriptor-utils.ts b/src/cli/program/command-descriptor-utils.ts index 98559c0f93d..5cb247f035b 100644 --- a/src/cli/program/command-descriptor-utils.ts +++ b/src/cli/program/command-descriptor-utils.ts @@ -10,14 +10,12 @@ export type CommandDescriptorCatalog getCommandsWithSubcommands: () => string[]; }; -export function getCommandDescriptorNames( - descriptors: readonly TDescriptor[], -): string[] { +export function getCommandDescriptorNames(descriptors: readonly CommandDescriptorLike[]): string[] { return descriptors.map((descriptor) => descriptor.name); } -export function getCommandsWithSubcommands( - descriptors: readonly TDescriptor[], +export function getCommandsWithSubcommands( + descriptors: readonly NamedCommandDescriptor[], ): string[] { return descriptors .filter((descriptor) => descriptor.hasSubcommands) @@ -52,9 +50,9 @@ export function defineCommandDescriptorCatalog( +export function addCommandDescriptorsToProgram( program: Command, - descriptors: readonly TDescriptor[], + descriptors: readonly CommandDescriptorLike[], existingCommands: Set = new Set(), ): Set { for (const descriptor of descriptors) { diff --git a/src/cli/program/command-group-descriptors.ts b/src/cli/program/command-group-descriptors.ts index 2d36cb902d3..11f46a64d3c 100644 --- a/src/cli/program/command-group-descriptors.ts +++ b/src/cli/program/command-group-descriptors.ts @@ -46,8 +46,8 @@ export function resolveCommandGroupEntries( - descriptors: readonly TDescriptor[], +export function buildCommandGroupEntries( + descriptors: readonly NamedCommandDescriptor[], specs: readonly CommandGroupDescriptorSpec[], mapRegister: (register: TRegister) => CommandGroupEntry["register"], ): CommandGroupEntry[] { diff --git a/src/cli/program/json-mode.ts b/src/cli/program/json-mode.ts index b289bea9117..3f2862bc5c4 100644 --- a/src/cli/program/json-mode.ts +++ b/src/cli/program/json-mode.ts @@ -27,10 +27,10 @@ function getDeclaredCommandJsonMode(command: Command): JsonMode | null { function commandSelectedJsonFlag(command: Command, argv: string[]): boolean { const commandWithGlobals = command as Command & { - optsWithGlobals?: >() => T; + optsWithGlobals?: () => Record; }; if (typeof commandWithGlobals.optsWithGlobals === "function") { - const resolved = commandWithGlobals.optsWithGlobals>().json; + const resolved = commandWithGlobals.optsWithGlobals().json; if (resolved === true) { return true; } diff --git a/src/cli/test-runtime-capture.ts b/src/cli/test-runtime-capture.ts index 6a72a93be4f..f48d24a950d 100644 --- a/src/cli/test-runtime-capture.ts +++ b/src/cli/test-runtime-capture.ts @@ -89,6 +89,7 @@ export function spyRuntimeJson(runtime: Pick) { return vi.spyOn(runtime, "writeJson").mockImplementation(() => {}); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets callers ascribe captured JSON shape. export function firstWrittenJsonArg(writeJson: MockCallsWithFirstArg): T | null { return (writeJson.mock.calls[0]?.[0] ?? null) as T | null; } diff --git a/src/commands/channels.adds-non-default-telegram-account.test.ts b/src/commands/channels.adds-non-default-telegram-account.test.ts index aac07082da2..c3558ebf2de 100644 --- a/src/commands/channels.adds-non-default-telegram-account.test.ts +++ b/src/commands/channels.adds-non-default-telegram-account.test.ts @@ -313,6 +313,7 @@ describe("channels command", () => { setMinimalChannelsCommandRegistryForTests(); }); + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe written config shape. function getWrittenConfig(): T { expect(configMocks.writeConfigFile).toHaveBeenCalledTimes(1); return configMocks.writeConfigFile.mock.calls[0]?.[0] as T; diff --git a/src/commands/onboard-non-interactive.gateway.test.ts b/src/commands/onboard-non-interactive.gateway.test.ts index 0bedc8923b7..13452b84ae7 100644 --- a/src/commands/onboard-non-interactive.gateway.test.ts +++ b/src/commands/onboard-non-interactive.gateway.test.ts @@ -53,6 +53,7 @@ function resolveTestConfigPath() { return path.join(stateDir, "openclaw.json"); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe stored config shape. function readTestConfig(): T { return (testConfigStore.get(resolveTestConfigPath()) ?? {}) as T; } diff --git a/src/commands/sandbox-formatters.ts b/src/commands/sandbox-formatters.ts index f96fc631ffd..b48f5878aec 100644 --- a/src/commands/sandbox-formatters.ts +++ b/src/commands/sandbox-formatters.ts @@ -28,10 +28,10 @@ export type ContainerItem = { lastUsedAtMs: number; }; -export function countRunning(items: T[]): number { +export function countRunning(items: readonly { running: boolean }[]): number { return items.filter((item) => item.running).length; } -export function countMismatches(items: T[]): number { +export function countMismatches(items: readonly { imageMatch: boolean }[]): number { return items.filter((item) => !item.imageMatch).length; } diff --git a/src/config/schema-base.ts b/src/config/schema-base.ts index 9720ba268a5..ce9425d22f0 100644 --- a/src/config/schema-base.ts +++ b/src/config/schema-base.ts @@ -35,7 +35,7 @@ type JsonSchemaObject = Record & { const LEGACY_HIDDEN_PUBLIC_PATHS = ["hooks.internal.handlers"] as const; const asJsonSchemaObject = (value: unknown): JsonSchemaObject | null => - asSchemaObject(value); + asSchemaObject(value) as JsonSchemaObject | null; function buildFieldDocumentation(): FieldDocumentation { const titles: Record = {}; diff --git a/src/config/schema.shared.ts b/src/config/schema.shared.ts index 11e220c5d87..acaf786589b 100644 --- a/src/config/schema.shared.ts +++ b/src/config/schema.shared.ts @@ -15,11 +15,11 @@ export function cloneSchema(value: T): T { return JSON.parse(JSON.stringify(value)) as T; } -export function asSchemaObject(value: unknown): T | null { +export function asSchemaObject(value: unknown): object | null { if (!value || typeof value !== "object" || Array.isArray(value)) { return null; } - return value as T; + return value; } export function schemaHasChildren(schema: JsonSchemaObject): boolean { diff --git a/src/config/schema.ts b/src/config/schema.ts index 44e4b3c0ff7..067d9639020 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -28,7 +28,7 @@ type JsonSchemaObject = JsonSchemaNode & { }; const asJsonSchemaObject = (value: unknown): JsonSchemaObject | null => - asSchemaObject(value); + asSchemaObject(value) as JsonSchemaObject | null; const FORBIDDEN_LOOKUP_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]); const LOOKUP_SCHEMA_STRING_KEYS = new Set([ diff --git a/src/gateway/test-helpers.server.ts b/src/gateway/test-helpers.server.ts index 4b53d99a88a..e3512f60c07 100644 --- a/src/gateway/test-helpers.server.ts +++ b/src/gateway/test-helpers.server.ts @@ -1033,6 +1033,7 @@ export async function connectWebchatClient(params: { return ws; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Gateway test RPC helper lets callers ascribe response payload shape. export async function rpcReq>( ws: WebSocket, method: string, diff --git a/src/hooks/module-loader.ts b/src/hooks/module-loader.ts index 7ce275aea3e..df571b48d93 100644 --- a/src/hooks/module-loader.ts +++ b/src/hooks/module-loader.ts @@ -25,6 +25,7 @@ export async function importFileModule(params: { return (await import(specifier)) as ModuleNamespace; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic module exports are typed by the caller. export function resolveFunctionModuleExport(params: { mod: ModuleNamespace; exportName?: string; diff --git a/src/infra/channel-runtime-context.ts b/src/infra/channel-runtime-context.ts index 799e6e3f526..da79fcef539 100644 --- a/src/infra/channel-runtime-context.ts +++ b/src/infra/channel-runtime-context.ts @@ -48,6 +48,7 @@ export function registerChannelRuntimeContext( }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Runtime context values are caller-typed by key. export function getChannelRuntimeContext( params: ChannelRuntimeContextKey & { channelRuntime?: ChannelRuntimeSurface; diff --git a/src/infra/exec-approvals-effective.ts b/src/infra/exec-approvals-effective.ts index f8ad3fe9d90..4b23345e4a5 100644 --- a/src/infra/exec-approvals-effective.ts +++ b/src/infra/exec-approvals-effective.ts @@ -94,7 +94,10 @@ function formatRequestedSource(params: { type ExecPolicyField = "security" | "ask" | "askFallback"; -function resolveRequestedField(params: { +function resolveRequestedField< + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Field-specific callers narrow the shared requested policy value. + TValue extends ExecSecurity | ExecAsk, +>(params: { field: ExecPolicyRequestedField; scopeExecConfig?: ExecPolicyConfig; globalExecConfig?: ExecPolicyConfig; diff --git a/src/infra/json-file.ts b/src/infra/json-file.ts index 01602efb430..247d6b404db 100644 --- a/src/infra/json-file.ts +++ b/src/infra/json-file.ts @@ -96,6 +96,7 @@ function writeTempJsonFile(pathname: string, payload: string) { } } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- JSON loading helper lets callers ascribe the expected payload type. export function loadJsonFile(pathname: string): T | undefined { try { const raw = fs.readFileSync(pathname, "utf8"); diff --git a/src/infra/outbound/send-deps.ts b/src/infra/outbound/send-deps.ts index 80d91adf589..7b491fdd8b3 100644 --- a/src/infra/outbound/send-deps.ts +++ b/src/infra/outbound/send-deps.ts @@ -26,6 +26,7 @@ export type ResolveOutboundSendDepOptions = { legacyKeys?: readonly string[]; }; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Channel-specific dependency lookup returns caller-typed values. export function resolveOutboundSendDep( deps: OutboundSendDeps | null | undefined, channelId: string, diff --git a/src/node-host/invoke.ts b/src/node-host/invoke.ts index 972bddecc10..bb039ad5b88 100644 --- a/src/node-host/invoke.ts +++ b/src/node-host/invoke.ts @@ -560,6 +560,7 @@ export async function handleInvoke( }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- CLI JSON params are typed by the invoked method. function decodeParams(raw?: string | null): T { if (!raw) { throw new Error("INVALID_REQUEST: paramsJSON required"); diff --git a/src/plugin-sdk/allow-from.ts b/src/plugin-sdk/allow-from.ts index c41426d8b2e..567449b266a 100644 --- a/src/plugin-sdk/allow-from.ts +++ b/src/plugin-sdk/allow-from.ts @@ -81,14 +81,14 @@ type ParsedChatAllowTarget = | { kind: "handle"; handle: string }; /** Match chat-aware allowlist entries against sender, chat id, guid, or identifier fields. */ -export function isAllowedParsedChatSender(params: { +export function isAllowedParsedChatSender(params: { allowFrom: Array; sender: string; chatId?: number | null; chatGuid?: string | null; chatIdentifier?: string | null; normalizeSender: (sender: string) => string; - parseAllowTarget: (entry: string) => TParsed; + parseAllowTarget: (entry: string) => ParsedChatAllowTarget; }): boolean { const allowFrom = params.allowFrom.map((entry) => String(entry).trim()); if (allowFrom.length === 0) { diff --git a/src/plugin-sdk/channel-config-helpers.ts b/src/plugin-sdk/channel-config-helpers.ts index ae1ce3ddbf3..fa4e63aade0 100644 --- a/src/plugin-sdk/channel-config-helpers.ts +++ b/src/plugin-sdk/channel-config-helpers.ts @@ -214,6 +214,7 @@ export function adaptScopedAccountAccessor(params: { resolveAccount: (params: { cfg: Config; accountId?: string | null }) => ResolvedAccount; diff --git a/src/plugin-sdk/channel-entry-contract.ts b/src/plugin-sdk/channel-entry-contract.ts index 621f42afcf3..e8b709ce3c9 100644 --- a/src/plugin-sdk/channel-entry-contract.ts +++ b/src/plugin-sdk/channel-entry-contract.ts @@ -335,6 +335,7 @@ function loadBundledEntryModuleSync(importMetaUrl: string, specifier: string): u return loaded; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic entry export loaders use caller-supplied export types. export function loadBundledEntryExportSync( importMetaUrl: string, reference: BundledEntryModuleRef, diff --git a/src/plugin-sdk/extension-shared.ts b/src/plugin-sdk/extension-shared.ts index efe035c9574..2da583eab3f 100644 --- a/src/plugin-sdk/extension-shared.ts +++ b/src/plugin-sdk/extension-shared.ts @@ -56,9 +56,7 @@ export function buildPassiveProbedChannelStatusSummary( }; } -export function buildTrafficStatusSummary( - snapshot?: TSnapshot | null, -) { +export function buildTrafficStatusSummary(snapshot?: TrafficStatusSnapshot | null) { return { lastInboundAt: snapshot?.lastInboundAt ?? null, lastOutboundAt: snapshot?.lastOutboundAt ?? null, diff --git a/src/plugin-sdk/facade-loader.ts b/src/plugin-sdk/facade-loader.ts index 4d9da4da9ea..b95252b6d84 100644 --- a/src/plugin-sdk/facade-loader.ts +++ b/src/plugin-sdk/facade-loader.ts @@ -257,6 +257,7 @@ export function loadFacadeModuleAtLocationSync(params: { return sentinel; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic facade loaders use caller-supplied module surface types. export function loadBundledPluginPublicSurfaceModuleSync(params: { dirName: string; artifactBasename: string; diff --git a/src/plugin-sdk/facade-runtime.ts b/src/plugin-sdk/facade-runtime.ts index ae87087c820..724a35fa6a7 100644 --- a/src/plugin-sdk/facade-runtime.ts +++ b/src/plugin-sdk/facade-runtime.ts @@ -239,6 +239,7 @@ function buildFacadeActivationCheckParams( }; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic facade loaders use caller-supplied module surface types. export function loadBundledPluginPublicSurfaceModuleSync( params: BundledPluginPublicSurfaceParams, ): T { @@ -269,6 +270,7 @@ export function canLoadActivatedBundledPluginPublicSurface(params: { ).allowed; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic facade loaders use caller-supplied module surface types. export function loadActivatedBundledPluginPublicSurfaceModuleSync(params: { dirName: string; artifactBasename: string; @@ -280,6 +282,7 @@ export function loadActivatedBundledPluginPublicSurfaceModuleSync(params); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic facade loaders use caller-supplied module surface types. export function tryLoadActivatedBundledPluginPublicSurfaceModuleSync(params: { dirName: string; artifactBasename: string; diff --git a/src/plugin-sdk/qa-runner-runtime.ts b/src/plugin-sdk/qa-runner-runtime.ts index 1349daa5740..9e660156a46 100644 --- a/src/plugin-sdk/qa-runner-runtime.ts +++ b/src/plugin-sdk/qa-runner-runtime.ts @@ -62,6 +62,7 @@ export function loadQaRuntimeModule(): QaRuntimeSurface { }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- QA runtime loader uses caller-supplied test API surface type. export function loadQaRunnerBundledPluginTestApi(pluginId: string): T { const env = resolvePrivateQaBundledPluginsEnv(); return loadBundledPluginPublicSurfaceModuleSync({ diff --git a/src/plugins/bundled-plugin-naming.test.ts b/src/plugins/bundled-plugin-naming.test.ts index 0e075bc61d8..c5087faa867 100644 --- a/src/plugins/bundled-plugin-naming.test.ts +++ b/src/plugins/bundled-plugin-naming.test.ts @@ -40,6 +40,7 @@ const ALLOWED_PACKAGE_SUFFIXES = [ "-media-understanding", ] as const; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe JSON file shape. function readJsonFile(filePath: string): T { return JSON.parse(fs.readFileSync(filePath, "utf8")) as T; } diff --git a/src/plugins/config-activation-shared.ts b/src/plugins/config-activation-shared.ts index 301ff772cc1..2de75808037 100644 --- a/src/plugins/config-activation-shared.ts +++ b/src/plugins/config-activation-shared.ts @@ -12,25 +12,20 @@ type EnableStateParamsLike = { type PluginKindLike = string | readonly string[] | undefined; -export function toEnableStateResult( - state: TState, -): { enabled: boolean; reason?: string } { +export function toEnableStateResult(state: EnableStateLike): { enabled: boolean; reason?: string } { return state.enabled ? { enabled: true } : { enabled: false, reason: state.reason }; } -export function resolveEnableStateResult( +export function resolveEnableStateResult( params: TParams, - resolveState: (params: TParams) => TState, + resolveState: (params: TParams) => EnableStateLike, ): { enabled: boolean; reason?: string } { return toEnableStateResult(resolveState(params)); } -export function resolveEnableStateShared< - TParams extends EnableStateParamsLike, - TState extends EnableStateLike, ->( +export function resolveEnableStateShared( params: TParams, - resolveState: (params: TParams) => TState, + resolveState: (params: TParams) => EnableStateLike, ): { enabled: boolean; reason?: string } { return resolveEnableStateResult(params, resolveState); } diff --git a/src/plugins/contracts/extension-package-project-boundaries.test.ts b/src/plugins/contracts/extension-package-project-boundaries.test.ts index acf5662d894..b69a01a02e4 100644 --- a/src/plugins/contracts/extension-package-project-boundaries.test.ts +++ b/src/plugins/contracts/extension-package-project-boundaries.test.ts @@ -38,6 +38,7 @@ type PackageJson = { devDependencies?: Record; }; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe JSON file shape. function readJsonFile(relativePath: string): T { return JSON.parse(readFileSync(resolve(REPO_ROOT, relativePath), "utf8")) as T; } diff --git a/src/plugins/hooks.ts b/src/plugins/hooks.ts index 2389ab30fc7..3bb27a21d2d 100644 --- a/src/plugins/hooks.ts +++ b/src/plugins/hooks.ts @@ -455,6 +455,7 @@ export function createHookRunner( async function runClaimingHookForPluginOutcome< K extends PluginHookName, + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Targeted hook outcomes preserve caller-specific handled result types. TResult extends { handled: boolean }, >( hookName: K, diff --git a/src/plugins/lazy-service-module.ts b/src/plugins/lazy-service-module.ts index c63b03d934d..3fa7e11dc28 100644 --- a/src/plugins/lazy-service-module.ts +++ b/src/plugins/lazy-service-module.ts @@ -6,6 +6,7 @@ export type LazyPluginServiceHandle = { stop: () => Promise; }; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic service exports are typed by the caller. function resolveExport(mod: LazyServiceModule, names: string[]): T | null { for (const name of names) { const value = mod[name]; diff --git a/src/plugins/public-surface-loader.ts b/src/plugins/public-surface-loader.ts index 34c8a23f87c..2e1029e71c3 100644 --- a/src/plugins/public-surface-loader.ts +++ b/src/plugins/public-surface-loader.ts @@ -141,6 +141,7 @@ function getSharedBundledPublicSurfaceJiti(modulePath: string, tryNative: boolea }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic public artifact loaders use caller-supplied module surface types. export function loadBundledPluginPublicArtifactModuleSync(params: { dirName: string; artifactBasename: string; diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index b244473b4f2..1a5f30fa352 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -654,14 +654,11 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { }); }; - const registerUniqueProviderLike = < - T extends { id: string }, - R extends PluginOwnedProviderRegistration, - >(params: { + const registerUniqueProviderLike = (params: { record: PluginRecord; provider: T; kindLabel: string; - registrations: R[]; + registrations: Array>; ownedIds: string[]; }) => { const id = params.provider.id.trim(); @@ -694,7 +691,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { provider: params.provider, source: record.source, rootDir: record.rootDir, - } as R); + }); }; const registerSpeechProvider = (record: PluginRecord, provider: SpeechProviderPlugin) => { diff --git a/src/plugins/runtime/runtime-cache.ts b/src/plugins/runtime/runtime-cache.ts index 20a4a016411..6e20d8674c4 100644 --- a/src/plugins/runtime/runtime-cache.ts +++ b/src/plugins/runtime/runtime-cache.ts @@ -1,8 +1,4 @@ -export function defineCachedValue( - target: T, - key: K, - create: () => unknown, -): void { +export function defineCachedValue(target: object, key: PropertyKey, create: () => unknown): void { let cached: unknown; let ready = false; Object.defineProperty(target, key, { diff --git a/src/plugins/runtime/runtime-channel.ts b/src/plugins/runtime/runtime-channel.ts index 1b81aea4906..1e3131959e0 100644 --- a/src/plugins/runtime/runtime-channel.ts +++ b/src/plugins/runtime/runtime-channel.ts @@ -314,6 +314,7 @@ export function createRuntimeChannel(): PluginRuntime["channel"] { }); return { dispose }; }, + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Runtime context values are caller-typed by key. get: (params: PluginRuntimeChannelContextKey) => { const normalized = normalizeRuntimeContextKey(params); if (!normalized) { diff --git a/src/plugins/runtime/runtime-plugin-boundary.ts b/src/plugins/runtime/runtime-plugin-boundary.ts index 97ec784547c..cf6aa3c88e6 100644 --- a/src/plugins/runtime/runtime-plugin-boundary.ts +++ b/src/plugins/runtime/runtime-plugin-boundary.ts @@ -127,6 +127,7 @@ export function getPluginBoundaryJiti(modulePath: string, loaders: PluginJitiLoa }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic plugin boundary loaders use caller-supplied module types. export function loadPluginBoundaryModuleWithJiti( modulePath: string, loaders: PluginJitiLoaderCache, @@ -134,6 +135,7 @@ export function loadPluginBoundaryModuleWithJiti( return getPluginBoundaryJiti(modulePath, loaders)(modulePath) as TModule; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic plugin boundary loaders use caller-supplied module types. export function createCachedPluginBoundaryModuleLoader( params: CachedPluginBoundaryLoaderParams, ): () => TModule | null { diff --git a/src/plugins/runtime/types-channel.ts b/src/plugins/runtime/types-channel.ts index 596df3684d7..62cb9b7d23a 100644 --- a/src/plugins/runtime/types-channel.ts +++ b/src/plugins/runtime/types-channel.ts @@ -60,6 +60,7 @@ export type PluginRuntimeChannelContextRegistry = { abortSignal?: AbortSignal; }, ) => { dispose: () => void }; + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Runtime context values are caller-typed by key. get: (params: PluginRuntimeChannelContextKey) => T | undefined; watch: (params: { channelId?: string; diff --git a/src/plugins/web-provider-resolution-shared.ts b/src/plugins/web-provider-resolution-shared.ts index f1643eb3531..e570403c43b 100644 --- a/src/plugins/web-provider-resolution-shared.ts +++ b/src/plugins/web-provider-resolution-shared.ts @@ -164,11 +164,8 @@ export function buildWebProviderSnapshotCacheKey(params: { }); } -export function mapRegistryProviders< - TProvider extends { id: string }, - TEntry extends { pluginId: string; provider: TProvider }, ->(params: { - entries: readonly TEntry[]; +export function mapRegistryProviders(params: { + entries: readonly { pluginId: string; provider: TProvider }[]; onlyPluginIds?: readonly string[]; sortProviders: ( providers: Array, diff --git a/src/secrets/runtime-web-tools.shared.ts b/src/secrets/runtime-web-tools.shared.ts index 783a716387d..779acf2698c 100644 --- a/src/secrets/runtime-web-tools.shared.ts +++ b/src/secrets/runtime-web-tools.shared.ts @@ -97,9 +97,9 @@ export function ensureObject( return next; } -export function normalizeKnownProvider( +export function normalizeKnownProvider( value: unknown, - providers: TProvider[], + providers: Array<{ id: string }>, ): string | undefined { const normalized = normalizeOptionalLowercaseString(value); if (!normalized) { diff --git a/src/tasks/task-flow-registry.store.sqlite.ts b/src/tasks/task-flow-registry.store.sqlite.ts index 2edd0b81b32..ea901cd804a 100644 --- a/src/tasks/task-flow-registry.store.sqlite.ts +++ b/src/tasks/task-flow-registry.store.sqlite.ts @@ -60,6 +60,7 @@ function serializeJson(value: unknown): string | null { return value === undefined ? null : JSON.stringify(value); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Persisted JSON columns are typed by the receiving field. function parseJsonValue(raw: string | null): T | undefined { if (!raw?.trim()) { return undefined; diff --git a/src/tasks/task-registry.store.sqlite.ts b/src/tasks/task-registry.store.sqlite.ts index 9cfb40b9f19..c15f34d5879 100644 --- a/src/tasks/task-registry.store.sqlite.ts +++ b/src/tasks/task-registry.store.sqlite.ts @@ -78,6 +78,7 @@ function serializeJson(value: unknown): string | null { return value == null ? null : JSON.stringify(value); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Persisted JSON columns are typed by the receiving field. function parseJsonValue(raw: string | null): T | undefined { if (!raw?.trim()) { return undefined; diff --git a/src/test-utils/bundled-plugin-public-surface.ts b/src/test-utils/bundled-plugin-public-surface.ts index 471a6dcf194..1e9543435d9 100644 --- a/src/test-utils/bundled-plugin-public-surface.ts +++ b/src/test-utils/bundled-plugin-public-surface.ts @@ -102,6 +102,7 @@ function resolveWorkspacePackageDir(packageName: string): string { throw new Error(`Unknown workspace package: ${packageName}`); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test loaders use caller-supplied module surface types. export function loadBundledPluginPublicSurfaceSync(params: { pluginId: string; artifactBasename: string; @@ -113,6 +114,7 @@ export function loadBundledPluginPublicSurfaceSync(params: { }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test loaders use caller-supplied module surface types. export function loadBundledPluginApiSync(pluginId: string): T { return loadBundledPluginPublicSurfaceSync({ pluginId, @@ -120,6 +122,7 @@ export function loadBundledPluginApiSync(pluginId: string): T }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test loaders use caller-supplied module surface types. export function loadBundledPluginContractApiSync(pluginId: string): T { return loadBundledPluginPublicSurfaceSync({ pluginId, @@ -127,6 +130,7 @@ export function loadBundledPluginContractApiSync(pluginId: str }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test loaders use caller-supplied module surface types. export function loadBundledPluginRuntimeApiSync(pluginId: string): T { return loadBundledPluginPublicSurfaceSync({ pluginId, @@ -134,6 +138,7 @@ export function loadBundledPluginRuntimeApiSync(pluginId: stri }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test loaders use caller-supplied module surface types. export function loadBundledPluginTestApiSync(pluginId: string): T { return loadBundledPluginPublicSurfaceSync({ pluginId, diff --git a/src/utils.ts b/src/utils.ts index ca6206b3756..521e9229fc4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -46,6 +46,7 @@ export function escapeRegExp(value: string): string { /** * Safely parse JSON, returning null on error instead of throwing. */ +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- JSON parsing helper lets callers ascribe the expected payload type. export function safeParseJson(raw: string): T | null { try { return JSON.parse(raw) as T; diff --git a/src/web-fetch/runtime.ts b/src/web-fetch/runtime.ts index 500bee087a1..02056669308 100644 --- a/src/web-fetch/runtime.ts +++ b/src/web-fetch/runtime.ts @@ -42,7 +42,7 @@ export function resolveWebFetchEnabled(params: { } function resolveFetchConfig(config: OpenClawConfig | undefined): WebFetchConfig | undefined { - return resolveWebProviderConfig<"fetch", NonNullable>(config, "fetch"); + return resolveWebProviderConfig(config, "fetch") as NonNullable | undefined; } function hasEntryCredential( @@ -141,10 +141,9 @@ export function resolveWebFetchProviderId(params: { export function resolveWebFetchDefinition( options?: ResolveWebFetchDefinitionParams, ): { provider: PluginWebFetchProviderEntry; definition: WebFetchProviderToolDefinition } | null { - const fetch = resolveWebProviderConfig<"fetch", NonNullable>( - options?.config, - "fetch", - ); + const fetch = resolveWebProviderConfig(options?.config, "fetch") as + | NonNullable + | undefined; const runtimeWebFetch = options?.runtimeWebFetch ?? getActiveRuntimeWebToolsMetadata()?.fetch; const providers = sortWebFetchProvidersForAutoDetect( resolvePluginWebFetchProviders({ diff --git a/src/web-search/runtime.ts b/src/web-search/runtime.ts index f9ab0109bf2..8f0f4da758f 100644 --- a/src/web-search/runtime.ts +++ b/src/web-search/runtime.ts @@ -38,7 +38,7 @@ export type { } from "./runtime-types.js"; function resolveSearchConfig(cfg?: OpenClawConfig): WebSearchConfig { - return resolveWebProviderConfig<"search", NonNullable>(cfg, "search"); + return resolveWebProviderConfig(cfg, "search") as NonNullable | undefined; } export function resolveWebSearchEnabled(params: { diff --git a/src/web/provider-runtime-shared.ts b/src/web/provider-runtime-shared.ts index a413c345bb0..e5c9b034427 100644 --- a/src/web/provider-runtime-shared.ts +++ b/src/web/provider-runtime-shared.ts @@ -12,10 +12,10 @@ type ProviderWithCredential = { requiresCredential?: boolean; }; -export function resolveWebProviderConfig< - TKind extends "search" | "fetch", - TConfig extends Record, ->(cfg: OpenClawConfig | undefined, kind: TKind): TConfig | undefined { +export function resolveWebProviderConfig( + cfg: OpenClawConfig | undefined, + kind: "search" | "fetch", +): Record | undefined { const webConfig = cfg?.tools?.web; if (!webConfig || typeof webConfig !== "object") { return undefined; @@ -24,7 +24,7 @@ export function resolveWebProviderConfig< if (!toolConfig || typeof toolConfig !== "object") { return undefined; } - return toolConfig as TConfig; + return toolConfig as Record; } export function readWebProviderEnvValue( diff --git a/test/helpers/node-builtin-mocks.ts b/test/helpers/node-builtin-mocks.ts index 661b50a1929..817c918dd9c 100644 --- a/test/helpers/node-builtin-mocks.ts +++ b/test/helpers/node-builtin-mocks.ts @@ -9,8 +9,8 @@ function resolveMockOverrides( return typeof factory === "function" ? factory(actual) : factory; } -function resolveDefaultBase(actual: TModule): Record { - const defaultExport = (actual as TModule & { default?: unknown }).default; +function resolveDefaultBase(actual: object): Record { + const defaultExport = (actual as { default?: unknown }).default; if (defaultExport && typeof defaultExport === "object") { return defaultExport as Record; } diff --git a/test/helpers/plugins/package-manifest-contract.ts b/test/helpers/plugins/package-manifest-contract.ts index dc7663731ef..3687ba2f394 100644 --- a/test/helpers/plugins/package-manifest-contract.ts +++ b/test/helpers/plugins/package-manifest-contract.ts @@ -22,6 +22,7 @@ type PackageManifestContractParams = { minHostVersionBaseline?: string; }; +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe package manifest shape. function readJson(relativePath: string): T { const absolutePath = path.resolve(process.cwd(), relativePath); return JSON.parse(fs.readFileSync(absolutePath, "utf8")) as T; @@ -34,8 +35,8 @@ export function describePackageManifestContract(params: PackageManifestContractP if (params.pluginLocalRuntimeDeps?.length) { for (const dependencyName of params.pluginLocalRuntimeDeps) { it(`keeps ${dependencyName} plugin-local`, () => { - const rootManifest = readJson("package.json"); - const pluginManifest = readJson(packagePath); + const rootManifest = readJson("package.json") as PackageManifest; + const pluginManifest = readJson(packagePath) as PackageManifest; const pluginSpec = pluginManifest.dependencies?.[dependencyName] ?? pluginManifest.optionalDependencies?.[dependencyName]; diff --git a/test/helpers/plugins/runtime-env.ts b/test/helpers/plugins/runtime-env.ts index ec59326b588..cb993f567be 100644 --- a/test/helpers/plugins/runtime-env.ts +++ b/test/helpers/plugins/runtime-env.ts @@ -16,6 +16,7 @@ export function createRuntimeEnv(options?: { throwOnExit?: boolean }): OutputRun }; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets plugin suites ascribe runtime extension shape. export function createTypedRuntimeEnv(options?: { throwOnExit?: boolean }): TRuntime { return createRuntimeEnv(options) as TRuntime; } @@ -24,6 +25,7 @@ export function createNonExitingRuntimeEnv(): OutputRuntimeEnv { return createRuntimeEnv({ throwOnExit: false }); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets plugin suites ascribe runtime extension shape. export function createNonExitingTypedRuntimeEnv(): TRuntime { return createTypedRuntimeEnv({ throwOnExit: false }); } diff --git a/test/helpers/plugins/setup-wizard.ts b/test/helpers/plugins/setup-wizard.ts index f30cc211af8..095b949b851 100644 --- a/test/helpers/plugins/setup-wizard.ts +++ b/test/helpers/plugins/setup-wizard.ts @@ -151,6 +151,7 @@ export function createSetupWizardAdapter(params: SetupWizardAdapterParams) { return buildChannelSetupWizardAdapterFromSetupWizard(params); } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper preserves plugin-specific setup wizard surface type. export function createPluginSetupWizardAdapter( plugin: TPlugin, ) { @@ -161,12 +162,14 @@ export function createPluginSetupWizardAdapter( plugin: TPlugin, ) { return createPluginSetupWizardAdapter(plugin).configure; } +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper preserves plugin-specific setup wizard surface type. export function createPluginSetupWizardStatus( plugin: TPlugin, ) { diff --git a/test/helpers/plugins/subagent-hooks.ts b/test/helpers/plugins/subagent-hooks.ts index 2cd80fc5a35..b031a4e012f 100644 --- a/test/helpers/plugins/subagent-hooks.ts +++ b/test/helpers/plugins/subagent-hooks.ts @@ -1,3 +1,4 @@ +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper preserves plugin-specific hook API type. export function registerHookHandlersForTest(params: { config: Record; register: (api: TApi) => void; diff --git a/test/scripts/oxlint-config.test.ts b/test/scripts/oxlint-config.test.ts index 25bfcc47bdd..31625fbdb0f 100644 --- a/test/scripts/oxlint-config.test.ts +++ b/test/scripts/oxlint-config.test.ts @@ -10,8 +10,8 @@ type OxlintTsconfig = { exclude?: string[]; }; -function readJson(path: string): T { - return JSON.parse(fs.readFileSync(path, "utf8")) as T; +function readJson(path: string): unknown { + return JSON.parse(fs.readFileSync(path, "utf8")) as unknown; } describe("oxlint config", () => {