diff --git a/eslint.config.js b/eslint.config.js index 1d688139ca..93c1c6dff3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -80,6 +80,11 @@ export default tseslint.config( }, }, languageOptions: { + parser: tseslint.parser, + parserOptions: { + projectService: true, + tsconfigRootDir: projectRoot, + }, globals: { ...globals.node, ...globals.es2021, @@ -117,6 +122,8 @@ export default tseslint.config( caughtErrorsIgnorePattern: '^_', }, ], + // Prevent async errors from bypassing catch handlers + '@typescript-eslint/return-await': ['error', 'in-try-catch'], 'import/no-internal-modules': [ 'error', { diff --git a/packages/a2a-server/src/agent/executor.ts b/packages/a2a-server/src/agent/executor.ts index 1e3afd6e81..408d3bfe72 100644 --- a/packages/a2a-server/src/agent/executor.ts +++ b/packages/a2a-server/src/agent/executor.ts @@ -99,11 +99,7 @@ export class CoderAgentExecutor implements AgentExecutor { loadEnvironment(); // Will override any global env with workspace envs const settings = loadSettings(workspaceRoot); const extensions = loadExtensions(workspaceRoot); - return await loadConfig( - settings, - new SimpleExtensionLoader(extensions), - taskId, - ); + return loadConfig(settings, new SimpleExtensionLoader(extensions), taskId); } /** diff --git a/packages/cli/src/commands/mcp/list.ts b/packages/cli/src/commands/mcp/list.ts index 793a017eab..4fbdf68fc2 100644 --- a/packages/cli/src/commands/mcp/list.ts +++ b/packages/cli/src/commands/mcp/list.ts @@ -88,7 +88,7 @@ async function getServerStatus( server: MCPServerConfig, ): Promise { // Test all server types by attempting actual connection - return await testMCPConnection(serverName, server); + return testMCPConnection(serverName, server); } export async function listMcpServers(): Promise { diff --git a/packages/cli/src/config/extension.test.ts b/packages/cli/src/config/extension.test.ts index 62653481bd..a30065f612 100644 --- a/packages/cli/src/config/extension.test.ts +++ b/packages/cli/src/config/extension.test.ts @@ -1796,12 +1796,8 @@ This extension will run the following MCP servers: }); it('should throw an error if you request system scope', async () => { - await expect( - async () => - await extensionManager.disableExtension( - 'my-extension', - SettingScope.System, - ), + await expect(async () => + extensionManager.disableExtension('my-extension', SettingScope.System), ).rejects.toThrow('System and SystemDefaults scopes are not supported.'); }); diff --git a/packages/cli/src/config/extensions/consent.ts b/packages/cli/src/config/extensions/consent.ts index b6db1f647b..ee040cbdee 100644 --- a/packages/cli/src/config/extensions/consent.ts +++ b/packages/cli/src/config/extensions/consent.ts @@ -45,7 +45,7 @@ export async function requestConsentInteractive( consentDescription: string, addExtensionUpdateConfirmationRequest: (value: ConfirmationRequest) => void, ): Promise { - return await promptForConsentInteractive( + return promptForConsentInteractive( consentDescription + '\n\nDo you want to continue?', addExtensionUpdateConfirmationRequest, ); @@ -89,7 +89,7 @@ async function promptForConsentInteractive( prompt: string, addExtensionUpdateConfirmationRequest: (value: ConfirmationRequest) => void, ): Promise { - return await new Promise((resolve) => { + return new Promise((resolve) => { addExtensionUpdateConfirmationRequest({ prompt, onConfirm: (resolvedConfirmed) => { diff --git a/packages/cli/src/config/extensions/github.ts b/packages/cli/src/config/extensions/github.ts index 502b610cea..f2a6bb677f 100644 --- a/packages/cli/src/config/extensions/github.ts +++ b/packages/cli/src/config/extensions/github.ts @@ -138,7 +138,7 @@ export async function fetchReleaseFromGithub( allowPreRelease?: boolean, ): Promise { if (ref) { - return await fetchJson( + return fetchJson( `https://api.github.com/repos/${owner}/${repo}/releases/tags/${ref}`, ); } diff --git a/packages/cli/src/config/extensions/storage.ts b/packages/cli/src/config/extensions/storage.ts index 583bdd044b..8682e578f6 100644 --- a/packages/cli/src/config/extensions/storage.ts +++ b/packages/cli/src/config/extensions/storage.ts @@ -40,8 +40,6 @@ export class ExtensionStorage { } static async createTmpDir(): Promise { - return await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'gemini-extension'), - ); + return fs.promises.mkdtemp(path.join(os.tmpdir(), 'gemini-extension')); } } diff --git a/packages/cli/src/utils/handleAutoUpdate.test.ts b/packages/cli/src/utils/handleAutoUpdate.test.ts index 8fd3958cf3..7d6b7c612a 100644 --- a/packages/cli/src/utils/handleAutoUpdate.test.ts +++ b/packages/cli/src/utils/handleAutoUpdate.test.ts @@ -22,10 +22,8 @@ vi.mock('./installationInfo.js', async () => { }; }); -vi.mock( - './updateEventEmitter.js', - async (importOriginal) => - await importOriginal(), +vi.mock('./updateEventEmitter.js', async (importOriginal) => + importOriginal(), ); interface MockChildProcess extends EventEmitter { diff --git a/packages/cli/src/utils/sandbox.ts b/packages/cli/src/utils/sandbox.ts index 45b7353c2f..8e5b7e0de2 100644 --- a/packages/cli/src/utils/sandbox.ts +++ b/packages/cli/src/utils/sandbox.ts @@ -191,7 +191,7 @@ export async function start_sandbox( sandboxProcess = spawn(config.command, args, { stdio: 'inherit', }); - return new Promise((resolve, reject) => { + return await new Promise((resolve, reject) => { sandboxProcess?.on('error', reject); sandboxProcess?.on('close', (code) => { process.stdin.resume(); @@ -666,7 +666,7 @@ export async function start_sandbox( stdio: 'inherit', }); - return new Promise((resolve, reject) => { + return await new Promise((resolve, reject) => { sandboxProcess.on('error', (err) => { coreEvents.emitFeedback('error', 'Sandbox process error', err); reject(err); diff --git a/packages/cli/src/zed-integration/acp.ts b/packages/cli/src/zed-integration/acp.ts index f8a0c8eace..16fe12403b 100644 --- a/packages/cli/src/zed-integration/acp.ts +++ b/packages/cli/src/zed-integration/acp.ts @@ -68,7 +68,7 @@ export class AgentSideConnection implements Client { * Streams new content to the client including text, tool calls, etc. */ async sessionUpdate(params: schema.SessionNotification): Promise { - return await this.#connection.sendNotification( + return this.#connection.sendNotification( schema.CLIENT_METHODS.session_update, params, ); @@ -83,7 +83,7 @@ export class AgentSideConnection implements Client { async requestPermission( params: schema.RequestPermissionRequest, ): Promise { - return await this.#connection.sendRequest( + return this.#connection.sendRequest( schema.CLIENT_METHODS.session_request_permission, params, ); @@ -92,7 +92,7 @@ export class AgentSideConnection implements Client { async readTextFile( params: schema.ReadTextFileRequest, ): Promise { - return await this.#connection.sendRequest( + return this.#connection.sendRequest( schema.CLIENT_METHODS.fs_read_text_file, params, ); @@ -101,7 +101,7 @@ export class AgentSideConnection implements Client { async writeTextFile( params: schema.WriteTextFileRequest, ): Promise { - return await this.#connection.sendRequest( + return this.#connection.sendRequest( schema.CLIENT_METHODS.fs_write_text_file, params, ); diff --git a/packages/core/src/code_assist/experiments/client_metadata.ts b/packages/core/src/code_assist/experiments/client_metadata.ts index c5450e4f40..5d76cb742e 100644 --- a/packages/core/src/code_assist/experiments/client_metadata.ts +++ b/packages/core/src/code_assist/experiments/client_metadata.ts @@ -52,5 +52,5 @@ export async function getClientMetadata(): Promise { updateChannel: await getReleaseChannel(__dirname), }))(); } - return await clientMetadataPromise; + return clientMetadataPromise; } diff --git a/packages/core/src/code_assist/experiments/experiments.ts b/packages/core/src/code_assist/experiments/experiments.ts index 9c8d42188f..90eae36679 100644 --- a/packages/core/src/code_assist/experiments/experiments.ts +++ b/packages/core/src/code_assist/experiments/experiments.ts @@ -24,7 +24,7 @@ export async function getExperiments( server: CodeAssistServer, ): Promise { if (experimentsPromise) { - return await experimentsPromise; + return experimentsPromise; } experimentsPromise = (async () => { @@ -32,7 +32,7 @@ export async function getExperiments( const response = await server.listExperiments(metadata); return parseExperiments(response); })(); - return await experimentsPromise; + return experimentsPromise; } function parseExperiments(response: ListExperimentsResponse): Experiments { diff --git a/packages/core/src/code_assist/oauth2.ts b/packages/core/src/code_assist/oauth2.ts index b0a4cb4baa..bb8ad37715 100644 --- a/packages/core/src/code_assist/oauth2.ts +++ b/packages/core/src/code_assist/oauth2.ts @@ -546,7 +546,7 @@ async function fetchCachedCredentials(): Promise< > { const useEncryptedStorage = getUseEncryptedStorageFlag(); if (useEncryptedStorage) { - return await OAuthCredentialStorage.loadCredentials(); + return OAuthCredentialStorage.loadCredentials(); } const pathsToTry = [ diff --git a/packages/core/src/code_assist/server.ts b/packages/core/src/code_assist/server.ts index 9cb2a8ce0f..f345ff0fcc 100644 --- a/packages/core/src/code_assist/server.ts +++ b/packages/core/src/code_assist/server.ts @@ -102,10 +102,7 @@ export class CodeAssistServer implements ContentGenerator { async onboardUser( req: OnboardUserRequest, ): Promise { - return await this.requestPost( - 'onboardUser', - req, - ); + return this.requestPost('onboardUser', req); } async loadCodeAssist( @@ -128,7 +125,7 @@ export class CodeAssistServer implements ContentGenerator { } async getCodeAssistGlobalUserSetting(): Promise { - return await this.requestGet( + return this.requestGet( 'getCodeAssistGlobalUserSetting', ); } @@ -136,7 +133,7 @@ export class CodeAssistServer implements ContentGenerator { async setCodeAssistGlobalUserSetting( req: SetCodeAssistGlobalUserSettingRequest, ): Promise { - return await this.requestPost( + return this.requestPost( 'setCodeAssistGlobalUserSetting', req, ); @@ -167,16 +164,13 @@ export class CodeAssistServer implements ContentGenerator { project: projectId, metadata: { ...metadata, duetProject: projectId }, }; - return await this.requestPost( - 'listExperiments', - req, - ); + return this.requestPost('listExperiments', req); } async retrieveUserQuota( req: RetrieveUserQuotaRequest, ): Promise { - return await this.requestPost( + return this.requestPost( 'retrieveUserQuota', req, ); diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index df42b1694e..43a8a5ae00 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -693,7 +693,7 @@ export class GeminiClient { error?: unknown, ) => // Pass the captured model to the centralized handler. - await handleFallback(this.config, currentAttemptModel, authType, error); + handleFallback(this.config, currentAttemptModel, authType, error); const result = await retryWithBackoff(apiCall, { onPersistent429: onPersistent429Callback, diff --git a/packages/core/src/core/geminiChat.test.ts b/packages/core/src/core/geminiChat.test.ts index ea5ef27806..18b291bfbf 100644 --- a/packages/core/src/core/geminiChat.test.ts +++ b/packages/core/src/core/geminiChat.test.ts @@ -1886,7 +1886,7 @@ describe('GeminiChat', () => { error, ); if (shouldRetry) { - return await apiCall(); + return apiCall(); } } throw error; // Stop if callback returns false/null or doesn't exist diff --git a/packages/core/src/core/geminiChat.ts b/packages/core/src/core/geminiChat.ts index 308a67d99a..bd8edce3cd 100644 --- a/packages/core/src/core/geminiChat.ts +++ b/packages/core/src/core/geminiChat.ts @@ -535,7 +535,7 @@ export class GeminiChat { const onPersistent429Callback = async ( authType?: string, error?: unknown, - ) => await handleFallback(this.config, effectiveModel, authType, error); + ) => handleFallback(this.config, effectiveModel, authType, error); const streamResponse = await retryWithBackoff(apiCall, { onPersistent429: onPersistent429Callback, diff --git a/packages/core/src/hooks/hookEventHandler.ts b/packages/core/src/hooks/hookEventHandler.ts index 67b61e3588..64a78c936d 100644 --- a/packages/core/src/hooks/hookEventHandler.ts +++ b/packages/core/src/hooks/hookEventHandler.ts @@ -268,7 +268,7 @@ export class HookEventHandler { }; const context: HookEventContext = { toolName }; - return await this.executeHooks(HookEventName.BeforeTool, input, context); + return this.executeHooks(HookEventName.BeforeTool, input, context); } /** @@ -288,7 +288,7 @@ export class HookEventHandler { }; const context: HookEventContext = { toolName }; - return await this.executeHooks(HookEventName.AfterTool, input, context); + return this.executeHooks(HookEventName.AfterTool, input, context); } /** @@ -301,7 +301,7 @@ export class HookEventHandler { prompt, }; - return await this.executeHooks(HookEventName.BeforeAgent, input); + return this.executeHooks(HookEventName.BeforeAgent, input); } /** @@ -319,7 +319,7 @@ export class HookEventHandler { details, }; - return await this.executeHooks(HookEventName.Notification, input); + return this.executeHooks(HookEventName.Notification, input); } /** @@ -338,7 +338,7 @@ export class HookEventHandler { stop_hook_active: stopHookActive, }; - return await this.executeHooks(HookEventName.AfterAgent, input); + return this.executeHooks(HookEventName.AfterAgent, input); } /** @@ -353,7 +353,7 @@ export class HookEventHandler { }; const context: HookEventContext = { trigger: source }; - return await this.executeHooks(HookEventName.SessionStart, input, context); + return this.executeHooks(HookEventName.SessionStart, input, context); } /** @@ -368,7 +368,7 @@ export class HookEventHandler { }; const context: HookEventContext = { trigger: reason }; - return await this.executeHooks(HookEventName.SessionEnd, input, context); + return this.executeHooks(HookEventName.SessionEnd, input, context); } /** @@ -383,7 +383,7 @@ export class HookEventHandler { }; const context: HookEventContext = { trigger }; - return await this.executeHooks(HookEventName.PreCompress, input, context); + return this.executeHooks(HookEventName.PreCompress, input, context); } /** @@ -398,7 +398,7 @@ export class HookEventHandler { llm_request: defaultHookTranslator.toHookLLMRequest(llmRequest), }; - return await this.executeHooks(HookEventName.BeforeModel, input); + return this.executeHooks(HookEventName.BeforeModel, input); } /** @@ -415,7 +415,7 @@ export class HookEventHandler { llm_response: defaultHookTranslator.toHookLLMResponse(llmResponse), }; - return await this.executeHooks(HookEventName.AfterModel, input); + return this.executeHooks(HookEventName.AfterModel, input); } /** @@ -430,7 +430,7 @@ export class HookEventHandler { llm_request: defaultHookTranslator.toHookLLMRequest(llmRequest), }; - return await this.executeHooks(HookEventName.BeforeToolSelection, input); + return this.executeHooks(HookEventName.BeforeToolSelection, input); } /** diff --git a/packages/core/src/hooks/hookRunner.ts b/packages/core/src/hooks/hookRunner.ts index b64438c432..7c9dfb01b7 100644 --- a/packages/core/src/hooks/hookRunner.ts +++ b/packages/core/src/hooks/hookRunner.ts @@ -81,7 +81,7 @@ export class HookRunner { this.executeHook(config, eventName, input), ); - return await Promise.all(promises); + return Promise.all(promises); } /** diff --git a/packages/core/src/mcp/token-storage/hybrid-token-storage.ts b/packages/core/src/mcp/token-storage/hybrid-token-storage.ts index 70edac07cd..d5e798cab4 100644 --- a/packages/core/src/mcp/token-storage/hybrid-token-storage.ts +++ b/packages/core/src/mcp/token-storage/hybrid-token-storage.ts @@ -57,7 +57,7 @@ export class HybridTokenStorage extends BaseTokenStorage { } // Wait for initialization to complete - return await this.storageInitPromise; + return this.storageInitPromise; } async getCredentials(serverName: string): Promise { diff --git a/packages/core/src/services/loopDetectionService.ts b/packages/core/src/services/loopDetectionService.ts index 081a8bb457..da4974f64d 100644 --- a/packages/core/src/services/loopDetectionService.ts +++ b/packages/core/src/services/loopDetectionService.ts @@ -192,7 +192,7 @@ export class LoopDetectionService { this.turnsInCurrentPrompt - this.lastCheckTurn >= this.llmCheckInterval ) { this.lastCheckTurn = this.turnsInCurrentPrompt; - return await this.checkForLoopWithLLM(signal); + return this.checkForLoopWithLLM(signal); } return false; diff --git a/packages/core/src/telemetry/trace.ts b/packages/core/src/telemetry/trace.ts index 6b4feda387..3c84a3b675 100644 --- a/packages/core/src/telemetry/trace.ts +++ b/packages/core/src/telemetry/trace.ts @@ -62,7 +62,7 @@ export async function runInDevTraceSpan( const { name: spanName, noAutoEnd, ...restOfSpanOpts } = opts; if (process.env['GEMINI_DEV_TRACING'] !== 'true') { // If GEMINI_DEV_TRACING env var not set, we do not trace. - return await fn({ + return fn({ metadata: { name: spanName, attributes: {}, @@ -74,66 +74,62 @@ export async function runInDevTraceSpan( } const tracer = trace.getTracer(TRACER_NAME, TRACER_VERSION); - return await tracer.startActiveSpan( - opts.name, - restOfSpanOpts, - async (span) => { - const meta: SpanMetadata = { - name: spanName, - attributes: {}, - }; - const endSpan = () => { - try { - if (meta.input !== undefined) { - span.setAttribute('input-json', safeJsonStringify(meta.input)); - } - if (meta.output !== undefined) { - span.setAttribute('output-json', safeJsonStringify(meta.output)); - } - for (const [key, value] of Object.entries(meta.attributes)) { - span.setAttribute(key, value as AttributeValue); - } - if (meta.error) { - span.setStatus({ - code: SpanStatusCode.ERROR, - message: getErrorMessage(meta.error), - }); - if (meta.error instanceof Error) { - span.recordException(meta.error); - } - } else { - span.setStatus({ code: SpanStatusCode.OK }); - } - } catch (e) { - // Log the error but don't rethrow, to ensure span.end() is called. - diag.error('Error setting span attributes in endSpan', e); + return tracer.startActiveSpan(opts.name, restOfSpanOpts, async (span) => { + const meta: SpanMetadata = { + name: spanName, + attributes: {}, + }; + const endSpan = () => { + try { + if (meta.input !== undefined) { + span.setAttribute('input-json', safeJsonStringify(meta.input)); + } + if (meta.output !== undefined) { + span.setAttribute('output-json', safeJsonStringify(meta.output)); + } + for (const [key, value] of Object.entries(meta.attributes)) { + span.setAttribute(key, value as AttributeValue); + } + if (meta.error) { span.setStatus({ code: SpanStatusCode.ERROR, - message: `Error in endSpan: ${getErrorMessage(e)}`, + message: getErrorMessage(meta.error), }); - } finally { - span.end(); + if (meta.error instanceof Error) { + span.recordException(meta.error); + } + } else { + span.setStatus({ code: SpanStatusCode.OK }); } - }; - try { - return await fn({ metadata: meta, endSpan }); } catch (e) { - meta.error = e; - if (noAutoEnd) { - // For streaming operations, the delegated endSpan call will not be reached - // on an exception, so we must end the span here to prevent a leak. - endSpan(); - } - throw e; + // Log the error but don't rethrow, to ensure span.end() is called. + diag.error('Error setting span attributes in endSpan', e); + span.setStatus({ + code: SpanStatusCode.ERROR, + message: `Error in endSpan: ${getErrorMessage(e)}`, + }); } finally { - if (!noAutoEnd) { - // For non-streaming operations, this ensures the span is always closed, - // and if an error occurred, it will be recorded correctly by endSpan. - endSpan(); - } + span.end(); } - }, - ); + }; + try { + return await fn({ metadata: meta, endSpan }); + } catch (e) { + meta.error = e; + if (noAutoEnd) { + // For streaming operations, the delegated endSpan call will not be reached + // on an exception, so we must end the span here to prevent a leak. + endSpan(); + } + throw e; + } finally { + if (!noAutoEnd) { + // For non-streaming operations, this ensures the span is always closed, + // and if an error occurred, it will be recorded correctly by endSpan. + endSpan(); + } + } + }); } /** diff --git a/packages/core/src/tools/smart-edit.ts b/packages/core/src/tools/smart-edit.ts index 4d5fdce37f..86d412b407 100644 --- a/packages/core/src/tools/smart-edit.ts +++ b/packages/core/src/tools/smart-edit.ts @@ -966,7 +966,7 @@ A good instruction should concisely answer: getFilePath: (params: EditToolParams) => params.file_path, getCurrentContent: async (params: EditToolParams): Promise => { try { - return this.config + return await this.config .getFileSystemService() .readTextFile(params.file_path); } catch (err) { diff --git a/packages/core/src/tools/web-fetch.ts b/packages/core/src/tools/web-fetch.ts index 79676851c0..dbfb173079 100644 --- a/packages/core/src/tools/web-fetch.ts +++ b/packages/core/src/tools/web-fetch.ts @@ -307,7 +307,7 @@ ${textContent} this.config, new WebFetchFallbackAttemptEvent('primary_failed'), ); - return this.executeFallback(signal); + return await this.executeFallback(signal); } const sourceListFormatted: string[] = []; diff --git a/packages/core/src/utils/memoryDiscovery.ts b/packages/core/src/utils/memoryDiscovery.ts index 55b2354d9c..e91cfd2ff1 100644 --- a/packages/core/src/utils/memoryDiscovery.ts +++ b/packages/core/src/utils/memoryDiscovery.ts @@ -436,7 +436,7 @@ export async function loadEnvironmentMemory( `Loading environment memory for trusted root: ${resolvedRoot} (Stopping exactly here)`, ); } - return await findUpwardGeminiFiles(resolvedRoot, resolvedRoot, debugMode); + return findUpwardGeminiFiles(resolvedRoot, resolvedRoot, debugMode); }); const pathArrays = await Promise.all(traversalPromises);