diff --git a/.oxlintrc.json b/.oxlintrc.json index 6a86d7b0d..f6da274bf 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -37,6 +37,7 @@ "allow": ["URL", "URLSearchParams"] } ], + "typescript/no-unnecessary-type-parameters": "error", "jsx-a11y/interactive-supports-focus": "off", "unicorn/prefer-spread": "error" }, diff --git a/packages/cli/src/lib/alias.ts b/packages/cli/src/lib/alias.ts index 6312af8be..0b2c12f68 100644 --- a/packages/cli/src/lib/alias.ts +++ b/packages/cli/src/lib/alias.ts @@ -353,9 +353,9 @@ export type AliasMapResult = { * `project` slugs of a {@link ResolvedTarget} * @returns Alias map and DB entries */ -export function buildProjectAliasMap< - T extends { target: Pick }, ->(results: T[]): AliasMapResult { +export function buildProjectAliasMap( + results: readonly { target: Pick }[], +): AliasMapResult { const entries: Record = {}; const pairs = results.map((r) => ({ org: r.target.org, diff --git a/packages/cli/src/lib/api/infrastructure.ts b/packages/cli/src/lib/api/infrastructure.ts index 625cbdb7a..6dd8797a2 100644 --- a/packages/cli/src/lib/api/infrastructure.ts +++ b/packages/cli/src/lib/api/infrastructure.ts @@ -400,6 +400,7 @@ export function throwApiError( * @param context - Human-readable context for error messages * @returns The data from the successful response */ +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- callers name the app type for SDK data, which often differs from @sentry/api's generated types export function unwrapResult( result: Pick, context: string, diff --git a/packages/cli/src/lib/formatters/json.ts b/packages/cli/src/lib/formatters/json.ts index c30e9a959..20add4300 100644 --- a/packages/cli/src/lib/formatters/json.ts +++ b/packages/cli/src/lib/formatters/json.ts @@ -242,7 +242,7 @@ export function parseFieldsList(input: string): string[] { /** * Format data as pretty-printed JSON */ -export function formatJson(data: T): string { +export function formatJson(data: unknown): string { return JSON.stringify(data, null, 2); } @@ -257,7 +257,11 @@ export function formatJson(data: T): string { * @param data - Data to serialize * @param fields - Optional field paths to include (dot-notation supported) */ -export function writeJson(stream: Writer, data: T, fields?: string[]): void { +export function writeJson( + stream: Writer, + data: unknown, + fields?: string[], +): void { const output = fields && fields.length > 0 ? filterFields(data, fields) : data; stream.write(`${formatJson(output)}\n`); @@ -287,9 +291,9 @@ export function writeJson(stream: Writer, data: T, fields?: string[]): void { * // → { "data": [{ "id": "1", "title": "Bug" }, ...], "hasMore": true } * ``` */ -export function writeJsonList( +export function writeJsonList( stream: Writer, - items: T[], + items: readonly unknown[], options: { hasMore: boolean; nextCursor?: string | null; diff --git a/packages/cli/src/lib/positional-parse.ts b/packages/cli/src/lib/positional-parse.ts index 857efa172..2e6574035 100644 --- a/packages/cli/src/lib/positional-parse.ts +++ b/packages/cli/src/lib/positional-parse.ts @@ -33,6 +33,7 @@ */ import { ArgumentParseError } from "@stricli/core"; +import type { SentryContext } from "../context.js"; import { type CompletionTarget, withCompletionTarget, @@ -143,14 +144,14 @@ export type BoundArguments = BoundPositional; * @param options.resolve - Resolves the parsed value; gets the command * context and the raw arguments */ -export function boundArguments(options: { +export function boundArguments(options: { readonly placeholder: string; readonly brief: string; readonly kind?: CompletionTarget; readonly parse: (raw: readonly string[]) => T; readonly resolve: ( value: T, - context: C, + context: SentryContext, raw: readonly string[], ) => Promise; }): { @@ -187,7 +188,7 @@ export function boundArguments(options: { ); } return new BoundPositional(raw, parsed, (value: T) => - options.resolve(value, this as C, raw), + options.resolve(value, this as SentryContext, raw), ); }); return positional; diff --git a/packages/cli/src/lib/sdk-invoke.ts b/packages/cli/src/lib/sdk-invoke.ts index a3a312507..7f2db4840 100644 --- a/packages/cli/src/lib/sdk-invoke.ts +++ b/packages/cli/src/lib/sdk-invoke.ts @@ -268,28 +268,28 @@ function concatChunksToBytes(chunks: Array): Uint8Array { * Parse captured output: prefer zero-copy object, then JSON, then raw string. * @internal Exported for testing */ -export function parseOutput( +export function parseOutput( capturedResult: unknown, stdoutChunks: Array, -): T { +): unknown { if (capturedResult !== undefined) { - return capturedResult as T; + return capturedResult; } // Binary output (e.g. `sentry api` attachment downloads) must be returned // byte-faithfully. If any chunk is a Uint8Array, joining as strings would // stringify it to comma-separated decimals — return raw bytes instead. if (stdoutChunks.some((c) => c instanceof Uint8Array)) { - return concatChunksToBytes(stdoutChunks) as T; + return concatChunksToBytes(stdoutChunks); } const stdoutStr = stdoutChunks.join(""); if (!stdoutStr.trim()) { - return undefined as T; + return undefined; } // oxlint-disable-next-line sentry-cli/no-silent-catch -- grandfathered silent catch — see #1531; drain by adding log.debug()/log.warn() or re-throwing. try { - return JSON.parse(stdoutStr) as T; + return JSON.parse(stdoutStr); } catch { - return stdoutStr.trim() as T; + return stdoutStr.trim(); } } @@ -450,10 +450,10 @@ async function executeWithCapture( ); } - return parseOutput( + return parseOutput( captureCtx.getCapturedResult(), captureCtx.stdoutChunks, - ); + ) as T; }); }); } @@ -526,7 +526,7 @@ function executeWithStream( // dropped when the channel closes. No streaming-capable command emits // binary today, but this keeps the streaming path faithful to the // capture path (see parseOutput) if one ever does. - const trailing = parseOutput(undefined, captureCtx.stdoutChunks); + const trailing = parseOutput(undefined, captureCtx.stdoutChunks) as T; if (trailing !== undefined) { channel.push(trailing); } diff --git a/packages/mcp-cloudflare/src/server/oauth/helpers.ts b/packages/mcp-cloudflare/src/server/oauth/helpers.ts index fc578ae78..0262b42ec 100644 --- a/packages/mcp-cloudflare/src/server/oauth/helpers.ts +++ b/packages/mcp-cloudflare/src/server/oauth/helpers.ts @@ -489,9 +489,10 @@ function recordTokenExchangeOutcome( }); } -function buildSuccessfulTokenExchangeResult< - TProps extends Record, ->(props: TProps, accessTokenTTL: number): TokenExchangeCallbackResult { +function buildSuccessfulTokenExchangeResult( + props: Record, + accessTokenTTL: number, +): TokenExchangeCallbackResult { return { newProps: props, accessTokenTTL, diff --git a/packages/mcp-core/src/internal/agents/callEmbeddedAgent.ts b/packages/mcp-core/src/internal/agents/callEmbeddedAgent.ts index 53b77a708..3c58c1525 100644 --- a/packages/mcp-core/src/internal/agents/callEmbeddedAgent.ts +++ b/packages/mcp-core/src/internal/agents/callEmbeddedAgent.ts @@ -108,10 +108,7 @@ interface EmbeddedAgentResult { * - Errors are re-thrown for the calling agent to handle * - Each agent can implement its own error handling strategy */ -export async function callEmbeddedAgent< - TOutput, - TSchema extends z.ZodType, ->({ +export async function callEmbeddedAgent({ system, prompt, tools, @@ -121,7 +118,7 @@ export async function callEmbeddedAgent< system: string; prompt: string; tools: Record; - schema: TSchema; + schema: z.ZodType; /** Whether this step produced a result that permits a final response. */ isReadyToFinalize?: (step: StepResult>) => boolean; }): Promise> { diff --git a/packages/mcp-core/src/test-utils/dataset-search-tool.ts b/packages/mcp-core/src/test-utils/dataset-search-tool.ts index 4ec2ec7cd..41ed5b832 100644 --- a/packages/mcp-core/src/test-utils/dataset-search-tool.ts +++ b/packages/mcp-core/src/test-utils/dataset-search-tool.ts @@ -25,6 +25,7 @@ const params = { * `SEARCH_REPLAYS_STUB` for search_replays) from `./search-events-stub` * instead of "ok"; search-errors.test.ts shows how. */ +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- accepts any tool's handler params type export async function inspectDatasetSearchTool

(tool: { inputSchema: object; handler(params: P, context: ServerContext): Promise; diff --git a/packages/mcp-core/src/test-utils/structured-content.ts b/packages/mcp-core/src/test-utils/structured-content.ts index 02c5f23ea..b0fd24435 100644 --- a/packages/mcp-core/src/test-utils/structured-content.ts +++ b/packages/mcp-core/src/test-utils/structured-content.ts @@ -8,6 +8,7 @@ export function getTextContent(result: unknown): string { } /** Returns structuredContent after checking the result has an object payload. */ +// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- lets tests name the expected payload type export function getStructuredContent>( result: unknown, ): T { diff --git a/packages/mcp-core/src/tools/support/search-events/agent.ts b/packages/mcp-core/src/tools/support/search-events/agent.ts index 8c727cf14..4879bfe0c 100644 --- a/packages/mcp-core/src/tools/support/search-events/agent.ts +++ b/packages/mcp-core/src/tools/support/search-events/agent.ts @@ -228,10 +228,7 @@ export async function searchEventsAgent( options.environmentNames ?? (await fetchEnvironmentNames(options)); // Use callEmbeddedAgent to translate the query with tool call capture - return await callEmbeddedAgent< - z.output, - typeof searchEventsAgentOutputSchema - >({ + return await callEmbeddedAgent({ system: buildSystemPromptWithEnvironments(systemPrompt, environmentNames), prompt: options.query, tools: { diff --git a/packages/mcp-core/src/tools/support/search-events/structured.ts b/packages/mcp-core/src/tools/support/search-events/structured.ts index bcc44c084..ff1118f1b 100644 --- a/packages/mcp-core/src/tools/support/search-events/structured.ts +++ b/packages/mcp-core/src/tools/support/search-events/structured.ts @@ -335,6 +335,7 @@ function searchEventsOutputSchema< /** Output schema for the dataset search tool that searches `dataset`. */ export function buildSearchEventsOutputSchema< + // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- the inferred return type depends on TDataset TDataset extends StructuredSearchDataset, >(dataset: TDataset) { return searchEventsOutputSchema(z.object(STRUCTURED_DATASETS[dataset].links)); diff --git a/packages/mcp-core/src/tools/support/search-issue-events/agent.ts b/packages/mcp-core/src/tools/support/search-issue-events/agent.ts index 37991efcf..0e1ff39db 100644 --- a/packages/mcp-core/src/tools/support/search-issue-events/agent.ts +++ b/packages/mcp-core/src/tools/support/search-issue-events/agent.ts @@ -91,10 +91,7 @@ export async function searchIssueEventsAgent( }); // Use callEmbeddedAgent to translate the query with tool call capture - return await callEmbeddedAgent< - z.output, - typeof searchIssueEventsAgentOutputSchema - >({ + return await callEmbeddedAgent({ system: systemPrompt, prompt: options.query, tools: { diff --git a/packages/mcp-core/src/tools/support/search-issues/agent.ts b/packages/mcp-core/src/tools/support/search-issues/agent.ts index e2125c98a..150a5ce38 100644 --- a/packages/mcp-core/src/tools/support/search-issues/agent.ts +++ b/packages/mcp-core/src/tools/support/search-issues/agent.ts @@ -39,10 +39,7 @@ export async function searchIssuesAgent( }> { // Provider check happens in callEmbeddedAgent via getAgentProvider() // Create tools pre-bound with the provided API service and organization - return await callEmbeddedAgent< - z.output, - typeof searchIssuesAgentOutputSchema - >({ + return await callEmbeddedAgent({ system: systemPrompt, prompt: options.query, tools: { diff --git a/packages/mcp-core/src/transports/stdio.ts b/packages/mcp-core/src/transports/stdio.ts index 297f3387e..e2de1ca59 100644 --- a/packages/mcp-core/src/transports/stdio.ts +++ b/packages/mcp-core/src/transports/stdio.ts @@ -63,9 +63,9 @@ export type StdioConnection = { * Context is already captured in tool handler closures by `buildServer()`; * it is only read here for telemetry attributes. */ -export async function startStdio( +export async function startStdio( server: McpServer, - context: Context, + context: StdioServerContext, ): Promise { const transport = new StdioServerTransport(); await startNewTrace(async () => {