diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec049686..22c47006 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,12 +44,11 @@ jobs: # 5. Linting - name: Run linter run: npm run lint - continue-on-error: true # TODO: Remove this when we have fixed lint errors # 6. Type Checking - name: Run type check run: npm run typecheck # Or: tsc --noEmit - continue-on-error: true # TODO: Remove this when we have fixed type errors + continue-on-error: true # 7. Build # Optional if your tests run directly on TS files (e.g., using ts-jest, ts-node) diff --git a/packages/cli/src/gemini.ts b/packages/cli/src/gemini.ts index e080fd1b..b4db8189 100644 --- a/packages/cli/src/gemini.ts +++ b/packages/cli/src/gemini.ts @@ -1,6 +1,6 @@ import React from 'react'; import { render } from 'ink'; -import App from './ui/App.js'; +import { App } from './ui/App.js'; import { toolRegistry } from './tools/tool-registry.js'; import { LSTool } from './tools/ls.tool.js'; import { ReadFileTool } from './tools/read-file.tool.js'; diff --git a/packages/cli/src/tools/web-fetch.tool.ts b/packages/cli/src/tools/web-fetch.tool.ts index 4fc1e45e..8db7aad3 100644 --- a/packages/cli/src/tools/web-fetch.tool.ts +++ b/packages/cli/src/tools/web-fetch.tool.ts @@ -1,6 +1,7 @@ import { SchemaValidator } from '../utils/schemaValidator.js'; import { BaseTool, ToolResult } from './tools.js'; import { ToolCallConfirmationDetails } from '../ui/types.js'; // Added for shouldConfirmExecute +import { getErrorMessage } from '../utils/errors.js'; /** * Parameters for the WebFetch tool @@ -12,18 +13,10 @@ export interface WebFetchToolParams { url: string; } -/** - * Standardized result from the WebFetch tool - */ -export interface WebFetchToolResult extends ToolResult {} - /** * Implementation of the WebFetch tool that reads content from a URL. */ -export class WebFetchTool extends BaseTool< - WebFetchToolParams, - WebFetchToolResult -> { +export class WebFetchTool extends BaseTool { static readonly Name: string = 'web_fetch'; /** @@ -73,7 +66,7 @@ export class WebFetchTool extends BaseTool< if (!['http:', 'https:'].includes(parsedUrl.protocol)) { return `Invalid URL protocol: "${parsedUrl.protocol}". Only 'http:' and 'https:' are supported.`; } - } catch (error) { + } catch { // The URL constructor throws if the format is invalid return `Invalid URL format: "${params.url}". Please provide a valid absolute URL (e.g., 'https://example.com').`; } @@ -101,6 +94,7 @@ export class WebFetchTool extends BaseTool< * @returns Whether execute should be confirmed. */ async shouldConfirmExecute( + // eslint-disable-next-line @typescript-eslint/no-unused-vars params: WebFetchToolParams, ): Promise { // Could add logic here to confirm based on domain, etc. if needed @@ -112,7 +106,7 @@ export class WebFetchTool extends BaseTool< * @param params Parameters for the web fetch operation. * @returns Result with the fetched content or an error message. */ - async execute(params: WebFetchToolParams): Promise { + async execute(params: WebFetchToolParams): Promise { const validationError = this.invalidParams(params); if (validationError) { return { @@ -159,10 +153,10 @@ export class WebFetchTool extends BaseTool< llmContent, returnDisplay: `Fetched content from ${url}`, // Simple display message }; - } catch (error: any) { + } catch (error: unknown) { // This catches network errors (DNS resolution, connection refused, etc.) // and errors from the URL constructor if somehow bypassed validation (unlikely) - const errorMessage = `Failed to fetch data from ${url}. Error: ${error instanceof Error ? error.message : String(error)}`; + const errorMessage = `Failed to fetch data from ${url}. Error: ${getErrorMessage(error)}`; return { llmContent: `Error: ${errorMessage}`, returnDisplay: `**Error:** ${errorMessage}`, diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index b17ab9d8..3a06851c 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -1,32 +1,27 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { Box, Text } from 'ink'; -import fs from 'fs'; -import path from 'path'; -import os from 'os'; import type { HistoryItem } from './types.js'; import { useGeminiStream } from './hooks/useGeminiStream.js'; import { useLoadingIndicator } from './hooks/useLoadingIndicator.js'; -import Header from './components/Header.js'; -import Tips from './components/Tips.js'; -import HistoryDisplay from './components/HistoryDisplay.js'; -import LoadingIndicator from './components/LoadingIndicator.js'; -import InputPrompt from './components/InputPrompt.js'; -import Footer from './components/Footer.js'; +import { Header } from './components/Header.js'; +import { Tips } from './components/Tips.js'; +import { HistoryDisplay } from './components/HistoryDisplay.js'; +import { LoadingIndicator } from './components/LoadingIndicator.js'; +import { InputPrompt } from './components/InputPrompt.js'; +import { Footer } from './components/Footer.js'; import { StreamingState } from '../core/gemini-stream.js'; import { PartListUnion } from '@google/genai'; -import ITermDetectionWarning from './utils/itermDetection.js'; +import { ITermDetectionWarning } from './utils/itermDetection.js'; import { useStartupWarnings, useInitializationErrorEffect, } from './hooks/useAppEffects.js'; -const warningsFilePath = path.join(os.tmpdir(), 'gemini-code-cli-warnings.txt'); - interface AppProps { directory: string; } -const App = ({ directory }: AppProps) => { +export const App = ({ directory }: AppProps) => { const [query, setQuery] = useState(''); const [history, setHistory] = useState([]); const [startupWarnings, setStartupWarnings] = useState([]); @@ -138,5 +133,3 @@ const App = ({ directory }: AppProps) => { ); }; - -export default App; diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx index f2afc1bd..e018780c 100644 --- a/packages/cli/src/ui/components/Footer.tsx +++ b/packages/cli/src/ui/components/Footer.tsx @@ -5,7 +5,7 @@ interface FooterProps { queryLength: number; } -const Footer: React.FC = ({ queryLength }) => ( +export const Footer: React.FC = ({ queryLength }) => ( {queryLength === 0 ? '? for shortcuts' : ''} @@ -13,5 +13,3 @@ const Footer: React.FC = ({ queryLength }) => ( Gemini ); - -export default Footer; diff --git a/packages/cli/src/ui/components/Header.tsx b/packages/cli/src/ui/components/Header.tsx index f8f7d27e..640da5a5 100644 --- a/packages/cli/src/ui/components/Header.tsx +++ b/packages/cli/src/ui/components/Header.tsx @@ -7,7 +7,7 @@ interface HeaderProps { cwd: string; } -const Header: React.FC = ({ cwd }) => ( +export const Header: React.FC = ({ cwd }) => ( <> {/* Static Header Art */} @@ -34,5 +34,3 @@ const Header: React.FC = ({ cwd }) => ( ); - -export default Header; diff --git a/packages/cli/src/ui/components/HistoryDisplay.tsx b/packages/cli/src/ui/components/HistoryDisplay.tsx index 7565c5bc..1c43a67b 100644 --- a/packages/cli/src/ui/components/HistoryDisplay.tsx +++ b/packages/cli/src/ui/components/HistoryDisplay.tsx @@ -1,12 +1,11 @@ import React from 'react'; import { Box } from 'ink'; import type { HistoryItem } from '../types.js'; -import { UI_WIDTH } from '../constants.js'; -import UserMessage from './messages/UserMessage.js'; -import GeminiMessage from './messages/GeminiMessage.js'; -import InfoMessage from './messages/InfoMessage.js'; -import ErrorMessage from './messages/ErrorMessage.js'; -import ToolGroupMessage from './messages/ToolGroupMessage.js'; +import { UserMessage } from './messages/UserMessage.js'; +import { GeminiMessage } from './messages/GeminiMessage.js'; +import { InfoMessage } from './messages/InfoMessage.js'; +import { ErrorMessage } from './messages/ErrorMessage.js'; +import { ToolGroupMessage } from './messages/ToolGroupMessage.js'; import { PartListUnion } from '@google/genai'; interface HistoryDisplayProps { @@ -14,7 +13,7 @@ interface HistoryDisplayProps { onSubmit: (value: PartListUnion) => void; } -const HistoryDisplay: React.FC = ({ +export const HistoryDisplay: React.FC = ({ history, onSubmit, }) => ( @@ -36,4 +35,3 @@ const HistoryDisplay: React.FC = ({ ))} ); -export default HistoryDisplay; diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 96089eec..74f45b7f 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -10,7 +10,7 @@ interface InputPromptProps { isActive: boolean; } -const InputPrompt: React.FC = ({ +export const InputPrompt: React.FC = ({ query, setQuery, onSubmit, @@ -33,5 +33,3 @@ const InputPrompt: React.FC = ({ ); }; - -export default InputPrompt; diff --git a/packages/cli/src/ui/components/LoadingIndicator.tsx b/packages/cli/src/ui/components/LoadingIndicator.tsx index 442ddf26..defef06c 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.tsx @@ -8,7 +8,7 @@ interface LoadingIndicatorProps { elapsedTime: number; } -const LoadingIndicator: React.FC = ({ +export const LoadingIndicator: React.FC = ({ isLoading, currentLoadingPhrase, elapsedTime, @@ -30,5 +30,3 @@ const LoadingIndicator: React.FC = ({ ); }; - -export default LoadingIndicator; diff --git a/packages/cli/src/ui/components/Tips.tsx b/packages/cli/src/ui/components/Tips.tsx index aa8d39d6..a7112161 100644 --- a/packages/cli/src/ui/components/Tips.tsx +++ b/packages/cli/src/ui/components/Tips.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Box, Text } from 'ink'; import { UI_WIDTH } from '../constants.js'; -const Tips: React.FC = () => ( +export const Tips: React.FC = () => ( Tips for getting started: @@ -16,5 +16,3 @@ const Tips: React.FC = () => ( 4. Be specific for the best results. ); - -export default Tips; diff --git a/packages/cli/src/ui/components/messages/DiffRenderer.tsx b/packages/cli/src/ui/components/messages/DiffRenderer.tsx index a45efe2a..0e1f7828 100644 --- a/packages/cli/src/ui/components/messages/DiffRenderer.tsx +++ b/packages/cli/src/ui/components/messages/DiffRenderer.tsx @@ -85,7 +85,7 @@ interface DiffRendererProps { const DEFAULT_TAB_WIDTH = 4; // Spaces per tab for normalization -const DiffRenderer: React.FC = ({ +export const DiffRenderer: React.FC = ({ diffContent, tabWidth = DEFAULT_TAB_WIDTH, }) => { @@ -157,6 +157,9 @@ const DiffRenderer: React.FC = ({ dim = true; prefixSymbol = ' '; break; + default: + throw new Error(`Unknown line type: ${line.type}`); + break; } // Render the line content *after* stripping the calculated *minimum* baseIndentation. @@ -179,5 +182,3 @@ const DiffRenderer: React.FC = ({ ); }; - -export default DiffRenderer; diff --git a/packages/cli/src/ui/components/messages/ErrorMessage.tsx b/packages/cli/src/ui/components/messages/ErrorMessage.tsx index fb7f9fa5..325af44f 100644 --- a/packages/cli/src/ui/components/messages/ErrorMessage.tsx +++ b/packages/cli/src/ui/components/messages/ErrorMessage.tsx @@ -5,7 +5,7 @@ interface ErrorMessageProps { text: string; } -const ErrorMessage: React.FC = ({ text }) => { +export const ErrorMessage: React.FC = ({ text }) => { const prefix = '✕ '; const prefixWidth = prefix.length; @@ -22,5 +22,3 @@ const ErrorMessage: React.FC = ({ text }) => { ); }; - -export default ErrorMessage; diff --git a/packages/cli/src/ui/components/messages/GeminiMessage.tsx b/packages/cli/src/ui/components/messages/GeminiMessage.tsx index ccccbfc6..96773358 100644 --- a/packages/cli/src/ui/components/messages/GeminiMessage.tsx +++ b/packages/cli/src/ui/components/messages/GeminiMessage.tsx @@ -6,7 +6,7 @@ interface GeminiMessageProps { text: string; } -const GeminiMessage: React.FC = ({ text }) => { +export const GeminiMessage: React.FC = ({ text }) => { const prefix = '✦ '; const prefixWidth = prefix.length; @@ -40,5 +40,3 @@ const GeminiMessage: React.FC = ({ text }) => { ); }; - -export default GeminiMessage; diff --git a/packages/cli/src/ui/components/messages/InfoMessage.tsx b/packages/cli/src/ui/components/messages/InfoMessage.tsx index e6f24859..a0d0bfb6 100644 --- a/packages/cli/src/ui/components/messages/InfoMessage.tsx +++ b/packages/cli/src/ui/components/messages/InfoMessage.tsx @@ -5,7 +5,7 @@ interface InfoMessageProps { text: string; } -const InfoMessage: React.FC = ({ text }) => { +export const InfoMessage: React.FC = ({ text }) => { const prefix = 'ℹ '; const prefixWidth = prefix.length; @@ -22,5 +22,3 @@ const InfoMessage: React.FC = ({ text }) => { ); }; - -export default InfoMessage; diff --git a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx index 59c2cc42..15c99850 100644 --- a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx @@ -6,9 +6,9 @@ import { ToolEditConfirmationDetails, ToolConfirmationOutcome, ToolExecuteConfirmationDetails, -} from '../../types.js'; // Adjust path as needed +} from '../../types.js'; import { PartListUnion } from '@google/genai'; -import DiffRenderer from './DiffRenderer.js'; +import { DiffRenderer } from './DiffRenderer.js'; import { UI_WIDTH } from '../../constants.js'; export interface ToolConfirmationMessageProps { @@ -27,9 +27,9 @@ interface InternalOption { value: ToolConfirmationOutcome; } -const ToolConfirmationMessage: React.FC = ({ - confirmationDetails, -}) => { +export const ToolConfirmationMessage: React.FC< + ToolConfirmationMessageProps +> = ({ confirmationDetails }) => { const { onConfirm } = confirmationDetails; useInput((_, key) => { @@ -42,14 +42,11 @@ const ToolConfirmationMessage: React.FC = ({ onConfirm(item.value); }; - let title: string; let bodyContent: React.ReactNode | null = null; // Removed contextDisplay here let question: string; const options: InternalOption[] = []; if (isEditDetails(confirmationDetails)) { - title = 'Edit'; // Title for the outer box - // Body content is now the DiffRenderer, passing filename to it // The bordered box is removed from here and handled within DiffRenderer bodyContent = ; @@ -69,7 +66,6 @@ const ToolConfirmationMessage: React.FC = ({ } else { const executionProps = confirmationDetails as ToolExecuteConfirmationDetails; - title = 'Execute Command'; // Title for the outer box // For execution, we still need context display and description const commandDisplay = {executionProps.command}; @@ -118,5 +114,3 @@ const ToolConfirmationMessage: React.FC = ({ ); }; - -export default ToolConfirmationMessage; diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 6644cd5f..9e58651c 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Box } from 'ink'; import { IndividualToolCallDisplay, ToolCallStatus } from '../../types.js'; -import ToolMessage from './ToolMessage.js'; +import { ToolMessage } from './ToolMessage.js'; import { PartListUnion } from '@google/genai'; -import ToolConfirmationMessage from './ToolConfirmationMessage.js'; +import { ToolConfirmationMessage } from './ToolConfirmationMessage.js'; interface ToolGroupMessageProps { toolCalls: IndividualToolCallDisplay[]; @@ -11,7 +11,7 @@ interface ToolGroupMessageProps { } // Main component renders the border and maps the tools using ToolMessage -const ToolGroupMessage: React.FC = ({ +export const ToolGroupMessage: React.FC = ({ toolCalls, onSubmit, }) => { @@ -44,5 +44,3 @@ const ToolGroupMessage: React.FC = ({ ); }; - -export default ToolGroupMessage; diff --git a/packages/cli/src/ui/components/messages/ToolMessage.tsx b/packages/cli/src/ui/components/messages/ToolMessage.tsx index cd18dae2..4bb5ea94 100644 --- a/packages/cli/src/ui/components/messages/ToolMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolMessage.tsx @@ -3,7 +3,7 @@ import { Box, Text } from 'ink'; import Spinner from 'ink-spinner'; import { ToolCallStatus } from '../../types.js'; import { ToolResultDisplay } from '../../../tools/tools.js'; -import DiffRenderer from './DiffRenderer.js'; +import { DiffRenderer } from './DiffRenderer.js'; import { MarkdownRenderer } from '../../utils/MarkdownRenderer.js'; interface ToolMessageProps { @@ -13,7 +13,7 @@ interface ToolMessageProps { status: ToolCallStatus; } -const ToolMessage: React.FC = ({ +export const ToolMessage: React.FC = ({ name, description, resultDisplay, @@ -70,5 +70,3 @@ const ToolMessage: React.FC = ({ ); }; - -export default ToolMessage; diff --git a/packages/cli/src/ui/components/messages/UserMessage.tsx b/packages/cli/src/ui/components/messages/UserMessage.tsx index 08c0070f..574b11bf 100644 --- a/packages/cli/src/ui/components/messages/UserMessage.tsx +++ b/packages/cli/src/ui/components/messages/UserMessage.tsx @@ -5,7 +5,7 @@ interface UserMessageProps { text: string; } -const UserMessage: React.FC = ({ text }) => { +export const UserMessage: React.FC = ({ text }) => { const prefix = '> '; const prefixWidth = prefix.length; @@ -20,5 +20,3 @@ const UserMessage: React.FC = ({ text }) => { ); }; - -export default UserMessage; diff --git a/packages/cli/src/ui/hooks/useAppEffects.ts b/packages/cli/src/ui/hooks/useAppEffects.ts index 7bd7c6d6..86b56223 100644 --- a/packages/cli/src/ui/hooks/useAppEffects.ts +++ b/packages/cli/src/ui/hooks/useAppEffects.ts @@ -3,6 +3,7 @@ import fs from 'fs'; import path from 'path'; import os from 'os'; import type { HistoryItem } from '../types.js'; +import { getErrorMessage } from '../../utils/errors.js'; const warningsFilePath = path.join(os.tmpdir(), 'gemini-code-cli-warnings.txt'); @@ -19,17 +20,17 @@ export function useStartupWarnings( ); try { fs.unlinkSync(warningsFilePath); - } catch (unlinkErr: any) { + } catch { setStartupWarnings((prev) => [ ...prev, `Warning: Could not delete temporary warnings file.`, ]); } } - } catch (err: any) { + } catch (err: unknown) { setStartupWarnings((prev) => [ ...prev, - `Error checking/reading warnings file: ${err.message}`, + `Error checking/reading warnings file: ${getErrorMessage(err)}`, ]); } }, [setStartupWarnings]); // Include setStartupWarnings in dependency array diff --git a/packages/cli/src/ui/utils/itermDetection.tsx b/packages/cli/src/ui/utils/itermDetection.tsx index 9a847724..69c1f06a 100644 --- a/packages/cli/src/ui/utils/itermDetection.tsx +++ b/packages/cli/src/ui/utils/itermDetection.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Box, Text } from 'ink'; -const ITermDetectionWarning: React.FC = () => { +export const ITermDetectionWarning: React.FC = () => { if (process.env.TERM_PROGRAM !== 'iTerm.app') { return null; // Don't render anything if not in iTerm } @@ -12,5 +12,3 @@ const ITermDetectionWarning: React.FC = () => { ); }; - -export default ITermDetectionWarning; diff --git a/scripts/check-build-status.js b/scripts/check-build-status.js index 37638e72..6299a6e9 100644 --- a/scripts/check-build-status.js +++ b/scripts/check-build-status.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef */ import fs from 'fs'; import path from 'path'; import os from 'os'; // Import os module