Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Tutorial: gemini-cli
- The **gemini-cli** is an *interactive command-line interface* that provides AI-powered coding assistance. It combines **terminal UI components** with **Gemini AI capabilities** to help developers edit files, run commands, and get coding suggestions. Key features include:
- - *Sandboxed execution* for security
- - *Context-aware* suggestions based on project files
- - *Tool integration* for common development tasks
- - *Themable interface* with markdown support
- **Source Repository:** [None](None)
- ```mermaid
- flowchart TD
- A0["Configuration System
- "]
- A1["Context Management
- "]
- A2["Sandbox System
- "]
- A3["Authentication Flow
- "]
- A4["Telemetry System
- "]
- A5["Content Generation
- "]
- A6["Tool Registry
- "]
- A7["Tool Scheduler
- "]
- A8["Editor Integration
- "]
- A9["Terminal UI Components
- "]
- A10["Message Display System
- "]
- A11["Theme Management System
- "]
- A12["Theme System
- "]
- A13["Tool System
- "]
- A14["Error Handling Framework
- "]
- A15["File System Operations
- "]
- A16["Interactive Shell Utilities
- "]
- A17["Interactive UI Framework
- "]
- A18["Utility Functions
- "]
- A19["Validation Framework
- "]
- A20["Build Pipeline
- "]
- A21["Custom Hooks
- "]
- A22["Input Handling
- "]
- A23["Layout Management
- "]
- A24["Markdown Rendering Engine
- "]
- A25["Package Management
- "]
- A26["Privacy Notices
- "]
- A27["Session Statistics
- "]
- A28["Shared UI Components
- "]
- A29["Telemetry Service
- "]
- A30["Tool Execution System
- "]
- A31["Tool Framework
- "]
- A32["CLI Application Core
- "]
- A33["Configuration Management
- "]
- A34["Error Handling System
- "]
- A35["Event Logging
- "]
- A36["File Operations
- "]
- A37["File Processing Pipeline
- "]
- A38["Release Process
- "]
- A39["Sandboxing System
- "]
- A40["User Context Management
- "]
- A41["API Server Interface
- "]
- A42["Command Processing
- "]
- A43["Config Management
- "]
- A44["Content Correction System
- "]
- A45["Content Diffing
- "]
- A46["Conversation Management
- "]
- A47["File Reference Processor
- "]
- A48["File System Utilities
- "]
- A49["History Management
- "]
- A50["Memory Management
- "]
- A51["Non-Interactive Mode
- "]
- A52["Request/Response Formatting
- "]
- A53["Schema Validation
- "]
- A54["Tool Execution
- "]
- A55["Activity Logger
- "]
- A56["Authentication System
- "]
- A57["Chat Session
- "]
- A58["Content Correction
- "]
- A59["Conversation Turn
- "]
- A60["Cross-Package Import Rules
- "]
- A61["Error Reporting
- "]
- A62["Extension System
- "]
- A63["File Discovery
- "]
- A64["File Discovery Service
- "]
- A65["Gemini Client
- "]
- A66["Gemini Stream Processing
- "]
- A67["Git Integration
- "]
- A68["MCP Tools
- "]
- A69["Shell Command Execution
- "]
- A70["Shell Execution
- "]
- A71["System Prompts
- "]
- A32 -- "Orchestrates" --> A0
- A32 -- "Manages" --> A3
- A32 -- "Controls" --> A17
- A17 -- "Renders" --> A9
- A17 -- "Displays" --> A10
- A5 -- "Uses" --> A65
- A6 -- "Manages" --> A13
- A7 -- "Coordinates" --> A30
- A11 -- "Controls" --> A12
- A14 -- "Extends" --> A34
- A15 -- "Wraps" --> A36
- A16 -- "Provides" --> A22
- A18 -- "Supports" --> A15
- A19 -- "Uses" --> A53
- A20 -- "Feeds" --> A38
- A21 -- "Extends" --> A17
- A23 -- "Arranges" --> A10
- A24 -- "Formats" --> A10
- A25 -- "Manages" --> A20
- A26 -- "Shows" --> A3
- A27 -- "Reports" --> A4
- A28 -- "Provides" --> A9
- A29 -- "Implements" --> A4
- A31 -- "Supports" --> A54
- A33 -- "Manages" --> A43
- A35 -- "Feeds" --> A55
- A37 -- "Processes" --> A47
- A39 -- "Implements" --> A2
- A40 -- "Provides" --> A1
- A41 -- "Connects" --> A5
- A42 -- "Triggers" --> A69
- A44 -- "Performs" --> A58
- A45 -- "Supports" --> A50
- A46 -- "Controls" --> A57
- A48 -- "Assists" --> A63
- A49 -- "Tracks" --> A59
- A51 -- "Bypasses" --> A8
- A52 -- "Formats" --> A66
- A56 -- "Implements" --> A3
- A60 -- "Governs" --> A25
- A61 -- "Feeds" --> A14
- A62 -- "Loads" --> A68
- A64 -- "Supports" --> A47
- A67 -- "Enhances" --> A15
- A70 -- "Secures" --> A69
- A71 -- "Guides" --> A5
- ```
- ## Chapters
- 1. [CLI Application Core
- ](01_cli_application_core_.md)
- 2. [Interactive UI Framework
- ](02_interactive_ui_framework_.md)
- 3. [Terminal UI Components
- ](03_terminal_ui_components_.md)
- 4. [Message Display System
- ](04_message_display_system_.md)
- 5. [Content Generation
- ](05_content_generation_.md)
- 6. [Gemini Client
- ](06_gemini_client_.md)
- 7. [Authentication Flow
- ](07_authentication_flow_.md)
- 8. [Authentication System
- ](08_authentication_system_.md)
- 9. [Sandbox System
- ](09_sandbox_system_.md)
- 10. [Sandboxing System
- ](10_sandboxing_system_.md)
- 11. [Tool Registry
- ](11_tool_registry_.md)
- 12. [Tool System
- ](12_tool_system_.md)
- 13. [Tool Execution System
- ](13_tool_execution_system_.md)
- 14. [Tool Execution
- ](14_tool_execution_.md)
- 15. [File System Operations
- ](15_file_system_operations_.md)
- 16. [File Operations
- ](16_file_operations_.md)
- 17. [File Discovery
- ](17_file_discovery_.md)
- 18. [File Reference Processor
- ](18_file_reference_processor_.md)
- 19. [Configuration System
- ](19_configuration_system_.md)
- 20. [Configuration Management
- ](20_configuration_management_.md)
- 21. [Config Management
- ](21_config_management_.md)
- 22. [Theme Management System
- ](22_theme_management_system_.md)
- 23. [Theme System
- ](23_theme_system_.md)
- 24. [Markdown Rendering Engine
- ](24_markdown_rendering_engine_.md)
- 25. [Error Handling Framework
- ](25_error_handling_framework_.md)
- 26. [Error Handling System
- ](26_error_handling_system_.md)
- 27. [Error Reporting
- ](27_error_reporting_.md)
- 28. [Telemetry System
- ](28_telemetry_system_.md)
- 29. [Telemetry Service
- ](29_telemetry_service_.md)
- 30. [Session Statistics
- ](30_session_statistics_.md)
- 31. [Conversation Management
- ](31_conversation_management_.md)
- 32. [Chat Session
- ](32_chat_session_.md)
- 33. [Conversation Turn
- ](33_conversation_turn_.md)
- 34. [System Prompts
- ](34_system_prompts_.md)
- 35. [Input Handling
- ](35_input_handling_.md)
- 36. [Interactive Shell Utilities
- ](36_interactive_shell_utilities_.md)
- 37. [Shell Command Execution
- ](37_shell_command_execution_.md)
- 38. [Shell Execution
- ](38_shell_execution_.md)
- 39. [Tool Scheduler
- ](39_tool_scheduler_.md)
- 40. [Tool Framework
- ](40_tool_framework_.md)
- 41. [Custom Hooks
- ](41_custom_hooks_.md)
- 42. [Layout Management
- ](42_layout_management_.md)
- 43. [Shared UI Components
- ](43_shared_ui_components_.md)
- 44. [Editor Integration
- ](44_editor_integration_.md)
- 45. [Non-Interactive Mode
- ](45_non_interactive_mode_.md)
- 46. [Utility Functions
- ](46_utility_functions_.md)
- 47. [Validation Framework
- ](47_validation_framework_.md)
- 48. [Schema Validation
- ](48_schema_validation_.md)
- 49. [Build Pipeline
- ](49_build_pipeline_.md)
- 50. [Package Management
- ](50_package_management_.md)
- 51. [Cross-Package Import Rules
- ](51_cross_package_import_rules_.md)
- 52. [Release Process
- ](52_release_process_.md)
- 53. [Privacy Notices
- ](53_privacy_notices_.md)
- 54. [Context Management
- ](54_context_management_.md)
- 55. [User Context Management
- ](55_user_context_management_.md)
- 56. [Event Logging
- ](56_event_logging_.md)
- 57. [Activity Logger
- ](57_activity_logger_.md)
- 58. [File Processing Pipeline
- ](58_file_processing_pipeline_.md)
- 59. [API Server Interface
- ](59_api_server_interface_.md)
- 60. [Command Processing
- ](60_command_processing_.md)
- 61. [Content Correction System
- ](61_content_correction_system_.md)
- 62. [Content Correction
- ](62_content_correction_.md)
- 63. [Content Diffing
- ](63_content_diffing_.md)
- 64. [File System Utilities
- ](64_file_system_utilities_.md)
- 65. [History Management
- ](65_history_management_.md)
- 66. [Memory Management
- ](66_memory_management_.md)
- 67. [Request/Response Formatting
- ](67_request_response_formatting_.md)
- 68. [Gemini Stream Processing
- ](68_gemini_stream_processing_.md)
- 69. [Extension System
- ](69_extension_system_.md)
- 70. [MCP Tools
- ](70_mcp_tools_.md)
- 71. [File Discovery Service
- ](71_file_discovery_service_.md)
- 72. [Git Integration
- ](72_git_integration_.md)
- ---
- # Chapter 1: CLI Application Core
- Welcome to your first step in building CLI applications! In this chapter, we'll explore the heart of any command-line tool - the **CLI Application Core**. Think of this as the "brain" that coordinates everything your app does.
- ## Why Do We Need a Core?
- Imagine you're building a simple weather CLI app. When someone types `weather --city Paris`, your app needs to:
- 1. Understand the command (`weather`)
- 2. Read the option (`--city Paris`)
- 3. Fetch weather data
- 4. Display it nicely
- 5. Handle any errors
- The CLI Application Core handles all this coordination behind the scenes, like a restaurant manager making sure all staff work together smoothly.
- ## Key Responsibilities
- Our core has three main jobs:
- 1. **Startup**: Setting up everything when the app launches
- 2. **Orchestration**: Managing all components (like [Configuration System](19_configuration_system_.md) and [Authentication Flow](07_authentication_flow_.md))
- 3. **Shutdown**: Cleaning up when the app closes
- ## A Simple Example
- Here's what a minimal core might look like:
- ```typescript
- // The main entry point
- async function main() {
- // 1. Startup
- const config = loadConfig(); // [Configuration System](19_configuration_system_.md)
- // 2. Orchestration
- const command = process.argv[2]; // Get user input
- if (command === 'weather') {
- const weather = await fetchWeather(config);
- displayWeather(weather); // [Message Display System](04_message_display_system_.md)
- }
- // 3. Shutdown
- cleanup();
- }
- ```
- This shows the core's basic flow: setup → do work → clean up.
- ## Under the Hood
- Let's visualize how this works using a simple sequence:
- ```mermaid
- sequenceDiagram
- participant User as User
- participant Core as CLI Core
- participant Config as Configuration
- participant Service as Weather Service
- User->>Core: Runs "weather --city Paris"
- Core->>Config: Load settings
- Config-->>Core: Returns config
- Core->>Service: Fetch Paris weather
- Service-->>Core: Returns data
- Core->>User: Displays forecast
- ```
- ## Real-World Implementation
- In our actual code (found in `packages/cli/src/gemini.tsx`), the core handles more complex scenarios:
- ```typescript
- async function main() {
- // Load configuration
- const config = await loadCliConfig();
- // Check if we need more memory
- const memoryArgs = getNodeMemoryArgs(config);
- if (memoryArgs.length > 0) {
- await relaunchWithAdditionalArgs(memoryArgs);
- }
- // Handle user input
- if (hasInputFromUser) {
- await handleUserInput(config);
- } else {
- showInteractiveUI(config); // [Interactive UI Framework](02_interactive_ui_framework_.md)
- }
- }
- ```
- Key things to notice:
- 1. It first loads configuration
- 2. Checks system resources
- 3. Decides whether to show an interactive UI or process direct input
- ## Common Patterns
- The core typically uses these patterns:
- - **Singleton**: Only one core instance exists
- - **Facade**: Provides simple interfaces to complex subsystems
- - **Lifecycle Hooks**: Methods like `startup()` and `shutdown()`
- ## Error Handling
- A good core also manages errors gracefully:
- ```typescript
- main().catch((error) => {
- console.error('Oops! Something went wrong:');
- console.error(error);
- process.exit(1); // Exit with error code
- });
- ```
- ## What's Next?
- Now that you understand the CLI Application Core, you're ready to explore how it interacts with other parts! In [Chapter 2: Interactive UI Framework](02_interactive_ui_framework_.md), we'll see how the core manages user interfaces.
- ---
- # Chapter 2: Interactive UI Framework
- Welcome back! In [Chapter 1: CLI Application Core](01_cli_application_core_.md), we learned how CLI apps work behind the scenes. Now, let's explore something exciting - how to make your terminal apps interactive like web apps!
- ## Why Interactive UI?
- Imagine typing `weather` and seeing a friendly menu where you can:
- - Use arrow keys to select cities
- - See live weather updates
- - Get colorful forecasts
- This is what our Interactive UI Framework makes possible! It brings web-like experiences to your terminal.
- ## Key Concepts
- Our framework has three main parts:
- 1. **Components**: Building blocks like buttons or menus
- 2. **State**: Remembering what's selected/changed
- 3. **Events**: Handling keyboard/mouse actions
- Think of it like LEGO:
- - Components = LEGO pieces
- - State = What you're building
- - Events = Your hands moving pieces
- ## A Simple Example
- Here's how to create a basic menu:
- ```typescript
- import { Menu } from 'gemini-cli';
- function WeatherMenu() {
- return (
- <Menu
- items={["Paris", "London", "Tokyo"]}
- onSelect={(city) => fetchWeather(city)}
- />
- );
- }
- ```
- This creates a menu that:
- 1. Shows 3 cities
- 2. Calls `fetchWeather` when you pick one
- ## How It Works Inside
- When you run this, here's what happens:
- ```mermaid
- sequenceDiagram
- participant User as User
- participant UI as UI Framework
- participant App as Your App
- User->>UI: Presses down arrow
- UI->>UI: Updates selected item
- UI->>App: Highlights "London"
- User->>UI: Presses Enter
- UI->>App: Calls onSelect("London")
- App->>App: Fetches weather data
- ```
- ## Real-World Usage
- In our actual code (like `packages/cli/src/ui/App.tsx`), we use hooks to manage state:
- ```typescript
- function App() {
- const [city, setCity] = useState("Paris");
- return (
- <Box>
- <Text>Selected: {city}</Text>
- <Menu items={cities} onSelect={setCity} />
- </Box>
- );
- }
- ```
- Key things to notice:
- 1. `useState` remembers the selected city
- 2. `setCity` updates it when menu changes
- 3. The display automatically updates!
- ## Common Patterns
- You'll often see:
- - **State Hooks**: `useState`, `useEffect`
- - **Layout Components**: `Box`, `Text`
- - **Input Handlers**: `useInput` for keyboard events
- ## What's Next?
- Now you've seen how we build interactive terminal UIs! Next, we'll explore the [Terminal UI Components](03_terminal_ui_components_.md) that make this possible.
- > Pro Tip: Try adding `<Button>` components to your menu for extra interactivity!
- ---
- # Chapter 3: Terminal UI Components
- Welcome back! In [Chapter 2: Interactive UI Framework](02_interactive_ui_framework_.md), we learned how to make terminal apps interactive. Now, let's meet the building blocks that make this possible - Terminal UI Components!
- ## Why Do We Need Components?
- Imagine building a house. You wouldn't craft every brick from scratch - you'd use pre-made bricks, windows, and doors. Similarly, Terminal UI Components are pre-made pieces for building terminal interfaces:
- - Boxes to organize content
- - Text with colors and styles
- - Borders for visual separation
- - Input fields for user interaction
- ## Meet the Basic Components
- Here are the most common components you'll use:
- 1. **Text** - Displays words in the terminal
- 2. **Box** - Creates containers with borders
- 3. **Input** - Gets user keyboard input
- 4. **Menu** - Shows selectable options
- ## A Simple Example
- Let's create a basic message box:
- ```typescript
- import { Box, Text } from 'gemini-cli';
- function WelcomeMessage() {
- return (
- <Box borderStyle="round">
- <Text color="green">Welcome to Gemini CLI!</Text>
- </Box>
- );
- }
- ```
- This creates:
- - A rounded border box
- - Green text inside saying "Welcome to Gemini CLI!"
- ## How Components Work Together
- When you use components, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant App as Your App
- participant Ink as Ink Library
- participant Term as Terminal
- App->>Ink: Render <Box> with <Text>
- Ink->>Term: Draw borders and text
- Term-->>User: Shows the boxed message
- ```
- ## Real-World Component Usage
- Let's look at a more complete example from our codebase (`packages/cli/src/ui/components/AboutBox.tsx`):
- ```typescript
- function InfoBox() {
- return (
- <Box borderStyle="round" borderColor="gray">
- <Text bold>System Info</Text>
- <Text>Version: 1.0.0</Text>
- <Text>OS: MacOS</Text>
- </Box>
- );
- }
- ```
- Key features:
- - `borderStyle` makes the rounded box
- - `borderColor` sets the border color
- - Nested `Text` components display information
- ## Styling Your Components
- You can customize components with props:
- ```typescript
- <Text
- color="blue"
- bold
- underline
- >
- Important Message
- </Text>
- ```
- Common styling props:
- - `color`: Text color (red, green, blue, etc.)
- - `bold`: Makes text bold
- - `underline`: Underlines text
- - `backgroundColor`: Sets background color
- ## What's Next?
- Now you understand the building blocks of terminal interfaces! In [Chapter 4: Message Display System](04_message_display_system_.md), we'll learn how to show messages and responses to users.
- > Pro Tip: Try combining multiple Box components to create complex layouts!
- ---
- # Chapter 4: Message Display System
- Welcome back! In [Chapter 3: Terminal UI Components](03_terminal_ui_components_.md), we learned about building blocks for terminal interfaces. Now, let's learn how to show different types of messages in your CLI app - like chat bubbles in a messaging app!
- ## Why Do We Need Message Display?
- Imagine you're building a chatbot. You need to show:
- - User messages (what people type)
- - AI responses
- - Error messages
- - System notifications
- Each type should look different so users can tell them apart easily. That's what our Message Display System does!
- ## Meet the Message Types
- Here are the main message types we'll work with:
- 1. **User Messages**: What the user types (shown in gray bubbles)
- 2. **AI Messages**: Responses from Gemini (purple prefix)
- 3. **Error Messages**: When something goes wrong (red text)
- 4. **Tool Messages**: When tools run commands (with status icons)
- ## A Simple Example
- Let's create a basic user message:
- ```typescript
- import { UserMessage } from 'gemini-cli';
- function ShowMessage() {
- return <UserMessage text="Hello Gemini!" />;
- }
- ```
- This will display:
- ```
- > Hello Gemini!
- ```
- (In a gray rounded box)
- ## How Messages Work Together
- When messages are displayed, here's what happens:
- ```mermaid
- sequenceDiagram
- participant App as Your App
- participant Message as Message System
- participant Term as Terminal
- App->>Message: Show <UserMessage>
- Message->>Term: Draw gray bubble with text
- Term-->>User: Shows the message
- ```
- ## Real-World Message Components
- Let's look at how we show an AI response (from `packages/cli/src/ui/components/messages/GeminiMessage.tsx`):
- ```typescript
- function GeminiResponse() {
- return (
- <Box flexDirection="row">
- <Text color="purple">✦ </Text>
- <Text>Here's your answer!</Text>
- </Box>
- );
- }
- ```
- Key parts:
- - Purple `✦` prefix marks AI messages
- - Text appears next to it
- - Simple row layout
- ## Styling Different Messages
- Each message type has its own style:
- ```typescript
- // Error message (red)
- <ErrorMessage text="File not found" />
- // Info message (yellow)
- <InfoMessage text="Connected to server" />
- // Tool message (with status icon)
- <ToolMessage name="search" status="success" />
- ```
- Common styles:
- - Colors match message purpose (red for errors, etc.)
- - Icons show message type
- - Consistent spacing
- ## What's Next?
- Now you know how to display different message types! In [Chapter 5: Content Generation](05_content_generation_.md), we'll learn how Gemini creates the responses you show with this system.
- > Pro Tip: Try combining message types to build a complete chat interface!
- ---
- # Chapter 5: Content Generation
- Welcome back! In [Chapter 4: Message Display System](04_message_display_system_.md), we learned how to show messages in your CLI app. Now, let's explore how Gemini actually creates those responses - the magic of Content Generation!
- ## Why Do We Need Content Generation?
- Imagine asking your CLI app: "Translate 'hello' to French". The app needs to:
- 1. Understand your request
- 2. Generate the correct response ("bonjour")
- 3. Handle errors if something goes wrong
- 4. Show the result nicely
- Content Generation is like a helpful translator that does all this work behind the scenes!
- ## How Content Generation Works
- Let's break it down into simple parts:
- 1. **Input**: Your question ("Translate 'hello' to French")
- 2. **Processing**: Gemini understands and generates a response
- 3. **Output**: The translated word ("bonjour")
- Here's a simple example:
- ```typescript
- import { generateContent } from 'gemini-cli';
- async function translate() {
- const response = await generateContent({
- prompt: "Translate 'hello' to French"
- });
- console.log(response); // "bonjour"
- }
- ```
- This shows the basic flow: you ask, Gemini answers.
- ## Behind the Scenes
- When you make a request, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI App
- participant Gemini as Gemini Service
- You->>CLI: Ask to translate "hello"
- CLI->>Gemini: Sends request
- Gemini->>Gemini: Processes translation
- Gemini-->>CLI: Returns "bonjour"
- CLI->>You: Shows translation
- ```
- ## Handling Different Cases
- The Content Generation system is smart enough to handle different situations:
- 1. **Success**: Gets the correct answer
- 2. **Errors**: If Gemini is busy, it tries again
- 3. **Fallback**: If the main model fails, it uses a simpler one
- Here's how we handle errors:
- ```typescript
- try {
- const response = await generateContent({ prompt: "Translate..." });
- console.log(response);
- } catch (error) {
- console.log("Oops! Let me try again...");
- // Automatically retries with a simpler model
- }
- ```
- ## Real-World Example
- In our actual code (like `packages/core/src/core/contentGenerator.ts`), we configure the generator:
- ```typescript
- const config = {
- model: "gemini-pro", // Which AI model to use
- authType: "api-key" // How to authenticate
- };
- const generator = createContentGenerator(config);
- ```
- Key parts:
- - `model`: Which Gemini version to use
- - `authType`: How to log in (API key or Google account)
- ## What's Next?
- Now you understand how Gemini generates responses! In [Chapter 6: Gemini Client](06_gemini_client_.md), we'll explore how your app actually talks to Gemini's servers.
- > Pro Tip: Try changing the `model` in the config to see how responses vary!
- ---
- # Chapter 6: Gemini Client
- Welcome back! In [Chapter 5: Content Generation](05_content_generation_.md), we learned how Gemini creates responses. Now, let's meet the helpful "telephone operator" that connects your app to Gemini - the **Gemini Client**!
- ## Your App's Personal Assistant
- Imagine you're at a fancy hotel. When you need anything - room service, directions, or restaurant recommendations - you call the front desk. The Gemini Client works just like that helpful front desk operator:
- 1. You make a request ("What's the weather?")
- 2. The client talks to Gemini's servers
- 3. It brings back the answer ("Sunny and 75°F")
- ## A Simple Example
- Here's how easy it is to use the Gemini Client:
- ```typescript
- import { GeminiClient } from 'gemini-cli';
- // Set up your client
- const client = new GeminiClient(config);
- // Ask a question
- const response = await client.sendMessage("Hello Gemini!");
- console.log(response); // "Hello! How can I help you today?"
- ```
- This shows the basic flow: create client → send message → get response.
- ## What Can the Client Do?
- The Gemini Client handles four main jobs:
- 1. **Chat Sessions**: Keeps track of your conversation
- 2. **Content Generation**: Gets answers from Gemini
- 3. **Embeddings**: Turns words into numbers (for advanced features)
- 4. **Model Management**: Chooses the right Gemini version
- ## Behind the Scenes
- When you send a message, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Client as Gemini Client
- participant Gemini as Gemini Servers
- You->>Client: "What's 2+2?"
- Client->>Gemini: Sends question
- Gemini->>Gemini: Calculates answer
- Gemini-->>Client: Returns "4"
- Client->>You: Shows answer
- ```
- ## Real-World Usage
- In our actual code (like `packages/core/src/core/client.ts`), the client does much more:
- ```typescript
- class GeminiClient {
- private chat; // Remembers conversation history
- async sendMessage(message: string) {
- // 1. Add message to history
- this.chat.addMessage(message);
- // 2. Get response from Gemini
- const response = await this.getGeminiResponse();
- // 3. Return formatted answer
- return this.formatResponse(response);
- }
- }
- ```
- Key parts:
- - `chat`: Keeps track of your conversation
- - `getGeminiResponse`: Talks to Gemini's servers
- - `formatResponse`: Makes answers look nice
- ## Handling Different Requests
- The client is smart enough to handle different types of requests:
- ```typescript
- // Regular chat
- client.sendMessage("Hello!");
- // Get embeddings (for search features)
- client.generateEmbedding(["cat", "dog"]);
- // Generate JSON (for structured data)
- client.generateJson({schema: {name: "string"}});
- ```
- ## What's Next?
- Now you understand how your app talks to Gemini! In [Chapter 7: Authentication Flow](07_authentication_flow_.md), we'll learn how the client securely logs in to Gemini's services.
- > Pro Tip: Try adding multiple messages to see how the client remembers your conversation history!
- ---
- # Chapter 7: Authentication Flow
- Welcome back! In [Chapter 6: Gemini Client](06_gemini_client_.md), we learned how your app talks to Gemini. Now, let's explore how it securely logs in - just like when you sign into your favorite apps!
- ## Why Do We Need Authentication?
- Imagine going to a members-only club. Before entering, you need to:
- 1. Show your membership card (prove who you are)
- 2. Get checked by security (verify your access)
- 3. Receive a wristband (get temporary access)
- The Authentication Flow works similarly for your CLI app:
- 1. You choose how to log in (Google account or API key)
- 2. The system verifies your credentials
- 3. You get temporary access to use Gemini
- ## A Simple Example
- Here's how easy authentication can be:
- ```typescript
- import { authenticate } from 'gemini-cli';
- // Start authentication
- await authenticate();
- ```
- When you run this, you'll see:
- 1. A menu asking how you want to log in
- 2. Instructions based on your choice
- 3. Confirmation when successful
- ## The Three-Step Flow
- Authentication happens in three simple steps:
- 1. **Selection**: Choose your login method
- 2. **Verification**: Prove your identity
- 3. **Confirmation**: Get access to Gemini
- Here's how it looks in code:
- ```typescript
- // 1. Show login options
- const method = await showAuthMenu();
- // 2. Verify credentials
- const isValid = await verifyCredentials(method);
- // 3. Grant access
- if (isValid) {
- startGeminiSession();
- }
- ```
- ## Behind the Scenes
- When you authenticate, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI App
- participant Google as Google Servers
- You->>CLI: Runs "gemini auth"
- CLI->>You: Shows login options
- You->>CLI: Chooses "Google Login"
- CLI->>Google: Opens browser for login
- Google-->>CLI: Returns verification token
- CLI->>You: "Login successful!"
- ```
- ## Real-World Implementation
- In our actual code (like `packages/cli/src/ui/components/AuthDialog.tsx`), we handle different login methods:
- ```typescript
- function AuthDialog() {
- return (
- <Menu items={[
- "Login with Google",
- "Use API Key",
- "Vertex AI"
- ]} />
- );
- }
- ```
- Key parts:
- - Shows three login options
- - Handles each choice differently
- - Manages timeouts if login takes too long
- ## Handling Errors
- The system also manages problems gracefully:
- ```typescript
- try {
- await authenticate();
- } catch (error) {
- console.log("Oops! Let's try again...");
- // Automatically retries
- }
- ```
- Common issues it handles:
- - Wrong passwords
- - Expired API keys
- - Network problems
- ## What's Next?
- Now you understand how authentication works! In [Chapter 8: Authentication System](08_authentication_system_.md), we'll explore how your login stays secure while using Gemini.
- > Pro Tip: Try different login methods to see how the experience changes!
- ---
- # Chapter 8: Authentication System
- Welcome back! In [Chapter 7: Authentication Flow](07_authentication_flow_.md), we learned how users log in to your CLI app. Now, let's explore how the app keeps them securely logged in - like a bouncer checking IDs at a club!
- ## Why Do We Need an Authentication System?
- Imagine you're running a VIP club. You need to:
- 1. Check IDs at the door (verify who's allowed in)
- 2. Give wristbands to approved guests (temporary access)
- 3. Watch for expired wristbands (check ongoing access)
- Our Authentication System does exactly this for your CLI app:
- - Verifies login methods (API keys, Google accounts)
- - Manages active sessions
- - Handles expired or invalid credentials
- ## Meet the Authentication Methods
- The system supports three main ways to log in:
- 1. **Google Login**: Like showing your ID card
- 2. **API Key**: Like a secret password
- 3. **Vertex AI**: For advanced Google Cloud users
- Here's how simple it is to check credentials:
- ```typescript
- import { validateAuth } from 'gemini-cli';
- // Check if login is valid
- const isValid = await validateAuth('google-login');
- console.log(isValid); // true or false
- ```
- ## How Authentication Works
- When someone uses your app, here's what happens:
- ```mermaid
- sequenceDiagram
- participant User as User
- participant Auth as Auth System
- participant Google as Google Servers
- User->>Auth: Tries to use Gemini
- Auth->>Auth: Checks saved credentials
- Auth->>Google: Verifies with Google (if needed)
- Google-->>Auth: Returns verification
- Auth->>User: Grants or denies access
- ```
- ## Real-World Implementation
- Let's look at how we validate different login methods (from `packages/cli/src/config/auth.ts`):
- ```typescript
- function validateAuthMethod(method) {
- if (method === 'google-login') {
- return true; // Google handles verification
- }
- if (method === 'api-key') {
- return checkApiKeyExists(); // Looks for API key
- }
- }
- ```
- Key parts:
- - Different checks for each login type
- - Simple true/false responses
- - Handles missing credentials
- ## Keeping Sessions Secure
- The system also manages ongoing access:
- ```typescript
- // Check if session is still valid
- function checkSession() {
- if (session.expired) {
- logoutUser(); // Automatic logout
- }
- }
- ```
- Common security features:
- - Automatic logout after timeout
- - Token refreshing
- - Error handling for invalid sessions
- ## What's Next?
- Now you understand how authentication keeps your app secure! In [Chapter 9: Sandbox System](09_sandbox_system_.md), we'll explore how Gemini runs code safely.
- > Pro Tip: Try adding console logs to see when authentication checks happen!
- ---
- # Chapter 9: Sandbox System
- Welcome back! In [Chapter 8: Authentication System](08_authentication_system_.md), we learned how to keep your CLI app secure. Now, let's explore another safety feature - the **Sandbox System** - which acts like a protective bubble around risky operations.
- ## Why Do We Need a Sandbox?
- Imagine you're teaching a child to cook. You wouldn't let them use sharp knives right away - you'd give them safe plastic tools first. The Sandbox System works similarly for your CLI app:
- - It creates a safe space to run potentially dangerous code
- - If something goes wrong, it won't affect your main system
- - You can test new features without worrying about breaking things
- ## How the Sandbox Works
- Think of the sandbox like a playground with safety rules:
- 1. **Isolation**: Code runs in a separate environment
- 2. **Protection**: Can't accidentally delete your files
- 3. **Control**: You decide what's allowed
- Here's a simple example of running code in a sandbox:
- ```typescript
- import { runInSandbox } from 'gemini-cli';
- // This runs safely in the sandbox
- const result = await runInSandbox(() => {
- return "Hello from the sandbox!";
- });
- console.log(result); // "Hello from the sandbox!"
- ```
- ## Behind the Scenes
- When you use the sandbox, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as Your Code
- participant Sandbox as Sandbox System
- participant Host as Your Computer
- You->>Sandbox: Runs code
- Sandbox->>Sandbox: Creates safe environment
- Sandbox->>Host: Only allows approved actions
- Sandbox-->>You: Returns result
- Sandbox->>Sandbox: Cleans up safely
- ```
- ## Real-World Usage
- In our actual code (like `packages/cli/src/utils/sandbox.ts`), the sandbox can do more advanced things:
- ```typescript
- // Run a command safely
- await sandbox.executeCommand('ls', {
- allowFileAccess: true,
- timeout: 5000 // 5 second limit
- });
- ```
- Key safety features:
- - Time limits to prevent infinite loops
- - File access controls
- - Network restrictions
- ## Common Sandbox Patterns
- You'll often see these sandbox uses:
- 1. **Testing New Code**: Try features safely
- 2. **Running User Scripts**: Execute untrusted code
- 3. **File Operations**: Prevent accidental deletions
- ## What's Next?
- Now you understand how the Sandbox System keeps your CLI app safe! In [Chapter 10: Sandboxing System](10_sandboxing_system_.md), we'll explore more advanced sandboxing techniques.
- > Pro Tip: Try adding `console.log` inside a sandbox to see how it isolates your code!
- ---
- # Chapter 10: Sandboxing System
- Welcome back! In [Chapter 9: Sandbox System](09_sandbox_system_.md), we learned how to run code safely in a protected environment. Now, let's explore the **Sandboxing System** - like putting your code in a protective bubble that keeps your computer safe!
- ## Why Do We Need Sandboxing?
- Imagine you're letting a friend use your computer. You wouldn't give them full access - you'd create a special guest account with limited permissions. That's exactly what sandboxing does for untrusted code:
- - Runs code in an isolated space
- - Prevents access to your important files
- - Stops harmful network requests
- - Still lets the code do its job safely
- ## Meet the Sandbox Types
- Our system offers two main ways to sandbox code:
- 1. **macOS Seatbelt**: Like a strict parent watching over a child (only works on Mac)
- 2. **Container-Based**: Like putting the code in a sealed box (works everywhere)
- Here's how simple it is to use:
- ```typescript
- import { runSandboxed } from 'gemini-cli';
- // Run code safely in a sandbox
- const result = await runSandboxed(() => {
- return "I'm safe inside the sandbox!";
- });
- console.log(result); // "I'm safe inside the sandbox!"
- ```
- ## How Sandboxing Works
- When you run sandboxed code, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as Your Code
- participant Sandbox as Sandbox System
- participant Computer as Your Computer
- You->>Sandbox: Runs code
- Sandbox->>Sandbox: Creates protective bubble
- Sandbox->>Computer: Only allows safe actions
- Sandbox-->>You: Returns result
- Sandbox->>Sandbox: Cleans up safely
- ```
- ## Real-World Sandboxing
- Let's look at how we actually set up a sandbox (from `packages/cli/src/utils/sandbox.ts`):
- ```typescript
- // Simple file access sandbox
- const safeFileAccess = {
- read: ['/safe-folder'], // Can only read here
- write: ['/temp-folder'] // Can only write here
- };
- await runSandboxed(() => {
- // This would fail outside the allowed folders
- fs.readFile('/safe-folder/notes.txt');
- }, { restrictions: safeFileAccess });
- ```
- Key safety features:
- - Explicit file access rules
- - Network restrictions
- - Time limits on execution
- ## Common Sandboxing Uses
- You'll often use sandboxing for:
- 1. **User Plugins**: Let users add features safely
- 2. **Code Evaluation**: Run dynamic code safely
- 3. **File Operations**: Prevent accidental deletions
- ## What's Next?
- Now you understand how sandboxing keeps your CLI app secure! In [Chapter 11: Tool Registry](11_tool_registry_.md), we'll learn how to manage all the tools your app can use.
- > Pro Tip: Try sandboxing a simple file read operation to see the protection in action!
- ---
- # Chapter 11: Tool Registry
- Welcome back! In [Chapter 10: Sandboxing System](10_sandboxing_system_.md), we learned how to run code safely. Now, let's meet the **Tool Registry** - your CLI app's very own tool organizer, like a handy toolbelt that keeps all your tools neatly arranged and ready to use!
- ## Why Do We Need a Tool Registry?
- Imagine you're a carpenter with dozens of tools. Without organization, you'd waste time searching for the right hammer or screwdriver. The Tool Registry solves this problem by:
- 1. Keeping track of all available tools
- 2. Making tools easy to find when needed
- 3. Providing instructions for each tool
- For example, when you type `gemini search "best pizza places"`, the Tool Registry helps find the "web search" tool to get your results!
- ## Meet the Tool Organizer
- The Tool Registry has three main jobs:
- 1. **Registration**: Adding new tools to the collection
- 2. **Discovery**: Finding tools automatically (even remote ones!)
- 3. **Access**: Providing tool details when needed
- Here's how simple it is to register a tool:
- ```typescript
- import { ToolRegistry } from 'gemini-cli';
- // Create a registry
- const registry = new ToolRegistry();
- // Register a simple tool
- registry.registerTool({
- name: "greet",
- description: "Says hello",
- execute: () => "Hello there!"
- });
- ```
- This adds a new "greet" tool to your registry that says hello when called.
- ## How Tools Get Discovered
- The Tool Registry can also find tools automatically:
- ```typescript
- // Discover tools from your project
- await registry.discoverTools();
- ```
- This looks for special tool configuration files in your project and adds any tools it finds!
- ## Behind the Scenes
- When you use a tool, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Registry as Tool Registry
- participant Tool as The Tool
- You->>Registry: "Use the search tool"
- Registry->>Tool: Finds and activates
- Tool->>Registry: Returns results
- Registry->>You: Shows pizza places
- ```
- ## Real-World Implementation
- In our actual code (like `packages/core/src/tools/tool-registry.ts`), the registry does more advanced things:
- ```typescript
- class ToolRegistry {
- private tools = new Map(); // Stores all tools
- registerTool(tool) {
- this.tools.set(tool.name, tool); // Add to storage
- }
- getTool(name) {
- return this.tools.get(name); // Find by name
- }
- }
- ```
- Key parts:
- - Uses a `Map` to store tools efficiently
- - Simple methods to add and find tools
- - Handles duplicate tools gracefully
- ## Working with Remote Tools
- The registry can even manage tools from remote servers (called MCP tools):
- ```typescript
- // Connect to remote tool server
- await discoverMcpTools(serverConfig, registry);
- ```
- This lets your CLI use powerful tools hosted elsewhere while keeping everything organized in one place!
- ## What's Next?
- Now you understand how the Tool Registry keeps your CLI's tools organized! In [Chapter 12: Tool System](12_tool_system_.md), we'll explore how these tools actually work when you use them.
- > Pro Tip: Try registering a simple tool that returns the current time to see the registry in action!
- ---
- # Chapter 12: Tool System
- Welcome back! In [Chapter 11: Tool Registry](11_tool_registry_.md), we learned how to organize all the tools in your CLI app. Now, let's explore the **Tool System** - the magic that makes these tools actually work, like the engine in a Swiss Army knife that powers all its different functions!
- ## Why Do We Need Tools?
- Imagine you're building a robot helper. You want it to:
- - Search the web when you ask questions
- - Edit files when you need changes
- - List folders when you explore
- Each of these is a different "tool" your robot can use. The Tool System is what lets your CLI app switch between these different functions easily.
- ## Meet the Basic Tools
- Here are some simple tools you might use:
- 1. **File Editor**: Changes text in files
- 2. **Directory Lister**: Shows folder contents
- 3. **Web Searcher**: Finds information online
- Each tool follows the same simple pattern:
- ```typescript
- interface Tool {
- name: string;
- description: string;
- execute(params): Promise<Result>;
- }
- ```
- This means every tool has:
- - A name (like "web_search")
- - A description (what it does)
- - An execute method (how to run it)
- ## A Simple Example
- Let's create a basic "greet" tool:
- ```typescript
- const greetTool = {
- name: "greet",
- description: "Says hello to someone",
- execute: ({name}) => `Hello ${name}!`
- };
- // Using the tool:
- const result = await greetTool.execute({name: "Alice"});
- console.log(result); // "Hello Alice!"
- ```
- This shows how simple tools can be - just a name, description, and action!
- ## How Tools Work Together
- When you use a tool, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant System as Tool System
- participant Tool as The Tool
- You->>System: "Use the search tool"
- System->>Tool: Finds and runs
- Tool->>System: Returns results
- System->>You: Shows information
- ```
- ## Real-World Tools
- Let's look at part of our actual file editor tool (from `packages/core/src/tools/edit.ts`):
- ```typescript
- class EditTool {
- name = "edit_file";
- description = "Edits text in files";
- execute({filePath, oldText, newText}) {
- // 1. Read the file
- const content = fs.readFile(filePath);
- // 2. Make changes
- const newContent = content.replace(oldText, newText);
- // 3. Save changes
- fs.writeFile(filePath, newContent);
- return "File updated!";
- }
- }
- ```
- Key parts:
- 1. It reads the original file
- 2. Makes the requested changes
- 3. Saves the updated file
- ## Common Tool Patterns
- You'll often see tools that:
- 1. **Read Files**: Like our directory lister
- 2. **Modify Content**: Like the file editor
- 3. **Fetch Data**: Like the web searcher
- Each follows the same basic interface but does different work inside!
- ## What's Next?
- Now you understand how the Tool System powers all your CLI's functions! In [Chapter 13: Tool Execution System](13_tool_execution_system_.md), we'll learn how tools actually get run when you need them.
- > Pro Tip: Try creating a simple tool that returns the current time to see the system in action!
- ---
- # Chapter 13: Tool Execution System
- Welcome back! In [Chapter 12: Tool System](12_tool_system_.md), we learned how tools work in your CLI app. Now, let's meet the **Tool Execution System** - your app's personal assistant that carefully manages every tool operation from start to finish!
- ## Why Do We Need Tool Execution?
- Imagine you're baking cookies with a friend. You wouldn't just throw ingredients together randomly - you'd follow steps:
- 1. Check you have everything (confirmation)
- 2. Mix ingredients carefully (execution)
- 3. Show the delicious results (display)
- The Tool Execution System does exactly this for your CLI tools:
- 1. **Confirms** if tools should run
- 2. **Executes** them safely
- 3. **Shows** the results clearly
- ## Meet the Three-Step Process
- Every tool call follows this simple pattern:
- ```typescript
- // 1. Confirm the tool should run
- const shouldRun = await confirmToolUse("search");
- // 2. Execute if approved
- if (shouldRun) {
- const results = await executeTool("search", {query: "pizza"});
- // 3. Show results
- displayToolResults(results);
- }
- ```
- This shows the basic flow: confirm → execute → display.
- ## Behind the Scenes
- When you use a tool, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Confirm as Confirmation
- participant Tool as The Tool
- participant Display as Results
- You->>Confirm: "Can I use search?"
- Confirm-->>You: "Yes!"
- You->>Tool: Runs search for "pizza"
- Tool-->>Display: Returns pizza places
- Display->>You: Shows delicious results
- ```
- ## Real-World Implementation
- Let's look at how we actually confirm tool use (from `packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx`):
- ```typescript
- // Simple confirmation options
- const options = [
- { label: "Yes, run once", value: "once" },
- { label: "No, cancel", value: "cancel" }
- ];
- // Show confirmation dialog
- function confirmToolUse() {
- return showMenu(options); // Returns "once" or "cancel"
- }
- ```
- Key parts:
- - Simple menu with choices
- - Clear options for users
- - Returns the user's decision
- ## Executing Tools Safely
- After confirmation, tools run in a protected way:
- ```typescript
- async function executeTool(name, params) {
- try {
- // Run in protected environment
- return await safeRun(() => tools[name].execute(params));
- } catch (error) {
- return "Oops! Tool failed: " + error.message;
- }
- }
- ```
- Safety features:
- - Runs in protected space
- - Catches errors gracefully
- - Always returns something useful
- ## Displaying Results
- Finally, we show results clearly:
- ```typescript
- function displayToolResults(results) {
- console.log("=== Tool Results ===");
- console.log(results);
- console.log("===================");
- }
- ```
- This simple display helps users understand what happened.
- ## Common Patterns
- You'll often see tools that:
- 1. **Ask First**: Like our search tool confirmation
- 2. **Run Safely**: Protected execution
- 3. **Show Clearly**: Formatted results
- ## What's Next?
- Now you understand how tools get executed safely in your CLI app! In [Chapter 14: Tool Execution](14_tool_execution_.md), we'll explore more advanced execution techniques.
- > Pro Tip: Try adding a confirmation step to a simple tool to see the execution system in action!
- ---
- # Chapter 14: Tool Execution
- Welcome back! In [Chapter 13: Tool Execution System](13_tool_execution_system_.md), we learned how tools get scheduled and managed. Now, let's meet **Tool Execution** - the actual "worker" that runs your CLI tools, like a skilled chef who takes recipes and turns them into delicious meals!
- ## Why Do We Need Tool Execution?
- Imagine you're building a robot helper. You've given it tools (like a screwdriver and a paintbrush), but now you need it to actually *use* those tools when you ask. That's exactly what Tool Execution does:
- 1. Takes a tool request ("Paint the wall blue")
- 2. Gets the right tool (paintbrush)
- 3. Executes the task carefully
- 4. Shows you the beautiful blue wall!
- ## Meet the Simple Execution Flow
- Every tool execution follows these easy steps:
- ```typescript
- // 1. Get the tool you need
- const paintTool = getTool('paintbrush');
- // 2. Use the tool with your instructions
- const result = await paintTool.execute({color: 'blue', wall: 'north'});
- // 3. See what happened!
- console.log(result); // "Painted north wall blue!"
- ```
- This shows the basic flow: find tool → execute → get results.
- ## Behind the Scenes
- When you execute a tool, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Registry as Tool Registry
- participant Tool as The Tool
- You->>Registry: "I need the paintbrush"
- Registry->>Tool: Finds paintbrush tool
- Tool->>Tool: Paints the wall
- Tool-->>You: "Done painting!"
- ```
- ## Two Ways to Run Tools
- Our system offers two execution styles:
- 1. **Interactive Mode**: Asks for confirmation first (like a careful assistant)
- 2. **Non-Interactive Mode**: Runs immediately (like an automatic machine)
- Here's how they differ:
- ```typescript
- // Interactive execution (asks first)
- await runInteractive('paintbrush', {color: 'blue'});
- // Non-interactive (runs right away)
- await runNonInteractive('paintbrush', {color: 'blue'});
- ```
- ## Real-World Execution
- Let's look at how we actually execute tools (from `packages/core/src/core/nonInteractiveToolExecutor.ts`):
- ```typescript
- async function executeTool(toolName, params) {
- // 1. Find the tool
- const tool = getTool(toolName);
- // 2. Run it safely
- try {
- return await tool.execute(params);
- } catch (error) {
- return `Oops! ${error.message}`;
- }
- }
- ```
- Key parts:
- 1. Looks up the tool by name
- 2. Runs it in a protected way
- 3. Handles errors gracefully
- ## Watching Tools Work
- Some tools can even show progress while running:
- ```typescript
- // See live updates from the tool
- await runTool('download', {file: 'cat.jpg'}, (progress) => {
- console.log(`${progress}% downloaded...`);
- });
- ```
- This lets you see the download percentage update in real time!
- ## Common Patterns
- You'll often see tools that:
- 1. **Read Files**: Like our directory lister
- 2. **Modify Content**: Like the file editor
- 3. **Fetch Data**: Like the web searcher
- Each follows the same simple execution pattern.
- ## What's Next?
- Now you understand how tools actually run in your CLI app! In [Chapter 15: File System Operations](15_file_system_operations_.md), we'll explore how tools can safely work with your computer's files.
- > Pro Tip: Try creating a simple tool that counts files in a folder to see execution in action!
- ---
- # Chapter 15: File System Operations
- Welcome back! In [Chapter 14: Tool Execution](14_tool_execution_.md), we learned how tools run in your CLI app. Now, let's meet your app's **digital librarian** - the File System Operations that carefully manage all interactions with your computer's files!
- ## Why Do We Need File Operations?
- Imagine you're organizing a library. You need to:
- 1. Find books (search files)
- 2. Add new books (create files)
- 3. Update old books (edit files)
- 4. Remove outdated books (delete files)
- File System Operations do exactly this for your CLI app! They handle all file interactions safely and efficiently.
- ## Meet the Basic File Operations
- Here are the four main operations you'll use:
- 1. **Reading Files**: Like opening a book to read its contents
- 2. **Writing Files**: Like adding new pages to a notebook
- 3. **Searching Files**: Like looking up books in a catalog
- 4. **Managing Paths**: Like knowing exactly where each book belongs
- ## A Simple Example
- Let's read a file named "notes.txt":
- ```typescript
- import { readFile } from 'gemini-cli';
- const content = await readFile('notes.txt');
- console.log(content); // Shows the file's text
- ```
- This shows how easy it is to:
- 1. Import the file operation
- 2. Read the file
- 3. Use its contents
- ## How File Operations Work
- When you read a file, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant FS as File System
- participant File as Your File
- You->>FS: "Please read notes.txt"
- FS->>File: Finds the file
- File-->>FS: Returns the content
- FS->>You: Gives you the text
- ```
- ## Safety First!
- File operations include important safety checks:
- 1. **Path Validation**: Ensures files are in allowed folders
- 2. **Permission Checks**: Verifies you can access the file
- 3. **Git Ignore**: Respects .gitignore rules automatically
- Here's how we safely write to a file:
- ```typescript
- import { writeFile } from 'gemini-cli';
- await writeFile('diary.txt', 'Dear diary...', {
- safe: true // Enables all safety checks
- });
- ```
- ## Real-World Implementation
- Let's look at how we actually read files (from `packages/core/src/tools/read-file.ts`):
- ```typescript
- async function readFileSafe(path) {
- // 1. Check if path is allowed
- if (!isValidPath(path)) throw Error("Invalid path");
- // 2. Check Git ignore rules
- if (shouldIgnore(path)) return null;
- // 3. Read the file
- return fs.readFile(path);
- }
- ```
- Key safety steps:
- 1. Path validation
- 2. Git ignore check
- 3. Actual file reading
- ## Common Patterns
- You'll often use these file operations together:
- 1. **Search → Read**: Find a file then read it
- 2. **Read → Edit → Write**: Modify a file's content
- 3. **Check → Create**: Make new files safely
- ## What's Next?
- Now you understand how your CLI app works with files safely! In [Chapter 16: File Operations](16_file_operations_.md), we'll explore more advanced ways to handle files.
- > Pro Tip: Try creating a simple note-taking tool that saves and reads from a text file!
- ---
- # Chapter 16: File Operations
- Welcome back! In [Chapter 15: File System Operations](15_file_system_operations_.md), we learned how your CLI app interacts with files. Now, let's meet your app's **digital librarian** - the File Operations that carefully handle all your file reading, writing, and searching needs!
- ## Why Do We Need File Operations?
- Imagine you're organizing your digital bookshelf. You need to:
- 1. Find a book (search files)
- 2. Read a book (read files)
- 3. Add notes to a book (write files)
- 4. Keep everything organized (manage files)
- File Operations do exactly this for your CLI app! They provide safe, easy ways to work with files, just like a librarian helps you manage books.
- ## Meet the Three Main Operations
- Here are the key things you can do:
- 1. **Reading Files**: Like opening a book to read its contents
- 2. **Writing Files**: Like adding new pages to your notebook
- 3. **Searching Files**: Like looking up books in the library catalog
- ## A Simple Example
- Let's read a file named "notes.txt":
- ```typescript
- import { readFile } from 'gemini-cli';
- const content = await readFile('notes.txt');
- console.log(content); // Shows the file's text
- ```
- This simple code:
- 1. Imports the file operation
- 2. Reads the file
- 3. Shows its contents
- ## How File Operations Work
- When you read a file, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant FS as File System
- participant File as Your File
- You->>FS: "Please read notes.txt"
- FS->>File: Finds the file
- File-->>FS: Returns the content
- FS->>You: Gives you the text
- ```
- ## Safety First!
- File operations include important safety checks:
- 1. **Path Validation**: Ensures files are in allowed folders
- 2. **Permission Checks**: Verifies you can access the file
- 3. **Git Ignore**: Respects .gitignore rules automatically
- Here's how we safely write to a file:
- ```typescript
- import { writeFile } from 'gemini-cli';
- await writeFile('diary.txt', 'Dear diary...', {
- safe: true // Enables all safety checks
- });
- ```
- ## Real-World Implementation
- Let's peek at how reading files works internally (simplified from our actual code):
- ```typescript
- async function readFileSafe(path) {
- // 1. Check if path is allowed
- if (!isValidPath(path)) throw Error("Invalid path");
- // 2. Read the file
- return fs.readFile(path);
- }
- ```
- Key safety steps:
- 1. Checks if the path is valid
- 2. Only then reads the file
- ## Common Patterns
- You'll often use these operations together:
- 1. **Search → Read**: Find a file then read it
- 2. **Read → Edit → Write**: Modify a file's content
- 3. **Check → Create**: Make new files safely
- ## What's Next?
- Now you understand how to safely work with files in your CLI app! In [Chapter 17: File Discovery](17_file_discovery_.md), we'll learn how to efficiently find files when you need them.
- > Pro Tip: Try creating a simple note-taking tool that saves and reads from a text file!
- ---
- # Chapter 17: File Discovery
- Welcome back! In [Chapter 16: File Operations](16_file_operations_.md), we learned how to work with individual files. Now, let's meet your CLI app's **smart metal detector** - the File Discovery system that helps find exactly the files you need while automatically skipping the ones you don't!
- ## Why Do We Need File Discovery?
- Imagine you're searching for treasure in your backyard. You wouldn't want your metal detector to beep for every soda can and nail - just the valuable items! File Discovery works similarly:
- 1. It searches through folders to find files
- 2. Automatically skips files listed in `.gitignore` (like temporary files)
- 3. Also respects `.geminiignore` for project-specific exclusions
- 4. Returns only the files you actually care about
- ## Meet the Smart File Finder
- File Discovery has two main jobs:
- 1. **Finding Files**: Locates all files in a folder and its subfolders
- 2. **Filtering Files**: Removes files that should be ignored
- Here's how simple it is to use:
- ```typescript
- import { discoverFiles } from 'gemini-cli';
- // Find all non-ignored files in current folder
- const files = await discoverFiles('.');
- console.log(files); // ["src/index.ts", "README.md", ...]
- ```
- This shows all files in your project, automatically skipping ones listed in `.gitignore` or `.geminiignore`.
- ## How File Discovery Works
- When you search for files, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Finder as File Discovery
- participant Git as .gitignore
- participant Gemini as .geminiignore
- You->>Finder: "Find me files!"
- Finder->>Git: Checks ignore rules
- Git-->>Finder: "Skip these files"
- Finder->>Gemini: Checks ignore rules
- Gemini-->>Finder: "Also skip these"
- Finder->>You: Returns filtered files
- ```
- ## Real-World Usage
- Let's look at how we actually filter files (simplified from our code):
- ```typescript
- function filterFiles(allFiles) {
- return allFiles.filter(file => {
- // Skip if in .gitignore
- if (isGitIgnored(file)) return false;
- // Skip if in .geminiignore
- if (isGeminiIgnored(file)) return false;
- // Otherwise keep it
- return true;
- });
- }
- ```
- Key parts:
- 1. Takes a list of all files
- 2. Checks each against ignore rules
- 3. Returns only non-ignored files
- ## Customizing File Discovery
- You can control how strict the filtering is:
- ```typescript
- // Find files while ignoring .gitignore rules
- const files = await discoverFiles('.', {
- respectGitIgnore: false // Show all files
- });
- ```
- This lets you see everything when you need to, like a metal detector in "show all" mode.
- ## Common Patterns
- You'll often use File Discovery to:
- 1. **Find Source Files**: Locate all `.ts` files for processing
- 2. **List Documentation**: Get all `.md` files for building help
- 3. **Search Projects**: Look for specific file patterns
- ## What's Next?
- Now you understand how to smartly find files in your projects! In [Chapter 18: File Reference Processor](18_file_reference_processor_.md), we'll learn how to work with the files we've discovered.
- > Pro Tip: Try creating a `.geminiignore` file to hide temporary files from your searches!
- ---
- # Chapter 18: File Reference Processor
- Welcome back! In [Chapter 17: File Discovery](17_file_discovery_.md), we learned how to find files in your project. Now, let's meet your CLI's **helpful librarian** - the File Reference Processor that automatically fetches file contents when you mention them with `@` symbols, just like asking a librarian for specific books!
- ## Why Do We Need File References?
- Imagine you're writing an email and want to include a report. Instead of copying the whole document, you might say "See attached: annual_report.pdf". The File Reference Processor does something similar for your CLI:
- 1. You type: `@notes.txt` in your query
- 2. The processor finds and reads the file
- 3. It automatically includes the contents in your request
- This saves you from manually opening and copying files!
- ## Meet the @ Command
- The magic happens when you use `@` before a filename:
- ```typescript
- // Ask about a file's content
- const query = "What does @config.json say about timeout?";
- ```
- The processor will:
- 1. Find `config.json`
- 2. Read its contents
- 3. Include them with your question
- ## How It Works Behind the Scenes
- When you use an `@` reference, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Processor as File Processor
- participant Files as Your Files
- You->>Processor: "Read @notes.txt"
- Processor->>Files: Finds notes.txt
- Files-->>Processor: Returns content
- Processor->>You: Includes text with query
- ```
- ## A Simple Example
- Let's see how to use this in code:
- ```typescript
- import { processQuery } from 'gemini-cli';
- // The processor handles @ automatically
- const response = await processQuery("Explain @example.js");
- ```
- This will:
- 1. Find `example.js`
- 2. Add its code to your question
- 3. Get an explanation from Gemini
- ## Real-World Implementation
- Here's a simplified version of how we process `@` commands:
- ```typescript
- function handleAtCommand(query) {
- // Find all @ references
- const atFiles = query.match(/@(\S+)/g);
- // For each found file
- atFiles.forEach(file => {
- const content = readFile(file.substring(1));
- query += `\nFile ${file} contents:\n${content}`;
- });
- return query;
- }
- ```
- Key steps:
- 1. Finds all `@filename` references
- 2. Reads each file
- 3. Appends contents to the query
- ## Safety First!
- The processor includes important protections:
- 1. Checks file permissions first
- 2. Respects `.gitignore` rules
- 3. Limits file size for safety
- ## What's Next?
- Now you understand how to easily reference files in your queries! In [Chapter 19: Configuration System](19_configuration_system_.md), we'll learn how to customize your CLI's behavior.
- > Pro Tip: Try using `@` with different file types (like `.txt`, `.js`) to see how Gemini responds!
- ---
- # Chapter 19: Configuration System
- Welcome back! In [Chapter 18: File Reference Processor](18_file_reference_processor_.md), we learned how to automatically include file contents in our queries. Now, let's meet your CLI's **personal settings manager** - the Configuration System that remembers all your preferences, just like how your phone remembers your favorite apps and wallpaper!
- ## Why Do We Need Configuration?
- Imagine you're setting up a new video game. You'd want to:
- 1. Save your control preferences
- 2. Remember your graphics settings
- 3. Keep track of your progress
- The Configuration System does exactly this for your CLI app! It stores settings like:
- - Your preferred theme (dark/light mode)
- - Default tools to use
- - Authentication preferences
- ## Meet the Two-Level Settings
- The system organizes settings in two simple layers:
- 1. **User Settings**: Your personal preferences (like your phone's wallpaper)
- 2. **Workspace Settings**: Project-specific rules (like a team's coding standards)
- Here's how simple it is to get a setting:
- ```typescript
- import { getConfig } from 'gemini-cli';
- // Get your theme preference
- const theme = getConfig('theme');
- console.log(theme); // "dark" or "light"
- ```
- This shows how easy it is to access any saved setting.
- ## How Settings Work Together
- When you check a setting, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Config as Config System
- participant User as User Settings
- participant Workspace as Workspace Settings
- You->>Config: "What's my theme?"
- Config->>User: Checks personal settings
- User-->>Config: "dark"
- Config->>Workspace: Checks project settings
- Workspace-->>Config: "light" (overrides)
- Config->>You: "light"
- ```
- Notice how workspace settings can override user settings when needed!
- ## A Simple Example
- Let's set and get a configuration value:
- ```typescript
- import { setConfig, getConfig } from 'gemini-cli';
- // Set a user preference
- setConfig('theme', 'dark', 'user');
- // Later, get the value
- const theme = getConfig('theme');
- console.log(theme); // "dark"
- ```
- This shows the basic flow: set → save → retrieve later.
- ## Real-World Implementation
- Here's how we actually handle settings internally (simplified):
- ```typescript
- class ConfigSystem {
- private userSettings = {};
- private workspaceSettings = {};
- get(key) {
- // Workspace settings override user settings
- return this.workspaceSettings[key] || this.userSettings[key];
- }
- set(key, value, level = 'user') {
- if (level === 'workspace') {
- this.workspaceSettings[key] = value;
- } else {
- this.userSettings[key] = value;
- }
- }
- }
- ```
- Key parts:
- - Simple storage for both setting types
- - Workspace settings take priority
- - Easy get/set methods
- ## Common Patterns
- You'll often use the Configuration System to:
- 1. **Remember Preferences**: Like your favorite theme
- 2. **Set Defaults**: Like which tools to always enable
- 3. **Configure Projects**: Like special rules for certain folders
- ## What's Next?
- Now you understand how your CLI remembers all its settings! In [Chapter 20: Configuration Management](20_configuration_management_.md), we'll learn how to organize and maintain these settings effectively.
- > Pro Tip: Try setting a custom theme preference and see it persist between sessions!
- ---
- # Chapter 20: Configuration Management
- Welcome back! In [Chapter 19: Configuration System](19_configuration_system_.md), we learned how your CLI app stores settings. Now, let's meet your app's **super-organized assistant** - Configuration Management that carefully loads and combines all your preferences from different places, just like a personal assistant who gathers all your notes and reminders into one perfect system!
- ## Why Do We Need Configuration Management?
- Imagine you're planning a party with friends. You might have:
- - Your personal preferences (favorite music)
- - Group decisions (shared budget)
- - Venue rules (noise restrictions)
- Configuration Management does exactly this for your CLI app! It:
- 1. Collects settings from different sources
- 2. Combines them smartly
- 3. Gives you one perfect set of preferences to use
- ## Meet the Three Sources
- Your CLI app gets settings from three main places:
- 1. **User Settings**: Your personal preferences (like your theme choice)
- 2. **Workspace Settings**: Project-specific rules (like team coding standards)
- 3. **Command Line**: Temporary options (like `--debug` mode)
- Here's how simple it is to see merged settings:
- ```typescript
- import { getMergedConfig } from 'gemini-cli';
- // Get all settings combined
- const config = getMergedConfig();
- console.log(config.theme); // Shows your final theme
- ```
- This gives you one complete set of preferences, no matter where they came from!
- ## How Settings Get Merged
- When combining settings, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant User as User Settings
- participant Workspace as Workspace
- participant CLI as Command Line
- You->>CLI: Runs with --debug
- CLI->>User: Gets your preferences
- User->>Workspace: Checks project rules
- Workspace-->>You: Returns final settings
- ```
- Notice how command line options can override other settings!
- ## A Simple Example
- Let's see how settings combine:
- ```typescript
- // User settings: { theme: "dark" }
- // Workspace settings: { theme: "light" }
- const config = getMergedConfig();
- console.log(config.theme); // "light" (workspace wins!)
- ```
- This shows how workspace settings can override your personal ones when needed.
- ## Real-World Implementation
- Here's a peek at how we merge settings (simplified from our code):
- ```typescript
- function mergeSettings(user, workspace, cli) {
- return {
- ...user, // Start with user settings
- ...workspace, // Override with workspace
- ...cli // Finally apply CLI options
- };
- }
- ```
- Key parts:
- 1. Starts with user settings as base
- 2. Adds workspace settings on top
- 3. Finally applies command line options
- ## Common Patterns
- You'll often see Configuration Management:
- 1. **Resolving Conflicts**: Deciding which setting wins
- 2. **Validating Values**: Ensuring settings make sense
- 3. **Providing Defaults**: When no setting exists
- ## What's Next?
- Now you understand how your CLI combines all its settings perfectly! In [Chapter 21: Config Management](21_config_management_.md), we'll learn more advanced ways to work with these configurations.
- > Pro Tip: Try setting different themes in user vs workspace settings to see which one wins!
- ---
- # Chapter 21: Config Management
- Welcome back! In [Chapter 20: Configuration Management](20_configuration_management_.md), we learned how your CLI combines settings from different sources. Now, let's meet your app's **control center** - Config Management that stores and manages all the knobs and dials controlling your CLI's behavior, just like a soundboard that remembers all your favorite settings for different music genres!
- ## Why Do We Need Config Management?
- Imagine you're setting up a new smart home system. You'd want to:
- 1. Save your preferred lighting colors
- 2. Remember your favorite room temperatures
- 3. Keep track of security settings
- Config Management does exactly this for your CLI app! It:
- - Stores all runtime settings in one place
- - Provides easy access to these settings
- - Acts as the single source of truth for how your app behaves
- ## Meet the Settings Dashboard
- Think of Config Management as your CLI's control panel with three main features:
- 1. **Storage**: Safely keeps all settings
- 2. **Access**: Provides settings when needed
- 3. **Validation**: Ensures settings make sense
- Here's how simple it is to get a setting:
- ```typescript
- import { config } from 'gemini-cli';
- // Get the current theme
- const theme = config.get('theme');
- console.log(theme); // "dark" or "light"
- ```
- This shows how easy it is to access any stored setting.
- ## How Config Management Works
- When you request a setting, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Config as Config Management
- participant Storage as Settings Storage
- You->>Config: "What's my theme?"
- Config->>Storage: Looks up value
- Storage-->>Config: Returns "dark"
- Config->>You: Gives you "dark"
- ```
- ## A Simple Example
- Let's set and get a configuration value:
- ```typescript
- // Set the theme to dark mode
- config.set('theme', 'dark');
- // Later, retrieve it
- const currentTheme = config.get('theme');
- console.log(currentTheme); // "dark"
- ```
- This shows the basic flow: store → retrieve → use.
- ## Real-World Implementation
- Here's a peek at how we manage settings internally (simplified):
- ```typescript
- class ConfigManager {
- private settings = new Map();
- set(key, value) {
- this.settings.set(key, value);
- }
- get(key) {
- return this.settings.get(key);
- }
- }
- ```
- Key parts:
- - Uses a `Map` to store settings efficiently
- - Simple methods to get and set values
- - Centralized access point for all settings
- ## Common Settings
- You'll often work with these types of settings:
- 1. **UI Preferences**: Like themes and layouts
- 2. **Tool Configs**: Default tools to use
- 3. **System Settings**: Memory limits and timeouts
- ## What's Next?
- Now you understand how Config Management keeps all your CLI's settings organized! In [Chapter 22: Theme Management System](22_theme_management_system_.md), we'll explore how to customize your CLI's appearance using these settings.
- > Pro Tip: Try setting different theme values and see how they affect your CLI's look!
- ---
- # Chapter 22: Theme Management System
- Welcome back! In [Chapter 21: Config Management](21_config_management_.md), we learned how your CLI app stores all its settings. Now, let's meet your app's **fashion designer** - the Theme Management System that lets you change how your CLI looks, just like changing outfits for different occasions!
- ## Why Do We Need Themes?
- Imagine your favorite app only came in bright white - it would hurt your eyes at night! Themes solve this by letting you:
- - Switch between light/dark modes
- - Change colors to match your style
- - Make code easier to read with proper highlighting
- It's like having a wardrobe manager for your terminal's appearance!
- ## Meet the Theme Basics
- Themes control three main visual elements:
- 1. **Background/Foreground**: Main colors (like dark mode)
- 2. **Accent Colors**: Highlights for important elements
- 3. **Syntax Highlighting**: Colors for code examples
- Here's how simple it is to change themes:
- ```typescript
- import { setTheme } from 'gemini-cli';
- // Switch to dark mode
- setTheme('dark');
- ```
- This one command changes all your CLI's colors instantly!
- ## How Themes Work Together
- When you change themes, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Theme as Theme System
- participant UI as Your CLI
- You->>Theme: "Use dark theme"
- Theme->>UI: Updates all colors
- UI->>You: Shows new dark appearance
- ```
- ## A Simple Example
- Let's see all available themes and pick one:
- ```typescript
- import { getThemes, setTheme } from 'gemini-cli';
- // See all theme options
- const themes = getThemes();
- console.log(themes); // ["dark", "light", "github", "dracula"...]
- // Pick the GitHub theme
- setTheme('github-dark');
- ```
- This shows how easy it is to browse and apply themes.
- ## Real-World Implementation
- Let's peek at how themes are defined (simplified from our code):
- ```typescript
- // A simple theme definition
- const darkTheme = {
- name: "Dark",
- colors: {
- background: "#222",
- text: "#eee",
- accents: {
- blue: "#5af",
- red: "#f55"
- }
- }
- };
- ```
- Key parts:
- - Each theme has a name
- - Defines color groups
- - Simple structure for easy creation
- ## Switching Between Themes
- The system handles theme changes smoothly:
- ```typescript
- function changeTheme(name) {
- // 1. Find the theme
- const theme = findTheme(name);
- // 2. Apply all colors
- applyColors(theme.colors);
- // 3. Update syntax highlighting
- setSyntaxHighlighting(theme);
- }
- ```
- This ensures everything updates together when you switch themes.
- ## Common Theme Patterns
- You'll often work with:
- 1. **Dark/Light Modes**: For day/night usage
- 2. **Code Themes**: Specialized for programming
- 3. **Custom Themes**: Make your own color schemes
- ## What's Next?
- Now you understand how to customize your CLI's appearance with themes! In [Chapter 23: Theme System](23_theme_system_.md), we'll explore how to create and manage your own custom themes.
- > Pro Tip: Try switching themes throughout the day - light for daytime, dark for nighttime!
- ---
- # Chapter 23: Theme System
- Welcome back! In [Chapter 22: Theme Management System](22_theme_management_system_.md), we learned how to switch between different color themes. Now, let's explore the **Theme System** - your CLI's personal artist that paints all the colors and styles you see on screen, just like choosing different color palettes for a painting!
- ## Why Do We Need Themes?
- Imagine your favorite app only came in bright white - it would be hard to use at night! Themes solve this by letting you:
- - Switch between light and dark modes
- - Change colors to match your mood
- - Make text easier to read
- - Create a consistent look across your CLI
- It's like having a magic paintbrush for your terminal!
- ## Meet the Color Palette
- The Theme System organizes colors into simple groups:
- 1. **Main Colors**: Background and text colors
- 2. **Accent Colors**: Highlights for important parts
- 3. **Special Colors**: For code and other special text
- Here's how simple it is to use a theme:
- ```typescript
- import { useTheme } from 'gemini-cli';
- // Use the dark theme
- useTheme('dark');
- ```
- This one command changes all your CLI's colors instantly!
- ## How Themes Work Together
- When you set a theme, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Theme as Theme System
- participant UI as Your CLI
- You->>Theme: "Use dark theme"
- Theme->>UI: Updates all colors
- UI->>You: Shows new dark look
- ```
- ## A Simple Example
- Let's see all available themes and pick one:
- ```typescript
- import { listThemes, setTheme } from 'gemini-cli';
- // See all theme options
- const themes = listThemes();
- console.log(themes); // ["dark", "light", "github", "dracula"...]
- // Pick the Dracula theme
- setTheme('dracula');
- ```
- This shows how easy it is to browse and apply themes.
- ## Inside a Theme Definition
- Themes are defined with simple color objects. Here's part of our dark theme:
- ```typescript
- const darkTheme = {
- background: '#1E1E2E', // Dark background
- text: '#CDD6F4', // Light text
- accents: {
- blue: '#89B4FA', // Pretty blue
- red: '#F38BA8' // Soft red
- }
- };
- ```
- Key parts:
- - Background and text colors
- - Accent colors for highlights
- - Simple structure anyone can understand
- ## Changing Themes
- The system handles theme changes smoothly:
- ```typescript
- function changeTheme(name) {
- // 1. Find the theme colors
- const colors = getThemeColors(name);
- // 2. Update all UI elements
- updateAllColors(colors);
- }
- ```
- This ensures everything updates together when you switch themes.
- ## Common Theme Uses
- You'll often work with:
- 1. **Dark/Light Modes**: For day/night comfort
- 2. **Code Themes**: Special colors for programming
- 3. **Custom Themes**: Make your own color schemes
- ## What's Next?
- Now you understand how to color your CLI with themes! In [Chapter 24: Markdown Rendering Engine](24_markdown_rendering_engine_.md), we'll learn how to display beautiful formatted text in your terminal.
- > Pro Tip: Try creating a custom theme with your favorite colors!
- ---
- # Chapter 24: Markdown Rendering Engine
- Welcome back! In [Chapter 23: Theme System](23_theme_system_.md), we learned how to customize your CLI's colors and appearance. Now, let's meet your app's **document translator** - the Markdown Rendering Engine that turns simple text formatting into beautiful terminal displays, just like magic ink that transforms plain notes into colorful documents!
- ## Why Do We Need Markdown Rendering?
- Imagine you're writing a note in your terminal:
- ```
- # Shopping List
- - Milk
- - Eggs `priority`
- ```
- You want it to look nice with:
- - Big heading for "Shopping List"
- - Bullet points for items
- - Highlighted "priority" tag
- The Markdown Rendering Engine does exactly this! It converts simple symbols (`#`, `-`, `` ` ``) into formatted terminal output.
- ## Meet the Markdown Magic
- Our engine understands these basic markdown elements:
- 1. **Headings**: `# Big Title` becomes large text
- 2. **Lists**: `- Item` becomes bullet points
- 3. **Code**: `` `code` `` gets special highlighting
- 4. **Formatting**: `**bold**` and `*italic*` text
- Here's how simple it is to render markdown:
- ```typescript
- import { renderMarkdown } from 'gemini-cli';
- // Simple markdown text
- const mdText = "# Hello\nThis is **bold** text!";
- // Render it to terminal
- renderMarkdown(mdText);
- ```
- This will display:
- ```
- Hello
- This is bold text!
- ```
- (With "Hello" as a heading and "bold" actually bold)
- ## How Markdown Rendering Works
- When you render markdown, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Engine as Markdown Engine
- participant Terminal as Your Terminal
- You->>Engine: "# Hello"
- Engine->>Engine: Converts to big text
- Engine->>Terminal: Shows formatted text
- Terminal->>You: Displays beautiful heading
- ```
- ## A Simple Example
- Let's render a more complex example:
- ```typescript
- const recipe = `
- ## Chocolate Cake
- Ingredients:
- - 2 cups flour
- - 1 cup sugar
- Steps:
- 1. Mix dry ingredients
- 2. Bake at 350°F
- `;
- renderMarkdown(recipe);
- ```
- This will display with:
- - "Chocolate Cake" as a medium header
- - Bulleted ingredients
- - Numbered steps
- ## Behind the Scenes
- The engine works in three simple steps:
- 1. **Parsing**: Finds all markdown symbols
- 2. **Converting**: Changes them to terminal codes
- 3. **Rendering**: Displays the formatted text
- Here's a peek at the parsing step (simplified):
- ```typescript
- function parseMarkdown(text) {
- // Find headings
- if (text.startsWith('# ')) {
- return { type: 'heading', text: text.substring(2) };
- }
- // Find list items
- if (text.startsWith('- ')) {
- return { type: 'list', text: text.substring(2) };
- }
- }
- ```
- Key parts:
- - Checks for markdown symbols
- - Extracts the actual text
- - Identifies the element type
- ## Handling Complex Cases
- The engine also manages tricky situations:
- - Nested lists
- - Code blocks with syntax highlighting
- - Tables with proper alignment
- ## What's Next?
- Now you understand how to display beautiful formatted text in your terminal! In [Chapter 25: Error Handling Framework](25_error_handling_framework_.md), we'll learn how to gracefully handle when things go wrong.
- > Pro Tip: Try mixing different markdown elements to create rich terminal documents!
- ---
- # Chapter 25: Error Handling Framework
- Welcome back! In [Chapter 24: Markdown Rendering Engine](24_markdown_rendering_engine_.md), we learned how to display beautiful formatted text. Now, let's meet your CLI's **safety net** - the Error Handling Framework that catches problems before they crash your app, just like a trapeze artist's net that ensures they can perform daring tricks safely!
- ## Why Do We Need Error Handling?
- Imagine you're building a bridge out of toy blocks. Sometimes:
- - A block might be missing (API error)
- - The bridge gets too long (rate limit)
- - Someone bumps the table (system crash)
- The Error Handling Framework does three important jobs:
- 1. **Catches** these problems gracefully
- 2. **Explains** what went wrong in simple terms
- 3. **Helps** you fix it or try again
- ## Meet the Three Safety Nets
- Our framework provides different safety nets for different problems:
- 1. **API Errors**: When Gemini's servers have issues
- 2. **Rate Limits**: When you make too many requests too fast
- 3. **System Errors**: When your computer has problems
- Here's how simple it is to catch an error:
- ```typescript
- import { safeRun } from 'gemini-cli';
- // Wrap risky code in safeRun
- const result = await safeRun(() => {
- return fetchData(); // Might fail!
- });
- console.log(result.error?.message); // Friendly explanation
- ```
- ## How Errors Get Handled
- When something goes wrong, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as Your Code
- participant Net as Error Handler
- participant Gemini as Gemini API
- You->>Gemini: Ask a question
- Gemini-->>Net: "Too many requests!"
- Net->>You: "Slow down! Try again later"
- ```
- ## A Simple Example
- Let's handle a rate limit error:
- ```typescript
- try {
- await askGemini("Tell me about space");
- } catch (error) {
- // The framework makes the error message friendly
- console.error(error.message);
- // "You're asking too fast! Wait 1 minute."
- }
- ```
- ## Behind the Scenes
- The framework checks different error types (simplified from our code):
- ```typescript
- function handleError(error) {
- if (error.code === 429) {
- return "Too many requests! Please wait";
- }
- if (error.type === "api") {
- return "Gemini is having trouble right now";
- }
- return "Something unexpected went wrong";
- }
- ```
- Key parts:
- - Checks error codes
- - Returns simple explanations
- - Handles unknown errors safely
- ## Common Error Patterns
- You'll often see:
- 1. **Rate Limits**: "You're asking too fast"
- 2. **API Errors**: "Gemini is unavailable"
- 3. **Network Issues**: "Can't connect to internet"
- Each gets a clear, helpful message.
- ## What's Next?
- Now you understand how your CLI stays stable even when things go wrong! In [Chapter 26: Error Handling System](26_error_handling_system_.md), we'll explore more advanced ways to manage and recover from errors.
- > Pro Tip: Try triggering different errors to see how the framework responds - it's designed to help!
- ---
- # Chapter 26: Error Handling System
- Welcome back! In [Chapter 25: Error Handling Framework](25_error_handling_framework_.md), we learned how to catch basic errors in your CLI app. Now, let's meet your app's **safety inspector** - the Error Handling System that carefully categorizes and manages all types of errors, just like a hospital triage system that sorts patients by how urgently they need care!
- ## Why Do We Need Error Handling?
- Imagine your CLI app is like a busy restaurant. Sometimes things go wrong:
- - The kitchen burns a dish (API error)
- - Too many orders come at once (rate limit)
- - A waiter drops a tray (network issue)
- The Error Handling System helps by:
- 1. **Catching** errors before they crash your app
- 2. **Classifying** them by type (network, auth, etc.)
- 3. **Responding** appropriately for each case
- ## Meet the Error Categories
- Our system organizes errors into three main types:
- 1. **Network Errors**: Connection problems (like WiFi dropping)
- 2. **Auth Errors**: Login issues (wrong password)
- 3. **System Errors**: Computer problems (out of memory)
- Here's how simple it is to handle an error:
- ```typescript
- import { handleError } from 'gemini-cli';
- try {
- // Risky operation that might fail
- await fetchData();
- } catch (error) {
- // The system handles it appropriately
- handleError(error);
- }
- ```
- ## How Errors Get Processed
- When an error occurs, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as Your Code
- participant System as Error System
- participant Display as UI
- You->>System: Error occurs!
- System->>System: Checks error type
- System->>Display: Shows appropriate message
- Display->>You: "Network error - try again?"
- ```
- ## A Simple Example
- Let's see how different errors get handled:
- ```typescript
- try {
- await login(); // Might fail
- } catch (error) {
- // System automatically shows:
- // - "Check your password" for auth errors
- // - "No internet" for network issues
- // - "System busy" for other problems
- handleError(error);
- }
- ```
- ## Behind the Scenes
- The system checks error types like this (simplified):
- ```typescript
- function handleError(error) {
- if (error.message.includes('network')) {
- showNetworkError();
- } else if (error.code === 401) {
- showAuthError();
- } else {
- showGenericError();
- }
- }
- ```
- Key parts:
- - Checks error messages and codes
- - Shows specific messages for each type
- - Has a fallback for unknown errors
- ## Special Network Handling
- The system includes smart retries for network issues:
- ```typescript
- async function fetchWithRetry() {
- let attempts = 0;
- while (attempts < 3) {
- try {
- return await fetchData();
- } catch (error) {
- if (isNetworkError(error)) {
- await wait(1000); // Wait 1 second
- attempts++;
- } else {
- throw error;
- }
- }
- }
- }
- ```
- This automatically retries network errors up to 3 times.
- ## What's Next?
- Now you understand how your CLI gracefully handles all types of errors! In [Chapter 27: Error Reporting](27_error_reporting_.md), we'll learn how to collect and analyze these errors to improve your app.
- > Pro Tip: Try triggering different error types to see how the system responds uniquely to each!
- ---
- # Chapter 27: Error Reporting
- Welcome back! In [Chapter 26: Error Handling System](26_error_handling_system_.md), we learned how to catch and categorize different types of errors. Now, let's meet your CLI's **black box recorder** - the Error Reporting system that carefully saves crash details to help developers fix problems, just like an airplane's black box that helps investigators understand what went wrong!
- ## Why Do We Need Error Reporting?
- Imagine your CLI app is like a car. Sometimes it might stall unexpectedly. Without knowing why, it's hard to fix! Error Reporting helps by:
- 1. Recording what happened when errors occur
- 2. Saving the "crash scene" details
- 3. Helping developers understand and fix issues
- It's like having a detective that investigates every problem automatically!
- ## Meet the Error Report
- When something goes wrong, the system creates a report with:
- 1. **What happened**: The error message
- 2. **Where it happened**: The code location (stack trace)
- 3. **What you were doing**: The context (like your last command)
- Here's how simple it is to generate a report:
- ```typescript
- import { reportError } from 'gemini-cli';
- try {
- // Something that might fail
- riskyOperation();
- } catch (error) {
- // Creates a detailed error report
- reportError(error, "Oops! Something went wrong");
- }
- ```
- This saves all the details developers need to fix the issue.
- ## How Error Reporting Works
- When an error occurs, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as Your Code
- participant Reporter as Error Reporter
- participant File as Report File
- You->>Reporter: Error occurred!
- Reporter->>Reporter: Gathers details
- Reporter->>File: Saves report
- Reporter->>You: "Report saved at /tmp/error123.json"
- ```
- ## A Simple Example
- Let's see what a saved report looks like:
- ```typescript
- // Sample error report contents
- {
- "error": {
- "message": "Network timeout",
- "stack": "at fetchData (client.js:12:3)..."
- },
- "context": {
- "lastCommand": "search pizza places",
- "time": "2024-02-20T14:30:00Z"
- }
- }
- ```
- Key parts:
- - Clear error message
- - Exact code location
- - What you were doing
- ## Behind the Scenes
- The reporter works in three simple steps (simplified from our code):
- ```typescript
- async function reportError(error) {
- // 1. Create timestamp for unique filename
- const timestamp = new Date().toISOString();
- // 2. Gather error details
- const report = {
- message: error.message,
- stack: error.stack
- };
- // 3. Save to temporary file
- await saveReport(`error-${timestamp}.json`, report);
- }
- ```
- Key features:
- - Unique filenames prevent overwrites
- - Includes both message and technical details
- - Saves to a safe temporary location
- ## Reading Error Reports
- Developers can then use these reports to fix issues:
- ```typescript
- // Later, developers can read reports
- const report = await readReport('error-2024-02-20.json');
- console.log(report.message); // "Network timeout"
- ```
- This helps them understand exactly what went wrong.
- ## What's Next?
- Now you understand how your CLI automatically documents problems! In [Chapter 28: Telemetry System](28_telemetry_system_.md), we'll learn how your app collects usage data to improve performance.
- > Pro Tip: Try triggering an error in your CLI and check your temp folder for the generated report!
- ---
- # Chapter 28: Telemetry System
- Welcome back! In [Chapter 27: Error Reporting](27_error_reporting_.md), we learned how your CLI documents problems when they occur. Now, let's meet your app's **flight recorder** - the Telemetry System that quietly tracks important usage information to help improve the CLI, just like an airplane's black box that records flight data!
- ## Why Do We Need Telemetry?
- Imagine you're training for a marathon. You'd want to track:
- - How far you run each day
- - Your average speed
- - When you take breaks
- Telemetry does exactly this for your CLI app! It automatically collects:
- - Which commands are used most
- - How long operations take
- - Any errors that occur
- - Basic usage patterns (without personal data)
- This helps developers understand how people use the CLI and improve it over time.
- ## Meet the Simple Telemetry Flow
- The telemetry system works in three easy steps:
- 1. **Collect**: Gathers usage data as you work
- 2. **Process**: Organizes the information
- 3. **Report**: Sends anonymous summaries to help improve the CLI
- Here's how simple it is to check if telemetry is enabled:
- ```typescript
- import { isTelemetryEnabled } from 'gemini-cli';
- console.log(isTelemetryEnabled()); // true or false
- ```
- This shows whether anonymous usage reporting is active.
- ## How Telemetry Works
- When you use the CLI, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Telemetry as Telemetry System
- You->>CLI: Runs a command
- CLI->>Telemetry: Records basic usage
- Telemetry->>Telemetry: Processes data
- Telemetry-->>Developers: Sends anonymous reports
- ```
- ## A Simple Example
- Let's see what data might be collected:
- ```typescript
- // Sample telemetry data for a search command
- {
- command: "search",
- duration: 1200, // milliseconds
- success: true,
- toolsUsed: ["web-search"]
- }
- ```
- This shows basic info about what happened, without any personal details.
- ## Behind the Scenes
- The telemetry system carefully organizes different types of data (simplified from our code):
- ```typescript
- class Telemetry {
- private events = [];
- record(event) {
- // Remove any personal data first
- const cleanEvent = removePersonalData(event);
- this.events.push(cleanEvent);
- }
- sendReport() {
- // Send anonymous data periodically
- sendToServer(this.events);
- }
- }
- ```
- Key parts:
- 1. Cleans data to remove personal info
- 2. Stores events temporarily
- 3. Sends anonymous reports
- ## What Data Is Collected?
- The system tracks only helpful technical information:
- - Command names (like "search" or "ask")
- - Performance metrics (how long things take)
- - Error types (without personal details)
- - Basic system info (like OS version)
- ## Controlling Telemetry
- You can always check or change telemetry settings:
- ```typescript
- import { getTelemetryConfig, setTelemetryEnabled } from 'gemini-cli';
- // See current settings
- console.log(getTelemetryConfig());
- // Disable if preferred
- setTelemetryEnabled(false);
- ```
- ## What's Next?
- Now you understand how your CLI collects anonymous usage data to improve! In [Chapter 29: Telemetry Service](29_telemetry_service_.md), we'll explore how this data gets processed and used to make the CLI better.
- > Pro Tip: Try checking your telemetry settings to see how the system works!
- ---
- # Chapter 29: Telemetry Service
- Welcome back! In [Chapter 28: Telemetry System](28_telemetry_system_.md), we learned how your CLI collects anonymous usage data. Now, let's meet your app's **dashboard display** - the Telemetry Service that organizes and shows these metrics, just like your car's dashboard that shows speed, fuel level, and engine stats!
- ## Why Do We Need a Telemetry Service?
- Imagine driving a car with no dashboard. You wouldn't know:
- - How fast you're going
- - How much fuel remains
- - If the engine is overheating
- The Telemetry Service solves this for your CLI by:
- 1. Tracking important metrics (like API calls and tool usage)
- 2. Organizing the data clearly
- 3. Making it available for display or analysis
- ## Meet the Dashboard Metrics
- The service tracks three main categories:
- 1. **API Calls**: How often you talk to Gemini
- 2. **Tool Usage**: Which tools you run and how long they take
- 3. **Token Counts**: How many "words" Gemini processes
- Here's how simple it is to check your session stats:
- ```typescript
- import { telemetry } from 'gemini-cli';
- // Get current usage stats
- const stats = telemetry.getMetrics();
- console.log(stats.api.totalRequests); // Number of API calls
- ```
- ## How Telemetry Works
- When you use the CLI, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Telemetry as Telemetry Service
- You->>CLI: Runs a command
- CLI->>Telemetry: Records the action
- Telemetry->>Telemetry: Updates metrics
- CLI->>You: Shows command results
- ```
- ## A Simple Example
- Let's see what typical metrics look like:
- ```typescript
- // Sample telemetry output
- {
- api: {
- totalRequests: 42,
- totalErrors: 2,
- averageLatency: 1200 // ms
- },
- tools: {
- search: { calls: 10, success: 9 },
- edit: { calls: 5, success: 5 }
- }
- }
- ```
- This shows how many times you've used different features and how well they worked.
- ## Behind the Scenes
- The service carefully counts each event (simplified from our code):
- ```typescript
- class TelemetryService {
- private metrics = {
- api: { calls: 0, errors: 0 },
- tools: {}
- };
- recordApiCall() {
- this.metrics.api.calls++;
- }
- recordToolUse(toolName) {
- if (!this.metrics.tools[toolName]) {
- this.metrics.tools[toolName] = 0;
- }
- this.metrics.tools[toolName]++;
- }
- }
- ```
- Key parts:
- - Simple counters for each metric
- - Automatic initialization of new tools
- - Easy-to-read structure
- ## Viewing Your Metrics
- You can check your stats anytime:
- ```typescript
- // See tool usage counts
- const toolCounts = telemetry.getToolCounts();
- console.log(`You've used search ${toolCounts.search} times!`);
- ```
- This helps you understand your own usage patterns.
- ## What's Next?
- Now you understand how your CLI tracks and organizes usage metrics! In [Chapter 30: Session Statistics](30_session_statistics_.md), we'll learn how to analyze this data across multiple CLI sessions.
- > Pro Tip: Try checking your telemetry metrics after running different commands to see how they're tracked!
- ---
- # Chapter 30: Session Statistics
- Welcome back! In [Chapter 29: Telemetry Service](29_telemetry_service_.md), we learned how your CLI tracks usage metrics. Now, let's meet your app's **personal dashboard** - Session Statistics that show real-time insights about your current conversation, just like a car's dashboard that displays your speed, fuel level, and trip distance!
- ## Why Do We Need Session Stats?
- Imagine you're having a long conversation with Gemini. You might wonder:
- - How many questions have I asked?
- - Which tools were used most?
- - How long has this session been active?
- Session Statistics answer these questions by showing:
- - Tool usage counts
- - Model call metrics
- - Performance timings
- - Success/failure rates
- All in a beautiful terminal dashboard!
- ## Meet Your Session Dashboard
- The stats system tracks three main categories:
- 1. **Tool Usage**: Which tools ran and how often
- 2. **Model Calls**: How many API requests were made
- 3. **Performance**: How long operations took
- Here's how simple it is to view your stats:
- ```typescript
- import { showStats } from 'gemini-cli';
- // Display current session statistics
- showStats();
- ```
- This shows a colorful dashboard in your terminal with all the key metrics.
- ## How Stats Get Tracked
- When you use the CLI, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Stats as Stats System
- You->>CLI: Runs a command
- CLI->>Stats: Records the action
- Stats->>Stats: Updates counters
- CLI->>You: Shows command results
- ```
- ## A Simple Example
- Let's see what typical stats look like:
- ```typescript
- // Sample stats output
- {
- tools: {
- search: { calls: 5, success: 4 },
- edit: { calls: 2, success: 2 }
- },
- models: {
- 'gemini-pro': { calls: 7, tokens: 1200 }
- },
- duration: "15 minutes"
- }
- ```
- This shows you've used the search tool 5 times and made 7 model calls.
- ## Behind the Scenes
- The stats system carefully counts each event (simplified from our code):
- ```typescript
- class SessionStats {
- private tools = {};
- private models = {};
- recordToolUse(toolName) {
- if (!this.tools[toolName]) {
- this.tools[toolName] = 0;
- }
- this.tools[toolName]++;
- }
- }
- ```
- Key parts:
- - Simple counters for each metric
- - Automatic initialization of new tools/models
- - Easy-to-read structure
- ## Viewing Your Dashboard
- The stats dashboard shows information in clear sections:
- 1. **Tool Usage**: Success/failure counts
- 2. **Model Calls**: API request details
- 3. **Performance**: Time spent on different tasks
- You can access detailed views too:
- ```typescript
- // Show tool-specific stats
- showToolStats();
- // Show model-specific stats
- showModelStats();
- ```
- ## Common Patterns
- You'll often check stats to:
- 1. **Monitor Usage**: See which tools you use most
- 2. **Debug Issues**: Find failing operations
- 3. **Optimize Performance**: Identify slow commands
- ## What's Next?
- Now you understand how to track your CLI usage with Session Statistics! In [Chapter 31: Conversation Management](31_conversation_management_.md), we'll learn how your CLI maintains context across multiple questions and answers.
- > Pro Tip: Try running different commands and check your stats after each to see them update in real-time!
- ---
- # Chapter 31: Conversation Management
- Welcome back! In [Chapter 30: Session Statistics](30_session_statistics_.md), we learned how to track our CLI usage. Now, let's meet your app's **conversation referee** - Conversation Management that decides who gets to speak next in your chat with Gemini, just like a moderator in a discussion who says "Now it's your turn to speak!"
- ## Why Do We Need Conversation Management?
- Imagine you're playing ping-pong with a friend. The ball goes back and forth:
- - You serve (ask a question)
- - Friend returns (Gemini answers)
- - You hit back (follow-up question)
- Conversation Management is like the unspoken rules that decide:
- 1. When it's your turn to speak
- 2. When Gemini should continue talking
- 3. When the conversation naturally pauses
- Without this, you might both talk at once or sit in awkward silence!
- ## Meet the Turn-Taking Rules
- The system follows three simple rules to decide who speaks next:
- 1. **Gemini Continues**: If Gemini says "Now I'll analyze this..."
- 2. **Your Turn**: If Gemini asks you a direct question
- 3. **Natural Pause**: If Gemini finishes a thought and waits for you
- Here's how simple it is to check:
- ```typescript
- import { checkNextSpeaker } from 'gemini-cli';
- // After Gemini responds, check who goes next
- const next = await checkNextSpeaker();
- console.log(next); // { speaker: "user", reason: "Asked you a question" }
- ```
- ## How Turn-Taking Works
- When deciding who speaks next, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Check as Turn Checker
- participant Gemini as Gemini
- You->>Gemini: Ask a question
- Gemini->>You: Responds
- You->>Check: Who speaks next?
- Check->>Gemini: Analyzes last message
- Gemini-->>Check: "user should speak"
- Check->>You: "Your turn!"
- ```
- ## A Simple Example
- Let's see how different responses affect turn-taking:
- ```typescript
- // Case 1: Gemini asks a question
- const response1 = "What do you think about this idea?";
- const next1 = await checkNextSpeaker(response1);
- console.log(next1.speaker); // "user" (because you were asked)
- // Case 2: Gemini continues working
- const response2 = "Now I'll analyze the data...";
- const next2 = await checkNextSpeaker(response2);
- console.log(next2.speaker); // "model" (because Gemini is working)
- ```
- ## Behind the Scenes
- The system analyzes Gemini's last message (simplified from our code):
- ```typescript
- function decideNextSpeaker(lastMessage) {
- if (lastMessage.includes("I'll") || lastMessage.includes("Now I")) {
- return "model"; // Gemini is continuing
- }
- if (lastMessage.endsWith("?")) {
- return "user"; // Asked you a question
- }
- return "user"; // Default to your turn
- }
- ```
- Key parts:
- - Looks for continuing phrases
- - Checks for questions
- - Defaults to user's turn
- ## Handling Special Cases
- The system also manages tricky situations:
- - When Gemini calls tools automatically
- - When responses get cut off
- - When no clear turn signal exists
- ## What's Next?
- Now you understand how your CLI manages conversation flow! In [Chapter 32: Chat Session](32_chat_session_.md), we'll explore how your entire conversation history is maintained.
- > Pro Tip: Try asking Gemini different types of questions to see how the turn-taking changes!
- ---
- # Chapter 32: Chat Session
- Welcome back! In [Chapter 31: Conversation Management](31_conversation_management_.md), we learned how your CLI decides who speaks next in a conversation. Now, let's meet your app's **memory keeper** - the Chat Session that remembers everything you and Gemini discuss, just like a notebook that keeps all your thoughts and ideas in one place!
- ## Why Do We Need Chat Sessions?
- Imagine you're having a long conversation with a friend about planning a trip. You wouldn't want to:
- - Repeat yourself constantly
- - Forget what you've already discussed
- - Lose track of important details
- The Chat Session solves this by:
- 1. Remembering your entire conversation history
- 2. Keeping track of who said what
- 3. Managing long discussions efficiently
- ## Meet Your Conversation Notebook
- A Chat Session is like a digital notebook with three key features:
- 1. **Message History**: Records every question and answer
- 2. **Context Management**: Keeps the conversation flowing naturally
- 3. **Memory Optimization**: Handles long chats smartly
- Here's how simple it is to start a new session:
- ```typescript
- import { createChatSession } from 'gemini-cli';
- // Start a new conversation
- const chat = createChatSession();
- ```
- This creates a fresh session ready for your first message.
- ## How Chat Sessions Work
- When you chat with Gemini, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Session as Chat Session
- participant Gemini as Gemini
- You->>Session: "What's 2+2?"
- Session->>Gemini: Sends question + history
- Gemini-->>Session: Returns "4"
- Session->>You: Shows answer
- Session->>Session: Saves both messages
- ```
- ## A Simple Example
- Let's have a short conversation:
- ```typescript
- // First question
- await chat.sendMessage("Hi Gemini!");
- // Gemini responds: "Hello! How can I help?"
- // Follow-up question
- await chat.sendMessage("What's 2+2?");
- // Gemini remembers the context and responds: "4"
- ```
- The session automatically keeps track of both messages in order.
- ## Behind the Scenes
- The session stores messages in a simple list (simplified from our code):
- ```typescript
- class ChatSession {
- private history = [];
- addMessage(role, text) {
- this.history.push({ role, text });
- }
- getHistory() {
- return [...this.history]; // Return a copy
- }
- }
- ```
- Key parts:
- - `history` array stores all messages
- - `role` tracks who spoke (user or model)
- - Methods to add and retrieve messages
- ## Handling Long Conversations
- For very long chats, the session automatically:
- 1. **Summarizes** old messages when needed
- 2. **Removes** less important parts
- 3. **Keeps** key context intact
- This ensures Gemini always has relevant context without getting overwhelmed.
- ## Common Patterns
- You'll often use chat sessions to:
- 1. **Continue Discussions**: Pick up where you left off
- 2. **Review History**: See past conversations
- 3. **Start Fresh**: Clear the history when needed
- ## What's Next?
- Now you understand how your CLI maintains complete conversation histories! In [Chapter 33: Conversation Turn](33_conversation_turn_.md), we'll explore how individual messages are structured within these sessions.
- > Pro Tip: Try asking follow-up questions in a chat session to see how it maintains context!
- ---
- # Chapter 33: Conversation Turn
- Welcome back! In [Chapter 32: Chat Session](32_chat_session_.md), we learned how your CLI remembers entire conversations. Now, let's zoom in to examine a **Conversation Turn** - the basic building block of your chat, like a single back-and-forth in a ping-pong match!
- ## Why Do We Need Conversation Turns?
- Imagine you're playing catch with a friend:
- 1. You throw the ball (your message)
- 2. Friend catches and throws back (Gemini's response)
- 3. You catch and prepare to throw again (your next move)
- Each throw and catch is one "turn." The Conversation Turn system manages these individual exchanges by:
- - Tracking who "has the ball" (whose turn it is to speak)
- - Handling any tools that need to run between turns
- - Managing errors if the ball gets dropped
- ## Meet the Simple Turn Structure
- Every conversation turn has three main parts:
- 1. **Input**: Your message or question
- 2. **Processing**: Gemini thinking or running tools
- 3. **Output**: Gemini's response or result
- Here's how simple it is to create a turn:
- ```typescript
- import { createTurn } from 'gemini-cli';
- // Start a new turn with your message
- const turn = createTurn("What's 2+2?");
- ```
- This creates a turn ready to process your question.
- ## How Turns Work Together
- When you send a message, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Turn as Conversation Turn
- participant Gemini as Gemini
- You->>Turn: "What's 2+2?"
- Turn->>Gemini: Sends question
- Gemini-->>Turn: Returns "4"
- Turn->>You: Shows answer
- ```
- ## A Simple Example
- Let's see a complete turn in action:
- ```typescript
- // Create and run a turn
- const turn = createTurn("Hello Gemini!");
- const response = await turn.run();
- console.log(response); // "Hello! How can I help?"
- ```
- This shows the basic flow: create turn → run it → get response.
- ## Behind the Scenes
- The turn manages several important tasks (simplified from our code):
- ```typescript
- class ConversationTurn {
- constructor(private message: string) {}
- async run() {
- // 1. Send the message to Gemini
- const response = await sendToGemini(this.message);
- // 2. Check if tools need to run
- if (response.needsTool) {
- await runTools(response.tools);
- }
- // 3. Return the final answer
- return response.answer;
- }
- }
- ```
- Key parts:
- 1. Sends your message
- 2. Handles any required tools
- 3. Returns the final response
- ## Handling Special Cases
- Turns also manage tricky situations:
- - When Gemini needs to run tools before responding
- - When responses come in multiple parts
- - When errors occur during processing
- ## What's Next?
- Now you understand how individual conversation turns work! In [Chapter 34: System Prompts](34_system_prompts_.md), we'll learn how to guide Gemini's behavior with special instructions.
- > Pro Tip: Try creating turns with different types of questions to see how they're processed!
- ---
- # Chapter 34: System Prompts
- Welcome back! In [Chapter 33: Conversation Turn](33_conversation_turn_.md), we learned how individual messages work in your CLI conversations. Now, let's meet your app's **instruction manual** - System Prompts that guide Gemini's behavior, like a coach giving an athlete clear directions before a big game!
- ## Why Do We Need System Prompts?
- Imagine you're teaching a new assistant how to help with coding. You'd want to explain:
- - How to write clean code
- - When to ask for help
- - What rules to always follow
- System Prompts do exactly this for Gemini! They contain all the instructions that shape how Gemini:
- - Responds to your questions
- - Uses tools safely
- - Follows coding best practices
- ## Meet the Instruction Manual
- Think of System Prompts as a rulebook with three main sections:
- 1. **Core Rules**: Always follow project conventions
- 2. **Safety Checks**: Explain risky commands first
- 3. **Workflows**: Step-by-step plans for common tasks
- Here's a tiny example of what a system prompt might say:
- ```typescript
- // Simplified system prompt
- const instructions = `
- 1. Always check existing code first
- 2. Explain risky commands
- 3. Keep responses short
- `;
- ```
- ## How System Prompts Work
- When you ask a question, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Gemini as Gemini
- participant Prompts as System Prompts
- You->>Gemini: "How do I fix this bug?"
- Gemini->>Prompts: Checks the rules
- Prompts-->>Gemini: "First analyze the code..."
- Gemini->>You: "I'll check the code first"
- ```
- ## A Simple Example
- Let's see how prompts affect responses:
- ```typescript
- // Without system prompt
- User: "Delete all temp files"
- Gemini: "Okay, deleting files..."
- // With system prompt
- User: "Delete all temp files"
- Gemini: "This will permanently delete files. Continue?"
- ```
- The system prompt adds important safety checks!
- ## Behind the Scenes
- The system loads prompts from special files (simplified from our code):
- ```typescript
- function loadSystemPrompt() {
- // Check for custom instructions
- if (fs.existsSync('system.md')) {
- return fs.readFileSync('system.md', 'utf8');
- }
- // Use default instructions
- return defaultInstructions;
- }
- ```
- Key parts:
- 1. Looks for custom instructions
- 2. Falls back to defaults
- 3. Makes them available to Gemini
- ## Customizing Prompts
- You can create your own `system.md` file to change behavior:
- ```markdown
- # My Custom Rules
- - Prefer Python over JavaScript
- - Always explain changes
- - Use emojis in responses 😊
- ```
- This lets you personalize how Gemini works for you!
- ## Common Prompt Uses
- You'll often customize prompts to:
- 1. **Match Team Style**: Follow your coding conventions
- 2. **Add Safety**: Extra confirmation steps
- 3. **Change Tone**: More formal or casual responses
- ## What's Next?
- Now you understand how System Prompts guide Gemini's behavior! In [Chapter 35: Input Handling](35_input_handling_.md), we'll learn how your CLI processes what you type.
- > Pro Tip: Try creating a simple `system.md` file to see how it changes Gemini's responses!
- ---
- # Chapter 35: Input Handling
- Welcome back! In [Chapter 34: System Prompts](34_system_prompts_.md), we learned how to guide Gemini's behavior with special instructions. Now, let's meet your CLI's **keyboard wizard** - Input Handling that manages everything you type, from simple commands to complex queries, just like a skilled translator converting your thoughts into actions!
- ## Why Do We Need Input Handling?
- Imagine you're playing a piano with special keys that can:
- - Remember songs you've played before (history)
- - Suggest next notes as you play (autocomplete)
- - Switch between piano and organ modes (shell toggling)
- Input Handling does exactly this for your CLI! It transforms your keystrokes into meaningful actions by:
- 1. Remembering past commands (history)
- 2. Predicting what you might type next (autocomplete)
- 3. Switching between chat and shell modes
- ## Meet the Three Magic Features
- Our input system offers three helpful tools:
- 1. **Command History**: Press up/down to cycle through past commands
- 2. **Smart Suggestions**: Get autocomplete as you type
- 3. **Mode Switching**: Toggle between chat and shell with `!`
- Here's how simple it is to use:
- ```typescript
- // When you type "hel" and press Tab
- > hel
- // The system suggests:
- > hello
- ```
- ## How Input Handling Works
- When you press a key, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Keyboard as Keyboard Input
- participant Handler as Input Handler
- participant Gemini as Gemini
- You->>Keyboard: Presses "H"
- Keyboard->>Handler: "H received"
- Handler->>Handler: Updates command line
- Handler->>You: Shows "H" on screen
- ```
- ## A Simple Example
- Let's see history in action:
- 1. You type: `ask about weather`
- 2. Later, press ↑ (up arrow)
- 3. Your previous command reappears!
- ```typescript
- // After typing some commands
- > ask about weather
- > list files
- // Press up arrow
- > list files [from history]
- ```
- ## Behind the Scenes
- The input handler manages three key parts (simplified):
- ```typescript
- class InputHandler {
- private history = [];
- private currentInput = "";
- handleKey(key) {
- if (key === "Up") return this.showHistory();
- if (key === "Tab") return this.autocomplete();
- this.currentInput += key;
- }
- }
- ```
- Key parts:
- - `history` stores past commands
- - `currentInput` tracks what you're typing
- - Special keys trigger different features
- ## Smart Suggestions
- When you type `@file`, the system suggests matching files:
- ```typescript
- // You type:
- > @src/
- // System suggests:
- > @src/index.ts
- > @src/utils.js
- ```
- This makes referencing files super easy!
- ## Switching Modes
- Press `!` to toggle between chat and shell modes:
- ```typescript
- // In chat mode
- > ask about weather
- // Press !
- ! ls -la # Now in shell mode
- ```
- The border color changes to show which mode is active.
- ## What's Next?
- Now you understand how your CLI expertly handles all your input! In [Chapter 36: Interactive Shell Utilities](36_interactive_shell_utilities_.md), we'll explore the powerful tools available in shell mode.
- > Pro Tip: Try pressing Tab after typing part of a filename to see autocomplete in action!
- ---
- # Chapter 36: Interactive Shell Utilities
- Welcome back! In [Chapter 35: Input Handling](35_input_handling_.md), we learned how your CLI processes what you type. Now, let's meet your terminal's **helpful concierge** - Interactive Shell Utilities that make command-line work feel like a luxury hotel stay, complete with witty loading messages and smart suggestions!
- ## Why Do We Need Shell Utilities?
- Imagine you're checking into a fancy hotel. The concierge:
- - Remembers your past stays (command history)
- - Anticipates your needs (autocomplete)
- - Entertains you while you wait (witty loading messages)
- Our Interactive Shell Utilities do exactly this for your CLI! They provide:
- 1. **Command History**: Cycle through past commands with up/down arrows
- 2. **Smart Suggestions**: Get file and command autocomplete with Tab
- 3. **Loading Entertainment**: Fun messages while waiting for responses
- ## Meet Your Terminal Concierge
- Let's explore the three main services:
- ### 1. Command History - Your Personal Butler
- Press ↑/↓ to cycle through past commands, just like asking the butler to recall your previous requests.
- ```typescript
- // After running these commands:
- > ask about weather
- > list files
- // Press ↑ to see:
- > list files
- ```
- ### 2. Smart Suggestions - The Anticipatory Assistant
- Start typing a file path with `@` or a command with `/`, then press Tab for suggestions:
- ```typescript
- // Type @src/ then Tab to see:
- @src/index.ts
- @src/utils.js
- ```
- ### 3. Loading Messages - The Hotel Entertainer
- While waiting for responses, enjoy witty phrases like:
- ```
- "Shipping awesomeness..."
- "Counting electrons..."
- "Consulting the digital spirits..."
- ```
- ## How It Works Behind the Scenes
- When you press a key, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Keyboard as Keyboard
- participant History as Command History
- participant Suggest as Suggestions
- You->>Keyboard: Presses ↑
- Keyboard->>History: "Get previous command"
- History-->>Keyboard: "list files"
- Keyboard->>You: Shows past command
- ```
- ## A Simple Implementation
- Here's how command history works (simplified):
- ```typescript
- class CommandHistory {
- private history = [];
- add(command) {
- this.history.push(command);
- }
- getPrevious() {
- return this.history[historyIndex--];
- }
- }
- ```
- This stores commands and lets you navigate them.
- ## Customizing Your Experience
- You can personalize the loading messages by modifying the phrases list:
- ```typescript
- const CUSTOM_PHRASES = [
- "Brewing your coffee...",
- "Training the AI hamsters...",
- "Almost there!"
- ];
- ```
- ## What's Next?
- Now you understand how Interactive Shell Utilities make your CLI experience delightful! In [Chapter 37: Shell Command Execution](37_shell_command_execution_.md), we'll learn how your CLI actually runs the commands you enter.
- > Pro Tip: Try pressing Tab after `@` to discover files in your project!
- ---
- # Chapter 37: Shell Command Execution
- Welcome back! In [Chapter 36: Interactive Shell Utilities](36_interactive_shell_utilities_.md), we learned how your CLI makes command-line work more enjoyable. Now, let's meet your app's **command runner** - Shell Command Execution that safely runs terminal commands for you, like a trustworthy assistant who follows your instructions carefully and reports back with the results!
- ## Why Do We Need Shell Command Execution?
- Imagine you're teaching a new assistant how to help with computer tasks. You'd want them to:
- 1. Run commands exactly as you say
- 2. Show you the results clearly
- 3. Stop immediately if something goes wrong
- Shell Command Execution does exactly this! When you type commands like `ls` or `git status`, it:
- - Runs them in the correct folder
- - Captures all output (success or errors)
- - Lets you cancel if needed
- - Shows results in a readable way
- ## Meet the Command Runner
- Our command runner has three main jobs:
- 1. **Execution**: Runs commands safely
- 2. **Output Handling**: Captures and displays results
- 3. **Control**: Lets you stop commands mid-run
- Here's how simple it is to run a command:
- ```typescript
- import { runCommand } from 'gemini-cli';
- // Run 'ls' to list files
- const result = await runCommand('ls');
- console.log(result.output); // Shows file list
- ```
- This runs the command and gives you the output.
- ## How Command Execution Works
- When you run a command, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Runner as Command Runner
- participant Terminal as Your Terminal
- You->>Runner: "Run ls"
- Runner->>Terminal: Executes command
- Terminal-->>Runner: Returns file list
- Runner->>You: Shows results
- ```
- ## A Simple Example
- Let's see a complete command execution:
- ```typescript
- // Run a command and handle results
- const { output, error } = await runCommand('pwd');
- if (error) {
- console.error('Oops:', error);
- } else {
- console.log('Current folder:', output);
- }
- ```
- This shows the current working directory or any errors.
- ## Behind the Scenes
- The runner handles commands carefully (simplified from our code):
- ```typescript
- async function runCommand(command) {
- // 1. Start the command
- const process = startProcess(command);
- // 2. Collect output
- let output = '';
- process.stdout.on('data', (data) => {
- output += data;
- });
- // 3. Wait for completion
- await process.completion;
- return { output };
- }
- ```
- Key steps:
- 1. Starts the command
- 2. Collects output as it comes
- 3. Returns everything when done
- ## Safety Features
- The runner includes important protections:
- - Timeouts for long-running commands
- - Binary output detection
- - Proper error handling
- ```typescript
- // Run with timeout
- await runCommand('long-task', { timeout: 5000 });
- // Cancels after 5 seconds
- ```
- ## Common Patterns
- You'll often use command execution to:
- 1. **Check System Info**: Like `node --version`
- 2. **Run Build Tools**: Like `npm install`
- 3. **Manage Files**: Like `ls` or `cat`
- ## What's Next?
- Now you understand how your CLI safely runs terminal commands! In [Chapter 38: Shell Execution](38_shell_execution_.md), we'll explore more advanced ways to work with the shell.
- > Pro Tip: Try running simple commands like `date` or `whoami` to see the execution system in action!
- ---
- # Chapter 38: Shell Execution
- Welcome back! In [Chapter 37: Shell Command Execution](37_shell_command_execution_.md), we learned how your CLI runs terminal commands. Now, let's meet your app's **security guard** - Shell Execution that carefully checks permissions before running any system commands, like a bouncer who verifies IDs before letting anyone into a club!
- ## Why Do We Need Shell Execution?
- Imagine you're building a robot assistant that can run commands on your computer. You wouldn't want it to:
- - Delete important files by accident
- - Run dangerous commands without asking
- - Access private folders without permission
- Shell Execution solves this by:
- 1. Checking if commands are allowed (like a security checklist)
- 2. Asking for confirmation on risky operations
- 3. Running commands in a safe environment
- ## Meet the Command Checker
- Shell Execution works like a careful assistant with three rules:
- 1. **Permission Check**: Is this command allowed?
- 2. **Confirmation**: Should we really run this?
- 3. **Safe Execution**: Run it carefully and watch for problems
- Here's how simple it is to run a safe command:
- ```typescript
- import { safeShell } from 'gemini-cli';
- // Try to list files
- const result = await safeShell('ls');
- console.log(result); // Shows files or error if blocked
- ```
- This runs `ls` only if it passes all safety checks!
- ## How Shell Execution Works
- When you run a command, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Guard as Security Guard
- participant Shell as Terminal
- You->>Guard: "Run ls"
- Guard->>Guard: Checks if allowed
- Guard->>Shell: Runs only if safe
- Shell-->>Guard: Returns results
- Guard->>You: Shows output or error
- ```
- ## A Simple Example
- Let's see permission checks in action:
- ```typescript
- // Safe command
- await safeShell('date'); // Shows current date
- // Dangerous command (blocked)
- await safeShell('rm *'); // Error: Command not allowed
- ```
- The system automatically blocks risky commands like file deletion.
- ## Behind the Scenes
- The security check looks like this (simplified):
- ```typescript
- function isAllowed(command) {
- const blocked = ['rm', 'format', 'shutdown'];
- return !blocked.some(cmd => command.includes(cmd));
- }
- ```
- Key parts:
- - List of dangerous commands
- - Simple check against that list
- - Blocks anything risky
- ## Safety Features
- Shell Execution includes important protections:
- - Blocks command chains (`;` or `&&`)
- - Asks before running new commands
- - Runs in limited environments
- ```typescript
- // Will ask for confirmation first
- await safeShell('npm install', { ask: true });
- ```
- ## Common Patterns
- You'll often use Shell Execution for:
- 1. **Safe File Operations**: Like `ls` or `cat`
- 2. **Build Tools**: Like `npm install` (with confirmation)
- 3. **System Checks**: Like `node --version`
- ## What's Next?
- Now you understand how your CLI safely runs system commands! In [Chapter 39: Tool Scheduler](39_tool_scheduler_.md), we'll learn how your app manages multiple tools running at once.
- > Pro Tip: Try running different commands to see which ones require confirmation!
- ---
- # Chapter 39: Tool Scheduler
- Welcome back! In [Chapter 38: Shell Execution](38_shell_execution_.md), we learned how your CLI safely runs system commands. Now, let's meet your app's **air traffic controller** - the Tool Scheduler that carefully manages all your CLI tools, making sure they run in the right order and don't crash into each other!
- ## Why Do We Need a Tool Scheduler?
- Imagine you're hosting a party with multiple entertainers:
- - A magician needs the stage at 7pm
- - The band needs setup time before playing
- - The caterers must finish before cleanup starts
- The Tool Scheduler does exactly this for your CLI tools! It:
- 1. **Organizes** when tools should run
- 2. **Checks** if they're safe to execute
- 3. **Tracks** their progress
- 4. **Handles** any problems that come up
- ## Meet the Tool Lifecycle
- Every tool goes through these simple stages:
- 1. **Scheduled**: Added to the to-do list
- 2. **Validating**: Checking if it's safe to run
- 3. **Awaiting Approval**: Waiting for your OK (if needed)
- 4. **Executing**: Running the actual tool
- 5. **Completed**: Finished successfully or with errors
- Here's how simple it is to schedule a tool:
- ```typescript
- import { scheduleTool } from 'gemini-cli';
- // Schedule a search tool
- scheduleTool({
- name: "web_search",
- args: { query: "best pizza places" }
- });
- ```
- This adds the search to the scheduler's queue.
- ## How the Scheduler Works
- When you schedule a tool, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Scheduler as Tool Scheduler
- participant Tool as The Tool
- You->>Scheduler: "Run web_search"
- Scheduler->>Tool: Checks if safe
- Tool-->>Scheduler: "Looks good!"
- Scheduler->>Tool: Runs when ready
- Tool-->>You: Returns pizza places
- ```
- ## A Simple Example
- Let's schedule and run a simple tool:
- ```typescript
- // Schedule a greeting tool
- const greetingCall = {
- name: "greet",
- args: { name: "Alice" }
- };
- // Run it through the scheduler
- scheduleTool(greetingCall);
- ```
- This will:
- 1. Validate the greet tool
- 2. Run it immediately (since it's safe)
- 3. Return "Hello Alice!"
- ## Behind the Scenes
- The scheduler manages tools in different states (simplified from our code):
- ```typescript
- class ToolScheduler {
- private tools = [];
- schedule(tool) {
- this.tools.push({
- ...tool,
- status: 'scheduled'
- });
- this.runNextTool();
- }
- }
- ```
- Key parts:
- - Keeps a list of scheduled tools
- - Tracks each tool's status
- - Runs tools when ready
- ## Handling Special Cases
- The scheduler also manages tricky situations:
- - Tools that need approval first
- - Tools that depend on others finishing
- - Tools that fail mid-execution
- ```typescript
- // Tool that requires approval
- scheduleTool({
- name: "delete_file",
- args: { file: "temp.txt" },
- needsApproval: true
- });
- ```
- This will pause and ask "Are you sure?" before running.
- ## What's Next?
- Now you understand how your CLI safely manages multiple tools! In [Chapter 40: Tool Framework](40_tool_framework_.md), we'll explore how to create your own custom tools for the scheduler to manage.
- > Pro Tip: Try scheduling multiple tools to see how the system manages them in order!
- ---
- # Chapter 40: Tool Framework
- Welcome back! In [Chapter 39: Tool Scheduler](39_tool_scheduler_.md), we learned how your CLI manages multiple tools running at once. Now, let's meet the **master builder** of your CLI - the Tool Framework that provides everything needed to create new tools, like a complete workshop where you can build any tool you can imagine!
- ## Why Do We Need a Tool Framework?
- Imagine you're opening a new toolbox. Inside you find:
- - A hammer for nails
- - A screwdriver for screws
- - A wrench for bolts
- The Tool Framework is like this toolbox for your CLI, but instead of physical tools, it helps you create digital ones! It provides:
- 1. **Blueprints**: Standard ways to define tools
- 2. **Materials**: Common functions all tools need
- 3. **Safety Checks**: Protection against mistakes
- ## Meet the Basic Tools
- Let's look at three simple tools you might create:
- 1. **Greet Tool**: Says hello to someone
- 2. **Calculator**: Does simple math
- 3. **File Reader**: Shows file contents
- Each follows the same simple pattern:
- ```typescript
- interface Tool {
- name: string;
- description: string;
- execute(params): Promise<Result>;
- }
- ```
- This means every tool has:
- - A name (like "greet")
- - A description (what it does)
- - An execute method (how to run it)
- ## A Simple Example
- Here's how to create a basic greet tool:
- ```typescript
- const greetTool = {
- name: "greet",
- description: "Says hello to someone",
- execute: ({name}) => `Hello ${name}!`
- };
- // Using the tool:
- const result = await greetTool.execute({name: "Alice"});
- console.log(result); // "Hello Alice!"
- ```
- This shows how simple tools can be - just a name, description, and action!
- ## How Tools Work Together
- When you use a tool, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Framework as Tool Framework
- participant Tool as The Tool
- You->>Framework: "Use the greet tool"
- Framework->>Tool: Finds and runs
- Tool->>Framework: Returns greeting
- Framework->>You: Shows "Hello Alice!"
- ```
- ## Behind the Scenes
- The framework handles important tasks for every tool (simplified from our code):
- ```typescript
- class ToolFramework {
- private tools = [];
- register(tool) {
- this.tools.push(tool); // Add to collection
- }
- run(name, params) {
- const tool = this.tools.find(t => t.name === name);
- return tool.execute(params); // Run it
- }
- }
- ```
- Key parts:
- - Stores all registered tools
- - Finds tools by name
- - Runs them with provided parameters
- ## Creating Different Tools
- The framework makes it easy to create various tools:
- ```typescript
- // Calculator tool
- const calcTool = {
- name: "calculate",
- description: "Does math operations",
- execute: ({operation, a, b}) => eval(`${a} ${operation} ${b}`)
- };
- // File reader tool
- const fileTool = {
- name: "read_file",
- description: "Reads file contents",
- execute: async ({path}) => fs.readFile(path)
- };
- ```
- Each follows the same pattern but does different work!
- ## Common Tool Patterns
- You'll often create tools that:
- 1. **Read Data**: Like our file reader
- 2. **Process Information**: Like the calculator
- 3. **Modify Files**: Like a text editor
- ## What's Next?
- Now you understand how the Tool Framework helps build all your CLI's capabilities! In [Chapter 41: Custom Hooks](41_custom_hooks_.md), we'll learn how to add special behaviors that run before or after tools execute.
- > Pro Tip: Try creating a simple tool that returns the current time to see the framework in action!
- ---
- # Chapter 41: Custom Hooks
- Welcome back! In [Chapter 40: Tool Framework](40_tool_framework_.md), we learned how to build custom tools for your CLI. Now, let's meet your app's **special helpers** - Custom Hooks that add reusable behaviors to your tools, like magical ingredients that give your tools superpowers!
- ## Why Do We Need Custom Hooks?
- Imagine you're baking cookies and need to:
- 1. Set a timer (so they don't burn)
- 2. Check the oven temperature (for perfect baking)
- 3. Know when they're ready (to take them out)
- Custom Hooks do exactly this for your CLI tools! They provide reusable functions like:
- - Timers that count seconds
- - Git branch detection
- - Automatic approval checks
- Instead of writing these from scratch each time, you can use pre-made hooks!
- ## Meet Three Simple Hooks
- Let's look at three handy hooks you can use:
- 1. **useTimer**: Like a kitchen timer for your tools
- 2. **useGitBranchName**: Knows which git branch you're using
- 3. **useAutoAccept**: Automatically approves safe actions
- Here's how easy it is to use the timer hook:
- ```typescript
- import { useTimer } from 'gemini-cli';
- // Start a timer that counts up every second
- const seconds = useTimer(true);
- console.log(`Running for ${seconds} seconds...`);
- ```
- This creates a timer that updates automatically!
- ## How Hooks Work Together
- When you use a hook, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as Your Tool
- participant Hook as Custom Hook
- participant React as React System
- You->>Hook: "Start timer"
- Hook->>React: Sets up timer
- React->>Hook: Updates every second
- Hook->>You: Returns current time
- ```
- ## A Simple Example
- Let's use the git branch hook:
- ```typescript
- import { useGitBranchName } from 'gemini-cli';
- // Get current git branch
- const branch = useGitBranchName('./');
- console.log(`Working on branch: ${branch}`);
- ```
- This automatically detects and tracks your git branch!
- ## Behind the Scenes
- Hooks use React's magic to remember state. Here's a simplified version of the timer hook:
- ```typescript
- function useTimer(isActive) {
- const [seconds, setSeconds] = useState(0);
- useEffect(() => {
- if (!isActive) return;
- const timer = setInterval(() => {
- setSeconds(s => s + 1); // Add 1 second
- }, 1000);
- return () => clearInterval(timer); // Clean up
- }, [isActive]);
- return seconds;
- }
- ```
- Key parts:
- - `useState` remembers the current time
- - `useEffect` runs the timer
- - Cleanup prevents memory leaks
- ## Common Hook Patterns
- You'll often use hooks for:
- 1. **Timers**: Track operation duration
- 2. **Git Info**: Detect branches and changes
- 3. **Auto-Approval**: Skip confirmations for safe actions
- ## What's Next?
- Now you understand how Custom Hooks add reusable behaviors to your CLI! In [Chapter 42: Layout Management](42_layout_management_.md), we'll learn how to organize your terminal interface beautifully.
- > Pro Tip: Try combining multiple hooks in one tool to see how they work together!
- ---
- # Chapter 42: Layout Management
- Welcome back! In [Chapter 41: Custom Hooks](41_custom_hooks_.md), we learned how to add reusable behaviors to our CLI tools. Now, let's meet your terminal's **interior designer** - Layout Management that carefully arranges all your content to fit perfectly on screen, just like a smart bookshelf that automatically adjusts to hold all your books neatly!
- ## Why Do We Need Layout Management?
- Imagine typing a long message in your terminal. Without proper layout:
- - Text might disappear off the screen
- - Important parts could get cut off
- - The display would look messy
- Layout Management solves this by:
- 1. Making sure content fits within terminal boundaries
- 2. Handling overflow gracefully (with "show more" options)
- 3. Keeping everything neatly organized
- ## Meet the Three Layout Helpers
- Our layout system has three main components:
- 1. **Boxes**: Containers that hold your content
- 2. **Text Wrapping**: Makes long lines fit neatly
- 3. **Overflow Handling**: Manages when content is too big
- Here's a simple example of creating a box:
- ```typescript
- import { Box, Text } from 'gemini-cli';
- function MyComponent() {
- return (
- <Box width={40}>
- <Text>This text stays neatly within 40 columns!</Text>
- </Box>
- );
- }
- ```
- This creates a container that keeps your text perfectly sized.
- ## How Layout Works Together
- When you display content, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as Your Component
- participant Layout as Layout System
- participant Terminal as Screen
- You->>Layout: "Show this text"
- Layout->>Terminal: Checks available space
- Terminal-->>Layout: "You have 80 columns"
- Layout->>Terminal: Fits text perfectly
- Terminal->>You: Displays neat content
- ```
- ## A Simple Example
- Let's create a component with automatic wrapping:
- ```typescript
- function LongMessage() {
- return (
- <Box width={30}>
- <Text wrap="wrap">
- This long message will automatically wrap to fit within 30 columns!
- </Text>
- </Box>
- );
- }
- ```
- The text will break into multiple lines to stay within the box's width.
- ## Behind the Scenes
- The layout system measures content carefully (simplified from our code):
- ```typescript
- function measureText(text, maxWidth) {
- const words = text.split(' ');
- let currentLine = '';
- let lines = [];
- words.forEach(word => {
- if (currentLine.length + word.length <= maxWidth) {
- currentLine += word + ' ';
- } else {
- lines.push(currentLine);
- currentLine = word + ' ';
- }
- });
- lines.push(currentLine);
- return lines;
- }
- ```
- Key steps:
- 1. Splits text into words
- 2. Fits as many words as possible per line
- 3. Creates new lines when needed
- ## Handling Overflow
- When content is too tall, the system shows helpful messages:
- ```typescript
- function ShowMoreLines() {
- return (
- <Text color="gray">
- Press ctrl-s to show more lines
- </Text>
- );
- }
- ```
- This appears when content is truncated due to space limits.
- ## Common Layout Patterns
- You'll often use:
- 1. **Fixed Width Boxes**: For consistent sizing
- 2. **Flexible Containers**: That grow with content
- 3. **Scrollable Areas**: For long content
- ## What's Next?
- Now you understand how to beautifully arrange content in your terminal! In [Chapter 43: Shared UI Components](43_shared_ui_components_.md), we'll explore ready-made components you can use in your CLI apps.
- > Pro Tip: Try creating boxes with different widths to see how text automatically adjusts!
- ---
- # Chapter 43: Shared UI Components
- Welcome back! In [Chapter 42: Layout Management](42_layout_management_.md), we learned how to organize content beautifully in our terminal. Now, let's meet your CLI's **building block set** - Shared UI Components that provide ready-to-use interface pieces like radio buttons and boxes, just like LEGO bricks you can snap together to build amazing terminal interfaces!
- ## Why Do We Need Shared Components?
- Imagine you're building a terminal app with settings. You'd need:
- - Radio buttons to choose options
- - Boxes to group related settings
- - Text areas for input
- Instead of building these from scratch each time, Shared UI Components provide them ready-made! They're like a toolbox full of pre-built parts that:
- 1. Look consistent across your app
- 2. Work the same way everywhere
- 3. Save you tons of time
- ## Meet the Component Collection
- Our shared components include three essential pieces:
- 1. **Radio Buttons**: For selecting one option from many
- 2. **Constrained Boxes**: Containers that manage their size
- 3. **Text Displays**: For showing formatted messages
- Here's how simple it is to use a radio button:
- ```typescript
- import { RadioButtonSelect } from 'gemini-cli';
- // Simple theme selector
- const themeOptions = [
- { label: "Dark", value: "dark" },
- { label: "Light", value: "light" }
- ];
- function ThemePicker() {
- return (
- <RadioButtonSelect
- items={themeOptions}
- onSelect={(theme) => setTheme(theme)}
- />
- );
- }
- ```
- This creates a clean theme selector with just a few lines!
- ## How Components Work Together
- When you use a radio button, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as Your App
- participant Radio as Radio Button
- participant Terminal as Screen
- You->>Radio: Show these options
- Radio->>Terminal: Draws buttons
- Terminal->>You: User selects one
- You->>Radio: Gets the selection
- ```
- ## A Simple Example
- Let's build a settings panel with multiple components:
- ```typescript
- function Settings() {
- return (
- <Box borderStyle="round">
- <Text bold>Settings</Text>
- <RadioButtonSelect items={themeOptions} />
- <Text>Enter your name:</Text>
- <Input />
- </Box>
- );
- }
- ```
- This creates:
- - A bordered box
- - A title
- - Theme radio buttons
- - A text input field
- ## Behind the Scenes
- The radio button component works like this (simplified):
- ```typescript
- function RadioButton({ label, selected }) {
- return (
- <Text>
- {selected ? '●' : '○'} {label}
- </Text>
- );
- }
- ```
- Key parts:
- - Shows a filled (●) or empty (○) circle
- - Displays the label text
- - Changes based on selection
- ## Constrained Boxes
- The `MaxSizedBox` component automatically fits content:
- ```typescript
- <MaxSizedBox maxWidth={40}>
- <Text>This text stays within 40 columns!</Text>
- </MaxSizedBox>
- ```
- This ensures content never overflows the specified width.
- ## Common Patterns
- You'll often use shared components to:
- 1. **Build Forms**: With inputs and buttons
- 2. **Create Menus**: With selectable options
- 3. **Display Alerts**: In consistent boxes
- ## What's Next?
- Now you understand how to quickly build interfaces with Shared UI Components! In [Chapter 44: Editor Integration](44_editor_integration_.md), we'll learn how to connect your CLI with code editors for an even better workflow.
- > Pro Tip: Try combining different components to create your own custom interfaces!
- ---
- # Chapter 44: Editor Integration
- Welcome back! In [Chapter 43: Shared UI Components](43_shared_ui_components_.md), we learned how to build beautiful terminal interfaces. Now, let's meet your CLI's **universal remote control** - Editor Integration that lets you connect with different code editors, just like one remote that works with all your TV, sound system, and streaming devices!
- ## Why Do We Need Editor Integration?
- Imagine you're working on a coding project and want to:
- 1. Open a file in your favorite editor
- 2. Compare changes between versions
- 3. Edit code directly from the CLI
- Without editor integration, you'd need to manually:
- - Find the file
- - Open your editor
- - Navigate to the right line
- Editor Integration does all this automatically! It's like having a personal assistant who knows exactly how to work with your preferred editor.
- ## Meet the Editor Remote Control
- Our editor integration works with popular editors like:
- - VS Code
- - Vim/Neovim
- - Zed
- - And more!
- Here's how simple it is to open a file:
- ```typescript
- import { openInEditor } from 'gemini-cli';
- // Open config.json in your default editor
- await openInEditor('config.json');
- ```
- This automatically launches your editor with the file ready to edit!
- ## How Editor Integration Works
- When you open a file, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Gemini CLI
- participant Editor as Your Editor
- You->>CLI: "Open config.json"
- CLI->>Editor: Finds and launches editor
- Editor-->>You: Shows the file ready to edit
- ```
- ## A Simple Example
- Let's compare two file versions:
- ```typescript
- import { compareFiles } from 'gemini-cli';
- // See differences between old and new versions
- await compareFiles('old-code.js', 'new-code.js');
- ```
- This opens your editor's diff view showing all changes!
- ## Behind the Scenes
- The system checks which editors you have installed (simplified):
- ```typescript
- function findAvailableEditors() {
- const editors = ['vscode', 'vim', 'zed'];
- return editors.filter(editor => {
- // Check if editor is installed
- return checkEditorExists(editor);
- });
- }
- ```
- Key parts:
- 1. Lists supported editors
- 2. Checks which are installed
- 3. Returns available options
- ## Editor Commands
- Each editor has specific commands for opening files:
- ```typescript
- const editorCommands = {
- vscode: 'code --wait',
- vim: 'vim',
- zed: 'zed'
- };
- ```
- These commands are used to launch the editors properly.
- ## Common Uses
- You'll often use editor integration to:
- 1. **Edit Configs**: Quickly tweak settings
- 2. **Review Changes**: Compare file versions
- 3. **Fix Code**: Edit files directly from CLI output
- ## What's Next?
- Now you understand how to connect your CLI with any code editor! In [Chapter 45: Non-Interactive Mode](45_non_interactive_mode_.md), we'll learn how to run commands without user input for automation.
- > Pro Tip: Try opening different file types to see how your editor handles them!
- ---
- # Chapter 45: Non-Interactive Mode
- Welcome back! In [Chapter 44: Editor Integration](44_editor_integration_.md), we learned how to connect your CLI with code editors. Now, let's meet your app's **silent worker** - Non-Interactive Mode that lets your CLI run automatically without user input, like a robot chef that follows a recipe perfectly every time!
- ## Why Do We Need Non-Interactive Mode?
- Imagine you want to:
- - Automatically process files every night
- - Pipe questions to Gemini from another program
- - Run commands from scripts without typing
- Non-Interactive Mode makes this possible! It's like putting your CLI on autopilot - it accepts input, does the work, and gives output without any human interaction.
- ## Meet the Silent Worker
- Non-Interactive Mode has three simple jobs:
- 1. **Take Input**: From files or other programs (stdin)
- 2. **Process It**: Using Gemini's AI
- 3. **Give Output**: To files or other programs (stdout)
- Here's how simple it is to use:
- ```bash
- # Ask Gemini a question automatically
- echo "What's 2+2?" | gemini-cli
- # Output: 4
- ```
- This pipes your question directly to Gemini and shows the answer!
- ## How Non-Interactive Mode Works
- When you pipe a command, here's what happens:
- ```mermaid
- sequenceDiagram
- participant Program as Other Program
- participant CLI as Gemini CLI
- participant Gemini as Gemini AI
- Program->>CLI: "What's 2+2?"
- CLI->>Gemini: Sends question
- Gemini-->>CLI: Returns "4"
- CLI->>Program: Outputs "4"
- ```
- ## A Simple Example
- Let's process a file automatically:
- ```bash
- # File: questions.txt
- What's 3×3?
- Capital of France?
- # Run Gemini on the file
- cat questions.txt | gemini-cli
- ```
- This will output:
- ```
- 9
- Paris
- ```
- ## Behind the Scenes
- The CLI checks if it's in non-interactive mode (simplified):
- ```typescript
- if (!process.stdin.isTTY) { // If input is piped
- const input = await readStdin(); // Read the input
- runNonInteractive(input); // Process automatically
- }
- ```
- Key parts:
- 1. Checks if input is coming from a pipe
- 2. Reads all the input at once
- 3. Runs in non-interactive mode
- ## Handling Tools Automatically
- Even tools can run non-interactively:
- ```typescript
- // In non-interactive mode
- if (needsApproval && !interactive) {
- return "Can't run this tool automatically";
- }
- ```
- This prevents risky tools from running without confirmation.
- ## Common Uses
- You'll often use non-interactive mode for:
- 1. **Automation**: Nightly processing jobs
- 2. **Scripting**: Building complex workflows
- 3. **Piping**: Connecting with other CLI tools
- ## What's Next?
- Now you understand how to run your CLI automatically! In [Chapter 46: Utility Functions](46_utility_functions_.md), we'll explore helpful tools that make building CLI apps easier.
- > Pro Tip: Try piping simple questions to your CLI to see non-interactive mode in action!
- ---
- # Chapter 46: Utility Functions
- Welcome back! In [Chapter 45: Non-Interactive Mode](45_non_interactive_mode_.md), we learned how to run CLI commands automatically. Now, let's meet your app's **Swiss Army knife** - Utility Functions that provide handy little tools for common tasks, like a pocket toolkit with all the essentials you need for quick fixes!
- ## Why Do We Need Utility Functions?
- Imagine you're packing for a camping trip. You'd want:
- - A small flashlight (for checking things)
- - A multi-tool (for quick fixes)
- - A notepad (for reminders)
- Utility Functions are exactly this for your CLI app! They're small, reusable tools that handle common needs like:
- - Cleaning up temporary files
- - Checking your CLI version
- - Reading user input
- - Showing helpful warnings
- ## Meet the Handy Helpers
- Let's look at three simple utilities you'll use often:
- 1. **Cleanup Crew**: Removes temporary files
- 2. **Version Checker**: Tells you which CLI version you're using
- 3. **Input Reader**: Gets text from user input
- Here's how easy it is to check your CLI version:
- ```typescript
- import { getCliVersion } from 'gemini-cli';
- // Get the current version
- const version = await getCliVersion();
- console.log(`You're using version ${version}`);
- ```
- This shows something like "You're using version 1.2.3".
- ## How Utilities Work Together
- When you use a utility function, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Utility as Utility Function
- participant System as Your Computer
- You->>Utility: "What's my version?"
- Utility->>System: Checks package info
- System-->>Utility: Returns "1.2.3"
- Utility->>You: Shows the version
- ```
- ## A Simple Example
- Let's clean up temporary files:
- ```typescript
- import { cleanupCheckpoints } from 'gemini-cli';
- // Remove old temporary files
- await cleanupCheckpoints();
- console.log("All clean!");
- ```
- This safely deletes any leftover temporary files from previous runs.
- ## Behind the Scenes
- The version checker works like this (simplified):
- ```typescript
- async function getCliVersion() {
- // 1. Check for override in environment
- if (process.env.CLI_VERSION) {
- return process.env.CLI_VERSION;
- }
- // 2. Read from package.json
- const pkg = await readPackageJson();
- return pkg?.version || 'unknown';
- }
- ```
- Key steps:
- 1. Checks environment variables first
- 2. Falls back to package.json
- 3. Returns "unknown" if all else fails
- ## Reading User Input
- Another handy utility reads typed input:
- ```typescript
- import { readStdin } from 'gemini-cli';
- // Get text piped from another command
- const input = await readStdin();
- console.log(`You sent: ${input}`);
- ```
- This captures anything piped to your CLI (like `echo "hi" | gemini-cli`).
- ## Common Utility Patterns
- You'll often use utilities for:
- 1. **Cleanup**: Removing temporary files
- 2. **Info Checks**: Version, system details
- 3. **Input/Output**: Reading and writing data
- ## What's Next?
- Now you understand how utility functions provide handy tools for common tasks! In [Chapter 47: Validation Framework](47_validation_framework_.md), we'll learn how to check if data meets certain rules.
- > Pro Tip: Try using different utility functions to see how they simplify common tasks!
- ---
- # Chapter 47: Validation Framework
- Welcome back! In [Chapter 46: Utility Functions](46_utility_functions_.md), we learned about handy helper tools for our CLI. Now, let's meet your app's **bouncer** - the Validation Framework that checks if everything is correct before letting it through, just like a club doorman who checks IDs before letting anyone inside!
- ## Why Do We Need Validation?
- Imagine you're running a pizza delivery app. Before sending out an order, you'd want to check:
- - Does the address exist?
- - Is the phone number valid?
- - Did they order at least one pizza?
- The Validation Framework does exactly this for your CLI! It makes sure:
- 1. Commands have all required information
- 2. Files are in allowed locations
- 3. User inputs make sense
- Without it, your app might try to deliver pizzas to "123 Fake Street" or accept orders for "minus 3 pizzas"!
- ## Meet the Three Checks
- Our validation system performs three main types of checks:
- 1. **Required Fields**: Like making sure a pizza order has toppings
- 2. **Correct Format**: Like checking if a phone number has 10 digits
- 3. **Safety Rules**: Like not letting someone order 1000 pizzas at once
- Here's how simple it is to validate a pizza order:
- ```typescript
- import { validateOrder } from 'pizza-cli';
- const order = { toppings: ['cheese'], address: '123 Main St' };
- const errors = validateOrder(order);
- if (errors.length > 0) {
- console.log("Order problems:", errors);
- } else {
- console.log("Order is valid!");
- }
- ```
- This checks if the order has all needed info before processing.
- ## How Validation Works
- When you validate something, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Validator as Validation
- participant Rules as Safety Rules
- You->>Validator: "Check this order"
- Validator->>Rules: "Is address valid?"
- Rules-->>Validator: "Yes!"
- Validator->>You: "All good!"
- ```
- ## A Simple Example
- Let's validate a file path:
- ```typescript
- import { validatePath } from 'gemini-cli';
- // Check if path is safe
- const result = validatePath('/safe/folder/file.txt');
- console.log(result.valid); // true or false
- console.log(result.message); // "Path is valid" or why it's not
- ```
- This prevents accessing dangerous locations like `/etc/passwd`.
- ## Behind the Scenes
- The validator uses simple rules (simplified from our code):
- ```typescript
- function validatePath(path) {
- const forbidden = ['/etc', '/sys', '/root'];
- if (forbidden.some(f => path.startsWith(f))) {
- return { valid: false, message: "Dangerous path!" };
- }
- return { valid: true, message: "Path is safe" };
- }
- ```
- Key parts:
- 1. List of banned folders
- 2. Check if path starts with any
- 3. Return validation result
- ## Common Validation Patterns
- You'll often validate:
- 1. **User Input**: Like commands and queries
- 2. **File Paths**: For safety
- 3. **API Responses**: To ensure proper format
- ## What's Next?
- Now you understand how the Validation Framework keeps your CLI safe and correct! In [Chapter 48: Schema Validation](48_schema_validation_.md), we'll learn how to define more complex validation rules.
- > Pro Tip: Try validating different file paths to see what gets allowed or blocked!
- ---
- # Chapter 48: Schema Validation
- Welcome back! In [Chapter 47: Validation Framework](47_validation_framework_.md), we learned how to check if data meets basic requirements. Now, let's meet your CLI's **rule enforcer** - Schema Validation that ensures data structures match expected formats, just like a bouncer checking IDs at a club entrance to make sure everyone follows the dress code!
- ## Why Do We Need Schema Validation?
- Imagine you're running a pizza delivery app. Before accepting an order, you'd want to check:
- - Does the order have all required fields (like toppings and address)?
- - Is the phone number in the correct format?
- - Are the quantities valid numbers?
- Schema Validation does exactly this for your CLI! It acts like a strict but fair bouncer that:
- 1. Checks if data has the right "shape"
- 2. Verifies all required fields are present
- 3. Ensures values match expected types
- Without it, your app might accept pizza orders for "minus 3 pizzas" or deliver to "123 Fake Street"!
- ## Meet the Simple Validator
- Our Schema Validator works with three basic rules:
- 1. **Required Fields**: Must-have items (like pizza toppings)
- 2. **Type Checks**: Correct data types (numbers, strings, etc.)
- 3. **Structure**: Proper organization (like address having street + city)
- Here's how simple it is to validate a pizza order:
- ```typescript
- import { SchemaValidator } from 'gemini-cli';
- // Define what a valid order looks like
- const pizzaSchema = {
- required: ['toppings', 'address'],
- properties: {
- toppings: { type: 'array' },
- address: { type: 'string' }
- }
- };
- // Check if an order is valid
- const isValid = SchemaValidator.validate(pizzaSchema, order);
- console.log(isValid); // true or false
- ```
- This checks if the order matches our pizza requirements!
- ## How Validation Works
- When validating data, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as Your Code
- participant Validator as Schema Validator
- participant Data as Your Data
- You->>Validator: "Check this pizza order"
- Validator->>Data: "Has required toppings?"
- Data-->>Validator: "Yes!"
- Validator->>Data: "Is address a string?"
- Data-->>Validator: "Yes!"
- Validator->>You: "All good!"
- ```
- ## A Simple Example
- Let's validate a user profile:
- ```typescript
- const profileSchema = {
- required: ['name', 'age'],
- properties: {
- name: { type: 'string' },
- age: { type: 'number' }
- }
- };
- const user = { name: "Alice", age: 30 };
- const isValid = SchemaValidator.validate(profileSchema, user);
- // Returns true since all checks pass
- ```
- This ensures profiles have both a name (string) and age (number).
- ## Behind the Scenes
- The validator performs two main checks (simplified from our code):
- ```typescript
- // Check required fields
- for (const field of schema.required) {
- if (!(field in data)) {
- return false; // Missing required field!
- }
- }
- // Check types
- for (const [field, rule] of Object.entries(schema.properties)) {
- if (typeof data[field] !== rule.type) {
- return false; // Wrong type!
- }
- }
- ```
- Key steps:
- 1. Verifies all required fields exist
- 2. Checks each field's type matches
- 3. Returns true only if all checks pass
- ## Handling Complex Data
- The validator can also check nested structures:
- ```typescript
- const orderSchema = {
- properties: {
- customer: {
- type: 'object',
- properties: {
- name: { type: 'string' }
- }
- }
- }
- };
- ```
- This ensures the customer field is an object with a name string.
- ## What's Next?
- Now you understand how Schema Validation keeps your CLI's data clean and correct! In [Chapter 49: Build Pipeline](49_build_pipeline_.md), we'll learn how your app gets packaged and prepared for users.
- > Pro Tip: Try creating simple schemas for different data types to see how validation works!
- ---
- # Chapter 49: Build Pipeline
- Welcome back! In [Chapter 48: Schema Validation](48_schema_validation_.md), we learned how to check if data follows the right structure. Now, let's meet your CLI's **automated factory** - the Build Pipeline that transforms your source code into a ready-to-use application, just like an assembly line that turns raw materials into finished products!
- ## Why Do We Need a Build Pipeline?
- Imagine you're baking cookies. You wouldn't want to:
- - Mix ingredients by hand every time
- - Bake each cookie separately
- - Package them one at a time
- A Build Pipeline solves this for your CLI app by automatically:
- 1. Combining all code files
- 2. Checking for errors
- 3. Creating installable packages
- 4. Testing everything works
- It's like having a cookie factory that takes your recipe (source code) and produces perfect cookies (your app) every time!
- ## Meet the Assembly Line
- Our build pipeline has three simple stations:
- 1. **Preparation**: Gets all ingredients (code files) ready
- 2. **Processing**: Combines and checks everything
- 3. **Packaging**: Creates the final product
- Here's how simple it is to start a build:
- ```bash
- # Run the build pipeline
- npm run build
- ```
- This single command triggers the entire process automatically!
- ## How the Pipeline Works
- When you run a build, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Prep as Preparation
- participant Process as Processing
- participant Package as Packaging
- You->>Prep: "npm run build"
- Prep->>Process: Gathers all code
- Process->>Package: Checks and combines
- Package->>You: Creates final app
- ```
- ## A Simple Example
- Let's see what happens during a typical build:
- 1. **Preparation**: Checks all files are present
- 2. **Processing**: Combines TypeScript into JavaScript
- 3. **Packaging**: Creates a `.tgz` file you can install
- ```bash
- # After running build, you get:
- google-gemini-cli-1.0.0.tgz # Your finished app!
- ```
- ## Behind the Scenes
- The build script does several important things (simplified):
- ```javascript
- // 1. Install dependencies if needed
- if (!existsSync('node_modules')) {
- run('npm install');
- }
- // 2. Build all packages
- run('npm run build --workspaces');
- // 3. Create final package
- run('npm pack');
- ```
- Key steps:
- 1. Ensures all tools are available
- 2. Builds each part of your app
- 3. Packages everything together
- ## Handling Special Cases
- The pipeline also manages tricky situations:
- - Missing files
- - Build errors
- - Different operating systems
- ```javascript
- try {
- runBuild();
- } catch (error) {
- console.log("Build failed!");
- showHelpfulErrorMessage(error);
- }
- ```
- This ensures you know exactly what went wrong if the build fails.
- ## Common Build Patterns
- You'll often use the build pipeline to:
- 1. **Prepare Releases**: Create installable versions
- 2. **Test Changes**: Verify everything works
- 3. **Update Dependencies**: Get the latest tools
- ## What's Next?
- Now you understand how your CLI gets built and packaged automatically! In [Chapter 50: Package Management](50_package_management_.md), we'll learn how to share and install your finished application.
- > Pro Tip: Try running the build command yourself to see the pipeline in action!
- ---
- # Chapter 50: Package Management
- Welcome back! In [Chapter 49: Build Pipeline](49_build_pipeline_.md), we learned how your CLI gets built and packaged automatically. Now, let's meet your app's **librarian** - Package Management that carefully organizes all the different parts of your CLI, just like a librarian who keeps track of which books work well together!
- ## Why Do We Need Package Management?
- Imagine you're building a toy robot from different kits:
- - The arms come from Kit A (version 2.0)
- - The legs need Kit B (but only version 1.5 or higher)
- - The head requires Kit C (but it conflicts with Kit A versions below 2.1)
- Package Management solves this puzzle for your CLI by:
- 1. Tracking which versions of different packages work together
- 2. Making sure all parts are compatible
- 3. Preventing version conflicts that could break your app
- ## Meet the Package Organizer
- Our Package Management system has three simple jobs:
- 1. **Version Tracking**: Knows which versions work together
- 2. **Dependency Checking**: Ensures all required packages are present
- 3. **Conflict Prevention**: Stops incompatible combinations
- Here's how simple it is to check dependencies:
- ```typescript
- import { checkDependencies } from 'gemini-cli';
- // Verify all packages are compatible
- const isValid = await checkDependencies();
- console.log(isValid ? "All good!" : "Version conflict!");
- ```
- This checks if all your CLI's internal packages play nicely together.
- ## How Package Management Works
- When checking dependencies, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant PM as Package Manager
- participant Core as Core Package
- participant CLI as CLI Package
- You->>PM: "Check dependencies"
- PM->>Core: "What version are you?"
- Core-->>PM: "Version 2.0"
- PM->>CLI: "Do you work with Core 2.0?"
- CLI-->>PM: "Yes, I need Core >=1.5"
- PM->>You: "All packages compatible!"
- ```
- ## A Simple Example
- Let's declare some package requirements:
- ```typescript
- // In package.json
- {
- "name": "cli-tool",
- "dependencies": {
- "core-package": "^1.5.0",
- "ui-package": "~2.0.3"
- }
- }
- ```
- This means:
- - `core-package` needs version 1.5.0 or higher (but not 2.0.0)
- - `ui-package` wants version 2.0.3 exactly (with only small updates allowed)
- ## Behind the Scenes
- The package manager checks versions like this (simplified):
- ```typescript
- function checkVersion(packageVersion, requiredVersion) {
- // Check if installed version meets requirement
- return semver.satisfies(packageVersion, requiredVersion);
- }
- ```
- Key parts:
- - `semver` library handles version comparisons
- - Checks if installed version "satisfies" the requirement
- - Returns true/false for compatibility
- ## Handling Conflicts
- When versions don't match, the system helps fix them:
- ```typescript
- async function resolveConflict() {
- // Find compatible versions
- const solutions = await findCompatibleVersions();
- // Update package.json automatically
- if (solutions.length > 0) {
- await updatePackages(solutions[0]);
- }
- }
- ```
- This automatically suggests and applies fixes when possible.
- ## Common Patterns
- You'll often use Package Management to:
- 1. **Add Features**: Install new packages
- 2. **Update Safely**: Get latest compatible versions
- 3. **Troubleshoot**: Fix version conflicts
- ## What's Next?
- Now you understand how Package Management keeps all your CLI's parts working together! In [Chapter 51: Cross-Package Import Rules](51_cross_package_import_rules_.md), we'll learn how different packages can safely share code.
- > Pro Tip: Try checking your project's `package.json` to see real dependency examples!
- ---
- # Chapter 51: Cross-Package Import Rules
- Welcome back! In [Chapter 50: Package Management](50_package_management_.md), we learned how different parts of your CLI work together. Now, let's meet your app's **border control** - Cross-Package Import Rules that ensure clean boundaries between different code packages, just like countries having clear borders with proper documentation for crossing between them!
- ## Why Do We Need Import Rules?
- Imagine you're organizing a big international conference with teams from different countries. You'd want:
- - Each team to have their own workspace (package)
- - Clear rules for visiting other teams' spaces (imports)
- - Proper documentation when sharing resources (exports)
- Cross-Package Import Rules do exactly this for your CLI's code! They:
- 1. Keep different packages neatly separated
- 2. Require proper documentation when code crosses boundaries
- 3. Prevent messy "backdoor" access between packages
- ## Meet the Three Border Rules
- Our import system enforces three simple principles:
- 1. **No Sneaky Paths**: Can't use `../` to access other packages
- 2. **Proper Documentation**: Must declare what you're sharing
- 3. **Clear Boundaries**: Each package has its own "territory"
- Here's a simple example of a *bad* import that breaks the rules:
- ```typescript
- // In packageA - DON'T DO THIS!
- import { helper } from '../../packageB/src/utils';
- ```
- This is like sneaking across a border without paperwork!
- ## How Import Rules Work
- When code tries to import something, here's what happens:
- ```mermaid
- sequenceDiagram
- participant Code as Your Code
- participant Checker as Import Checker
- participant PackageA as Package A
- participant PackageB as Package B
- Code->>Checker: "Import from PackageB"
- Checker->>PackageA: Are you allowed?
- PackageA-->>Checker: Shows documentation
- Checker->>PackageB: Is this shared?
- PackageB-->>Checker: Yes, properly exported
- Checker->>Code: Import approved!
- ```
- ## A Simple Example
- Here's the *correct* way to import between packages:
- ```typescript
- // In packageA - DO THIS!
- import { helper } from 'packageB';
- ```
- This is like using the proper border crossing with all your documents ready!
- ## Behind the Scenes
- The import checker works in three steps (simplified from our code):
- ```typescript
- function checkImport(filePath, importPath) {
- // 1. Find which packages are involved
- const fromPackage = findPackage(filePath);
- const toPackage = findPackage(importPath);
- // 2. Check if it's a cross-package import
- if (fromPackage !== toPackage) {
- // 3. Verify it uses proper package name
- if (importPath.startsWith('.')) {
- throw Error("Use package name instead of relative path!");
- }
- }
- }
- ```
- Key parts:
- 1. Identifies the source and destination packages
- 2. Checks if it's crossing boundaries
- 3. Enforces proper import syntax
- ## Handling Special Cases
- The system also manages tricky situations:
- - Circular dependencies (Package A needs B which needs A)
- - Deeply nested imports
- - Missing package declarations
- ```typescript
- // Special case: Circular imports are allowed but warned
- if (isCircular(fromPackage, toPackage)) {
- console.warn("Circular dependency detected!");
- }
- ```
- ## Common Patterns
- You'll often work with:
- 1. **Public APIs**: What a package officially exports
- 2. **Internal Code**: Private to each package
- 3. **Dependency Trees**: Which packages depend on others
- ## What's Next?
- Now you understand how Cross-Package Import Rules keep your CLI's code organized! In [Chapter 52: Release Process](52_release_process_.md), we'll learn how to prepare and share your finished CLI with the world.
- > Pro Tip: Try organizing your code into separate packages to see how import rules help maintain clean boundaries!
- ---
- # Chapter 52: Release Process
- Welcome back! In [Chapter 51: Cross-Package Import Rules](51_cross_package_import_rules_.md), we learned how to keep different parts of your CLI organized. Now, let's meet your app's **delivery truck** - the Release Process that packages and ships your finished CLI to users, just like a factory assembly line that carefully prepares products for delivery!
- ## Why Do We Need a Release Process?
- Imagine you're baking cookies to sell at a market. You wouldn't just throw them in a bag - you'd:
- 1. Check each cookie is perfect (testing)
- 2. Package them neatly in boxes (building)
- 3. Label them clearly (versioning)
- 4. Deliver to the market (publishing)
- The Release Process does exactly this for your CLI! It's an automated workflow that:
- 1. Tests everything works
- 2. Packages your code neatly
- 3. Adds version numbers
- 4. Publishes to users
- ## Meet the Four-Step Assembly Line
- Our release process has four simple stations:
- 1. **Preparation**: Gets all ingredients (code) ready
- 2. **Packaging**: Combines everything into installable bundles
- 3. **Versioning**: Tags each release clearly
- 4. **Shipping**: Delivers to package managers
- Here's how simple it is to start a release:
- ```bash
- # Run the release process
- npm run release
- ```
- This single command triggers the entire automated workflow!
- ## How Releases Work
- When you run a release, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Prep as Preparation
- participant Package as Packaging
- participant Ship as Shipping
- You->>Prep: "npm run release"
- Prep->>Prep: Runs all tests
- Prep->>Package: Creates install packages
- Package->>Ship: Publishes to npm
- Ship->>You: "Release complete!"
- ```
- ## A Simple Example
- Let's see what happens during a typical release:
- 1. **Preparation**: Checks all tests pass
- 2. **Packaging**: Creates `.tgz` files
- 3. **Versioning**: Tags as "v1.2.3"
- 4. **Shipping**: Uploads to npm registry
- ```bash
- # After running release, you get:
- Successfully published:
- - @google/[email protected]
- - @google/[email protected]
- ```
- ## Behind the Scenes
- The release script does several important checks (simplified):
- ```javascript
- // 1. Verify all tests pass
- if (!runTests()) {
- throw Error("Tests failed - fix before releasing!");
- }
- // 2. Update version numbers
- updateVersion('1.2.3');
- // 3. Publish packages
- publishToNpm();
- ```
- Key steps:
- 1. Ensures everything works
- 2. Sets the version
- 3. Shares with the world
- ## Handling Special Cases
- The process also manages tricky situations:
- - Release candidates (test versions)
- - Different environments
- - Failed publishes
- ```javascript
- if (isReleaseCandidate) {
- publishWithTag('rc'); // Mark as test version
- } else {
- publishWithTag('latest'); // Official release
- }
- ```
- ## Common Release Patterns
- You'll often use the release process to:
- 1. **Share Updates**: Publish new features
- 2. **Test Changes**: Release candidate versions
- 3. **Fix Bugs**: Patch versions for problems
- ## What's Next?
- Now you understand how your CLI gets shared with users through the Release Process! In [Chapter 53: Privacy Notices](53_privacy_notices_.md), we'll learn how your app communicates important privacy information to users.
- > Pro Tip: Try running the release process with `--dry-run` to see what would happen without actually publishing!
- ---
- # Chapter 53: Privacy Notices
- Welcome back! In [Chapter 52: Release Process](52_release_process_.md), we learned how to prepare and share your CLI with users. Now, let's meet your app's **legal translator** - Privacy Notices that clearly explain how user data is handled, just like a friendly guide who explains the rules before you enter a new place!
- ## Why Do We Need Privacy Notices?
- Imagine you're signing up for a new app. You'd want to know:
- - What information the app collects
- - How they'll use your data
- - Who can see your information
- Privacy Notices do exactly this for your CLI! They:
- 1. Show different policies based on how you're logged in
- 2. Explain data collection clearly
- 3. Let users make informed choices
- For example, free users might see different privacy terms than paid enterprise users.
- ## Meet the Notice Types
- Your CLI shows three main types of privacy notices:
- 1. **Free Tier Notice**: For individual users
- 2. **Enterprise Notice**: For business accounts
- 3. **API Key Notice**: For developers using API keys
- Here's how simple it is to show the right notice:
- ```typescript
- import { showPrivacyNotice } from 'gemini-cli';
- // Automatically shows the correct notice
- showPrivacyNotice(authType);
- ```
- This displays the appropriate policy based on how the user is authenticated.
- ## How Privacy Notices Work
- When checking which notice to show, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as User
- participant CLI as Your CLI
- participant Auth as Authentication
- You->>CLI: Runs command
- CLI->>Auth: Checks login type
- Auth-->>CLI: "Free tier user"
- CLI->>You: Shows free tier notice
- ```
- ## A Simple Example
- Let's see how different users get different notices:
- ```typescript
- // Free user sees this notice:
- "Google may use your data to improve services"
- // Enterprise user sees:
- "Your company's agreement governs data use"
- // API user sees:
- "API terms of service apply"
- ```
- Each notice matches the user's account type.
- ## Behind the Scenes
- The system checks auth type to pick the right notice (simplified):
- ```typescript
- function getNotice(authType) {
- switch(authType) {
- case 'FREE': return FreeNotice;
- case 'ENTERPRISE': return PaidNotice;
- case 'API_KEY': return APINotice;
- default: return DefaultNotice;
- }
- }
- ```
- Key parts:
- - Simple switch statement
- - Matches auth type to notice
- - Has a default fallback
- ## Real-World Implementation
- In our actual code (`packages/cli/src/ui/privacy/PrivacyNotice.tsx`), we handle more cases:
- ```typescript
- function PrivacyNoticeText({ authType }) {
- switch (authType) {
- case AuthType.USE_GEMINI:
- return <GeminiPrivacyNotice />;
- case AuthType.USE_VERTEX_AI:
- return <CloudPaidPrivacyNotice />;
- default:
- return <CloudFreePrivacyNotice />;
- }
- }
- ```
- This component renders the appropriate notice component.
- ## Common Patterns
- You'll often see privacy notices that:
- 1. **Vary By User Type**: Different for free/paid users
- 2. **Include Links**: To full policies
- 3. **Get Consent**: For data collection
- ## What's Next?
- Now you understand how Privacy Notices keep users informed about data handling! In [Chapter 54: Context Management](54_context_management_.md), we'll learn how your CLI maintains conversation history and settings.
- > Pro Tip: Try logging in different ways to see how the privacy notices change!
- ---
- # Chapter 54: Context Management
- Welcome back! In [Chapter 53: Privacy Notices](53_privacy_notices_.md), we learned how your CLI communicates important privacy information to users. Now, let's meet your app's **memory keeper** - Context Management that tracks and displays all the important details about your current work environment, just like a smart dashboard in a car that shows your speed, fuel level, and navigation!
- ## Why Do We Need Context Management?
- Imagine you're working on a coding project. You'd want to know:
- - Which files you're currently working with
- - What branch you're on in Git
- - How much memory your CLI is using
- - Any errors that might have occurred
- Context Management does exactly this! It's like having a personal assistant who constantly updates you about:
- 1. **Files**: What documents are open
- 2. **Projects**: Which folder you're working in
- 3. **System**: How your computer resources are being used
- ## Meet Your CLI Dashboard
- The Context Management system shows three main types of information:
- 1. **File Context**: Currently open files and their status
- 2. **Project Context**: The folder and Git branch you're working in
- 3. **System Context**: Memory usage and performance stats
- Here's how simple it is to check your current context:
- ```typescript
- import { getContext } from 'gemini-cli';
- // See your current working context
- const context = getContext();
- console.log(context.currentDirectory); // "/projects/my-app"
- ```
- This shows basic information about where you're working.
- ## How Context Works
- When you run a command, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Context as Context Manager
- participant Git as Git
- participant System as Your Computer
- You->>Context: "What's my context?"
- Context->>Git: Checks current branch
- Git-->>Context: "main branch"
- Context->>System: Checks memory
- System-->>Context: "2GB used"
- Context->>You: Returns all info
- ```
- ## A Simple Example
- Let's see what typical context looks like:
- ```typescript
- {
- currentDirectory: "/projects/gemini-cli",
- gitBranch: "main",
- openFiles: ["src/index.ts", "README.md"],
- memoryUsage: "1.2GB"
- }
- ```
- This tells you:
- - You're in the "gemini-cli" folder
- - On the "main" Git branch
- - With two files open
- - Using 1.2GB of memory
- ## Behind the Scenes
- The context manager gathers information from different sources (simplified):
- ```typescript
- function gatherContext() {
- return {
- // Get current folder
- currentDirectory: process.cwd(),
- // Check Git branch
- gitBranch: getGitBranch(),
- // Check memory usage
- memoryUsage: process.memoryUsage()
- };
- }
- ```
- Key parts:
- 1. Uses Node's `process` for basic info
- 2. Calls Git for branch details
- 3. Combines everything into one object
- ## Displaying Context
- The CLI shows this information in the footer:
- ```typescript
- function Footer() {
- const context = useContext();
- return (
- <Text>
- {context.currentDirectory} | {context.gitBranch} | {context.memoryUsage}
- </Text>
- );
- }
- ```
- This creates a helpful status bar at the bottom of your terminal.
- ## Common Patterns
- You'll often use context to:
- 1. **Check Location**: See your current folder
- 2. **Monitor Resources**: Watch memory usage
- 3. **Track Changes**: See Git branch status
- ## What's Next?
- Now you understand how Context Management keeps you informed about your work environment! In [Chapter 55: User Context Management](55_user_context_management_.md), we'll learn how to personalize and save your preferences across sessions.
- > Pro Tip: Try running different commands and watch how the context information updates in real-time!
- ---
- # Chapter 55: User Context Management
- Welcome back! In [Chapter 54: Context Management](54_context_management_.md), we learned how your CLI tracks your current work environment. Now, let's meet your app's **personal assistant** - User Context Management that remembers your preferences and identity across sessions, just like a helpful butler who knows exactly how you like your coffee every morning!
- ## Why Do We Need User Context?
- Imagine you're using a shared computer. You'd want:
- - Your settings to stay the same when you return
- - The CLI to remember who you are
- - Your preferences to carry over between sessions
- User Context Management does exactly this! It's like having a digital assistant that:
- 1. Remembers your login (even after closing the app)
- 2. Saves your preferences (like theme colors)
- 3. Keeps your work organized (with unique IDs)
- ## Meet Your Digital ID Card
- The system tracks three key things about you:
- 1. **Installation ID**: A unique number for your computer
- 2. **Google Account**: If you're logged in (optional)
- 3. **Preferences**: Your saved settings
- Here's how simple it is to get your installation ID:
- ```typescript
- import { getInstallationId } from 'gemini-cli';
- // Get your unique computer ID
- const id = getInstallationId();
- console.log(id); // "a1b2c3d4-..."
- ```
- This ID stays the same every time you use the CLI on this computer.
- ## How User Context Works
- When you start the CLI, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Gemini CLI
- participant Files as Your Computer
- You->>CLI: Starts the app
- CLI->>Files: Checks for existing ID
- Files-->>CLI: "No ID found"
- CLI->>Files: Creates new ID
- Files-->>CLI: "ID: a1b2c3d4"
- CLI->>You: Ready with your ID!
- ```
- ## A Simple Example
- Let's see how the system manages your identity:
- ```typescript
- // First run - creates new ID
- const firstId = getInstallationId();
- // Later runs - same ID
- const sameId = getInstallationId();
- console.log(firstId === sameId); // true
- ```
- This ensures you keep the same ID across sessions.
- ## Behind the Scenes
- The system stores your ID in a special file (simplified):
- ```typescript
- function getInstallationId() {
- // 1. Check if ID file exists
- if (fileExists('installation_id')) {
- return readFile('installation_id');
- }
- // 2. If not, create new ID
- const newId = generateRandomId();
- saveToFile('installation_id', newId);
- return newId;
- }
- ```
- Key steps:
- 1. Looks for existing ID
- 2. Creates new one if needed
- 3. Saves it for next time
- ## Handling Google Accounts
- If you log in with Google, it adds extra info:
- ```typescript
- function getUserIdentity() {
- const googleId = getGoogleAccountId();
- if (googleId) {
- return `google:${googleId}`;
- }
- return `local:${getInstallationId()}`;
- }
- ```
- This combines your computer ID with Google info if available.
- ## Common Patterns
- You'll often see user context used to:
- 1. **Personalize Experience**: Remember your settings
- 2. **Track Usage**: (Anonymously) improve the app
- 3. **Secure Access**: Verify it's really you
- ## What's Next?
- Now you understand how User Context Management keeps track of your preferences and identity! In [Chapter 56: Event Logging](56_event_logging_.md), we'll learn how your CLI records important actions to help improve the app.
- > Pro Tip: Try checking your installation ID file in `~/.gemini/installation_id` to see how it's stored!
- ---
- # Chapter 56: Event Logging
- Welcome back! In [Chapter 55: User Context Management](55_user_context_management_.md), we learned how your CLI remembers your preferences and identity. Now, let's meet your app's **flight recorder** - Event Logging that quietly tracks important activities in your CLI, just like an airplane's black box that records everything happening during a flight!
- ## Why Do We Need Event Logging?
- Imagine you're a pilot. After each flight, you'd want to review:
- - What route you took
- - How the engines performed
- - Any issues that came up
- Event Logging does exactly this for your CLI! It automatically records:
- 1. Commands you run
- 2. Tools you use
- 3. Errors that occur
- 4. System performance
- This helps developers improve the CLI by understanding how people actually use it.
- ## Meet the Simple Logger
- Event Logging works like a helpful assistant taking notes with three simple rules:
- 1. **Be Quiet**: Runs in the background without bothering you
- 2. **Be Helpful**: Only records useful information
- 3. **Be Safe**: Never collects personal data
- Here's how simple it is to log an event:
- ```typescript
- import { logEvent } from 'gemini-cli';
- // Log when a tool runs
- logEvent('tool_used', { name: 'search', duration: 1200 });
- ```
- This records that the search tool ran and took 1.2 seconds.
- ## How Event Logging Works
- When something happens in your CLI, here's what occurs behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Logger as Event Logger
- You->>CLI: Runs search tool
- CLI->>Logger: "Tool ran: search"
- Logger->>Logger: Records the event
- CLI->>You: Shows search results
- ```
- ## A Simple Example
- Let's see what typical logged events look like:
- ```typescript
- // Sample event when asking a question
- {
- type: "question_asked",
- text: "What's the weather?", // (shortened for privacy)
- length: 18 // Characters
- }
- // Sample tool event
- {
- type: "tool_ran",
- name: "file_edit",
- duration: 500 // Milliseconds
- }
- ```
- These show what happened without revealing private details.
- ## Behind the Scenes
- The logger works in three simple steps (simplified from our code):
- ```typescript
- class EventLogger {
- private events = [];
- log(type, data) {
- // 1. Create event with timestamp
- const event = {
- type,
- time: new Date(),
- ...data
- };
- // 2. Add to event list
- this.events.push(event);
- // 3. Occasionally send batches
- if (this.events.length > 10) {
- this.sendEvents();
- }
- }
- }
- ```
- Key parts:
- 1. Creates event objects
- 2. Stores them temporarily
- 3. Sends in batches for efficiency
- ## What Gets Logged?
- The system carefully tracks only helpful technical information:
- - Command names (like "search" or "ask")
- - Performance metrics (how long things take)
- - Error types (without personal details)
- - Basic system info (like OS version)
- ## Controlling Logging
- You can always check or change logging settings:
- ```typescript
- import { isLoggingEnabled, setLoggingEnabled } from 'gemini-cli';
- // See current setting
- console.log(isLoggingEnabled());
- // Disable if preferred
- setLoggingEnabled(false);
- ```
- ## What's Next?
- Now you understand how Event Logging helps improve your CLI by recording usage patterns! In [Chapter 57: Activity Logger](57_activity_logger_.md), we'll explore more advanced ways to track and analyze CLI activities.
- > Pro Tip: Try running different commands and check your event logs to see what gets recorded!
- ---
- # Chapter 57: Activity Logger
- Welcome back! In [Chapter 56: Event Logging](56_event_logging_.md), we learned how your CLI records important actions. Now, let's meet your app's **time machine** - the Activity Logger that remembers everything you do, allowing you to revisit past conversations or pick up where you left off, just like a journal that keeps all your thoughts and adventures safe to read later!
- ## Why Do We Need an Activity Logger?
- Imagine you're having an important conversation with Gemini about a coding project, and suddenly:
- - Your computer crashes
- - You need to take a break
- - You want to review what you discussed earlier
- The Activity Logger solves these problems by:
- 1. Recording your entire conversation history
- 2. Saving checkpoints so you can resume later
- 3. Letting you review past interactions
- It's like having a personal secretary who takes perfect notes of everything you do!
- ## Meet Your Digital Notebook
- The Activity Logger works like a smart notebook with three key features:
- 1. **Session History**: Records every message in your conversation
- 2. **Checkpoints**: Saves important moments to return to
- 3. **Search**: Lets you find past conversations easily
- Here's how simple it is to log an activity:
- ```typescript
- import { activityLogger } from 'gemini-cli';
- // Log a user message
- await activityLogger.logMessage('user', 'How do I fix this bug?');
- ```
- This adds your question to the session history automatically.
- ## How Activity Logging Works
- When you chat with Gemini, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Logger as Activity Logger
- participant File as Log File
- You->>Logger: "How do I fix this bug?"
- Logger->>File: Saves message with timestamp
- File-->>Logger: Confirms save
- Logger->>You: Continues conversation
- ```
- ## A Simple Example
- Let's see how to save and load checkpoints:
- ```typescript
- // Save current conversation state
- await activityLogger.saveCheckpoint(conversation);
- // Later, load it back
- const savedConversation = await activityLogger.loadCheckpoint();
- ```
- This lets you pause and resume your work anytime!
- ## Behind the Scenes
- The logger stores messages in a simple format (simplified from our code):
- ```typescript
- interface LogEntry {
- sessionId: string; // Which conversation
- messageId: number; // Message number
- type: 'user' | 'model'; // Who sent it
- message: string; // The actual text
- timestamp: string; // When it happened
- }
- ```
- Key parts:
- - Each message gets a unique ID
- - Tracks who sent it (you or Gemini)
- - Includes exact timing
- ## Real-World Implementation
- Here's how we actually save logs (simplified from `packages/core/src/core/logger.ts`):
- ```typescript
- async function saveLog(entry) {
- // 1. Read existing logs
- const allLogs = await readLogFile();
- // 2. Add new entry
- allLogs.push(entry);
- // 3. Save back to file
- await writeLogFile(allLogs);
- }
- ```
- Key steps:
- 1. Gets current log contents
- 2. Adds the new message
- 3. Saves everything back
- ## Handling Special Cases
- The logger also manages tricky situations:
- - Corrupted log files (makes backups)
- - Concurrent access (prevents conflicts)
- - Large histories (handles them efficiently)
- ## What's Next?
- Now you understand how the Activity Logger keeps track of all your CLI interactions! In [Chapter 58: File Processing Pipeline](58_file_processing_pipeline_.md), we'll learn how your CLI handles file operations efficiently.
- > Pro Tip: Try using `loadCheckpoint()` after restarting your CLI to continue right where you left off!
- ---
- # Chapter 58: File Processing Pipeline
- Welcome back! In [Chapter 57: Activity Logger](57_activity_logger_.md), we learned how your CLI remembers all your past conversations. Now, let's meet your app's **file inspector** - the File Processing Pipeline that automatically reads and understands different file types, just like a smart scanner that can tell whether a document is a recipe, a photo, or a contract!
- ## Why Do We Need a File Processing Pipeline?
- Imagine you're working on a project with:
- - Text files (like notes or code)
- - Images (screenshots or diagrams)
- - PDFs (reports or documentation)
- When you ask Gemini about these files, it needs to:
- 1. Know what type each file is
- 2. Read it correctly (text vs binary)
- 3. Prepare it for Gemini to understand
- The File Processing Pipeline does all this automatically! It's like having a personal assistant who can:
- - Read your handwritten notes (text files)
- - Describe photos (images)
- - Summarize PDFs (documents)
- ## Meet the Three-Step Process
- The pipeline works in three simple steps:
- 1. **Detection**: What kind of file is this? (Text, image, PDF)
- 2. **Reading**: Get the file's contents safely
- 3. **Preparing**: Format it for Gemini to use
- Here's how simple it is to process a file:
- ```typescript
- import { processFile } from 'gemini-cli';
- // Process a file automatically
- const result = await processFile('notes.txt');
- console.log(result.content); // Shows the file's text
- ```
- This automatically detects `notes.txt` as a text file and reads its contents.
- ## How File Processing Works
- When you give the pipeline a file, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Pipeline as File Pipeline
- participant File as Your File
- You->>Pipeline: "Read notes.txt"
- Pipeline->>File: Checks file type
- File-->>Pipeline: "It's text!"
- Pipeline->>File: Reads contents
- File-->>Pipeline: Returns text
- Pipeline->>You: Gives formatted content
- ```
- ## A Simple Example
- Let's process different file types:
- ```typescript
- // Text file
- const textResult = await processFile('notes.txt');
- // Returns the text content
- // Image file
- const imageResult = await processFile('diagram.png');
- // Returns a description Gemini can understand
- // PDF file
- const pdfResult = await processFile('report.pdf');
- // Extracts text from the PDF
- ```
- The pipeline handles each file type differently behind the scenes.
- ## Behind the Scenes
- The pipeline first detects the file type (simplified from our code):
- ```typescript
- function detectFileType(filePath) {
- const extension = filePath.split('.').pop();
- if (['txt', 'md', 'js'].includes(extension)) {
- return 'text';
- }
- if (['png', 'jpg'].includes(extension)) {
- return 'image';
- }
- if (extension === 'pdf') {
- return 'pdf';
- }
- return 'unknown';
- }
- ```
- Key parts:
- 1. Checks the file extension
- 2. Categorizes as text, image, or PDF
- 3. Handles unknown types safely
- ## Reading Different Files
- Then it reads each type appropriately:
- ```typescript
- async function readFile(filePath, type) {
- if (type === 'text') {
- return fs.readFile(filePath, 'utf8');
- }
- if (type === 'image' || type === 'pdf') {
- return fs.readFile(filePath); // Binary data
- }
- }
- ```
- Text files get read as UTF-8, while images/PDFs are read as binary data.
- ## Safety Features
- The pipeline includes important protections:
- - Checks file permissions first
- - Limits file sizes for safety
- - Handles errors gracefully
- ```typescript
- try {
- return await processFile('notes.txt');
- } catch (error) {
- console.log("Couldn't read file:", error.message);
- }
- ```
- ## What's Next?
- Now you understand how the File Processing Pipeline handles different file types automatically! In [Chapter 59: API Server Interface](59_api_server_interface_.md), we'll learn how your CLI communicates with Gemini's servers.
- > Pro Tip: Try processing different file types to see how the pipeline handles each one!
- ---
- # Chapter 59: API Server Interface
- Welcome back! In [Chapter 58: File Processing Pipeline](58_file_processing_pipeline_.md), we learned how your CLI handles different file types. Now, let's meet your app's **telephone operator** - the API Server Interface that connects your CLI to Gemini's powerful brain, just like a helpful receptionist who routes your calls to the right department!
- ## Why Do We Need an API Server Interface?
- Imagine you're calling a big company. Instead of dialing each department directly, you call the main number and the operator:
- 1. Connects you to the right person
- 2. Translates your request into their system
- 3. Brings back the answer in a way you understand
- The API Server Interface does exactly this for your CLI! It:
- 1. Routes your questions to the correct Gemini service
- 2. Formats your requests properly
- 3. Returns the responses in a clean, usable way
- ## Meet the Helpful Operator
- Our API Server Interface has three simple jobs:
- 1. **Connection**: Links your CLI to Gemini's servers
- 2. **Translation**: Converts between your CLI's format and Gemini's
- 3. **Delivery**: Brings back responses quickly and reliably
- Here's how simple it is to ask a question through the interface:
- ```typescript
- import { askGemini } from 'gemini-cli';
- // Ask Gemini a question
- const response = await askGemini("What's 2+2?");
- console.log(response); // "4"
- ```
- This shows how easy it is to get answers through the interface!
- ## How the Interface Works
- When you ask a question, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Interface as API Interface
- participant Gemini as Gemini Servers
- You->>CLI: "What's 2+2?"
- CLI->>Interface: Formats question
- Interface->>Gemini: Sends to correct server
- Gemini-->>Interface: Returns "4"
- Interface->>CLI: Formats response
- CLI->>You: Shows answer
- ```
- ## A Simple Example
- Let's see how the interface handles different requests:
- ```typescript
- // Simple question
- await askGemini("Hello!");
- // File processing request
- await processFileWithGemini("notes.txt");
- // Tool execution
- await runToolThroughGemini("search", {query: "pizza"});
- ```
- Each request gets routed to the right Gemini service automatically.
- ## Behind the Scenes
- The interface carefully manages connections (simplified from our code):
- ```typescript
- class ApiInterface {
- async sendRequest(type, data) {
- // 1. Find the right service
- const service = this.findService(type);
- // 2. Format the request
- const formatted = service.formatRequest(data);
- // 3. Send and get response
- return await service.send(formatted);
- }
- }
- ```
- Key steps:
- 1. Identifies which service to use
- 2. Prepares the request properly
- 3. Handles the response
- ## Handling Different Requests
- The interface is smart enough to route various request types:
- ```typescript
- // Routes to content generation
- interface.sendRequest('generate', {prompt: "Hello"});
- // Routes to embeddings
- interface.sendRequest('embed', {text: "Hello"});
- // Routes to token counting
- interface.sendRequest('count', {text: "Hello"});
- ```
- Each type goes to the appropriate Gemini service behind the scenes.
- ## Safety Features
- The interface includes important protections:
- - Automatic retries if connections fail
- - Timeouts to prevent hanging
- - Error handling for bad responses
- ```typescript
- try {
- return await askGemini("What's 2+2?");
- } catch (error) {
- console.log("Oops! Let me try again...");
- }
- ```
- ## What's Next?
- Now you understand how the API Server Interface connects your CLI to Gemini's powerful services! In [Chapter 60: Command Processing](60_command_processing_.md), we'll learn how your CLI understands and executes the commands you type.
- > Pro Tip: Try asking different types of questions to see how the interface handles each one!
- ---
- # Chapter 60: Command Processing
- Welcome back! In [Chapter 59: API Server Interface](59_api_server_interface_.md), we learned how your CLI connects to Gemini's powerful servers. Now, let's meet your app's **traffic director** - Command Processing that handles special instructions starting with `/` or `@`, just like a helpful receptionist who routes your calls to the right department!
- ## Why Do We Need Command Processing?
- Imagine you're in a fancy hotel. You might say:
- - "/help" to call the front desk
- - "@roomservice" to order food
- - "!lights" to control your room
- Command Processing does exactly this for your CLI! It recognizes special commands like:
- - `/help` - Shows help information
- - `@file.txt` - Includes a file's contents
- - `!ls` - Runs a shell command
- Without it, your CLI wouldn't know these are special instructions needing special handling!
- ## Meet the Command Types
- Your CLI understands three main command types:
- 1. **Slash Commands**: Start with `/` (like `/help`)
- 2. **At Commands**: Start with `@` (like `@notes.txt`)
- 3. **Bang Commands**: Start with `!` (like `!ls`)
- Here's how simple it is to use them:
- ```typescript
- // Ask for help
- "/help"
- // Include a file
- "@config.json"
- // Run a shell command
- "!date"
- ```
- ## How Command Processing Works
- When you type a command, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Processor as Command Processor
- You->>CLI: Types "/help"
- CLI->>Processor: "Is this a special command?"
- Processor->>Processor: Checks first character
- Processor-->>CLI: "Yes, it's a help command!"
- CLI->>You: Shows help menu
- ```
- ## A Simple Example
- Let's see how different commands get processed:
- ```typescript
- // Slash command (shows help)
- processCommand("/help");
- // At command (includes file)
- processCommand("@notes.txt");
- // Bang command (runs shell)
- processCommand("!pwd");
- ```
- Each type triggers different actions in your CLI.
- ## Behind the Scenes
- The processor checks commands like this (simplified):
- ```typescript
- function processCommand(input) {
- if (input.startsWith('/')) {
- handleSlashCommand(input); // Like /help
- }
- else if (input.startsWith('@')) {
- handleAtCommand(input); // Like @file.txt
- }
- else if (input.startsWith('!')) {
- handleBangCommand(input); // Like !ls
- }
- else {
- // Regular message to Gemini
- sendToGemini(input);
- }
- }
- ```
- Key parts:
- 1. Checks the first character
- 2. Routes to the right handler
- 3. Handles regular messages too
- ## Handling Slash Commands
- The system has many built-in slash commands:
- ```typescript
- const slashCommands = {
- '/help': showHelp,
- '/clear': clearScreen,
- '/theme': changeTheme
- };
- ```
- These are like shortcuts for common actions.
- ## Real-World Implementation
- In our actual code (`packages/cli/src/ui/hooks/slashCommandProcessor.ts`), we handle commands like:
- ```typescript
- // Help command
- if (command === '/help') {
- setShowHelp(true);
- }
- // Theme command
- else if (command === '/theme') {
- openThemeDialog();
- }
- ```
- Each command triggers specific actions in your CLI.
- ## What's Next?
- Now you understand how Command Processing handles special instructions in your CLI! In [Chapter 61: Content Correction System](61_content_correction_system_.md), we'll learn how Gemini can help fix mistakes in your content.
- > Pro Tip: Try different commands like `/help` and `!date` to see how they work!
- ---
- # Chapter 61: Content Correction System
- ---
- # Chapter 62: Content Correction
- Welcome back! In [Chapter 61: Content Correction System](61_content_correction_system_.md), we learned how Gemini can help fix mistakes in files. Now, let's meet your CLI's **helpful proofreader** - Content Correction that automatically fixes formatting and syntax errors in your files, just like an editor who cleans up your writing before publishing!
- ## Why Do We Need Content Correction?
- Imagine you're writing an important document. You might:
- - Make typos or grammar mistakes
- - Forget proper formatting
- - Use inconsistent styles
- Content Correction does exactly this for your code and text files! When you save a file, it:
- 1. Checks for common errors
- 2. Fixes formatting automatically
- 3. Keeps your code clean and consistent
- It's like having a personal assistant who proofreads everything you write!
- ## Meet the Auto-Fixer
- Content Correction handles three main tasks:
- 1. **Formatting**: Fixes indentation and spacing
- 2. **Syntax**: Corrects code structure
- 3. **Style**: Makes everything consistent
- Here's how simple it is to use:
- ```typescript
- import { correctContent } from 'gemini-cli';
- // Fix the formatting in some code
- const fixedCode = await correctContent('const x=5;');
- console.log(fixedCode); // "const x = 5;" (added space)
- ```
- This automatically adds missing spaces around the equals sign.
- ## How Correction Works
- When you correct content, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Corrector as Content Corrector
- participant Gemini as Gemini AI
- You->>Corrector: "const x=5;"
- Corrector->>Gemini: "Fix this code"
- Gemini-->>Corrector: "const x = 5;"
- Corrector->>You: Returns corrected code
- ```
- ## A Simple Example
- Let's fix some Python code:
- ```typescript
- const pythonCode = `
- def hello():
- print("Hello") # Missing indent
- `;
- const fixed = await correctContent(pythonCode);
- console.log(fixed);
- // Output:
- // def hello():
- // print("Hello") # Now properly indented
- ```
- The corrector automatically adds the missing indentation.
- ## Behind the Scenes
- The corrector uses simple rules first (simplified from our code):
- ```typescript
- async function correctContent(text) {
- // 1. Try basic formatting fixes
- const simpleFix = trySimpleFixes(text);
- if (simpleFix !== text) return simpleFix;
- // 2. Ask Gemini for complex fixes
- return await askGeminiToFix(text);
- }
- ```
- Key steps:
- 1. Attempts quick fixes first
- 2. Uses Gemini for harder problems
- 3. Returns the best corrected version
- ## Common Fixes
- You'll often see corrections for:
- 1. **Indentation**: Adding missing tabs/spaces
- 2. **Spacing**: Around operators like = and +
- 3. **Syntax**: Fixing broken code structure
- ## What's Next?
- Now you understand how Content Correction keeps your files clean and error-free! In [Chapter 63: Content Diffing](63_content_diffing_.md), we'll learn how to compare file versions to see what changed.
- > Pro Tip: Try correcting different code snippets to see what improvements Gemini suggests!
- ---
- # Chapter 63: Content Diffing
- Welcome back! In [Chapter 62: Content Correction](62_content_correction_.md), we learned how Gemini can help fix mistakes in your files. Now, let's meet your CLI's **time-traveling detective** - Content Diffing that shows exactly what changed between file versions, just like comparing two photos to spot the differences!
- ## Why Do We Need Content Diffing?
- Imagine you're writing a story and want to see:
- - What changes you made since yesterday
- - Which lines were added or removed
- - If any important parts got deleted by mistake
- Content Diffing does exactly this for your files! It:
- 1. Compares two versions of text
- 2. Highlights all differences
- 3. Shows additions in green and deletions in red
- It's like having a magic highlighter for your changes!
- ## Meet the Text Comparator
- Content Diffing has three simple jobs:
- 1. **Compare**: Looks at old and new text
- 2. **Analyze**: Finds all differences
- 3. **Display**: Shows changes clearly
- Here's how simple it is to compare two versions:
- ```typescript
- import { showDiff } from 'gemini-cli';
- // Compare old and new versions
- showDiff("Hello world", "Hello there");
- ```
- This will display:
- ```
- Hello world
- Hello there
- ```
- With "world" in red (removed) and "there" in green (added).
- ## How Diffing Works
- When you compare files, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Diff as Diff Tool
- participant Old as Old Version
- participant New as New Version
- You->>Diff: Compare these!
- Diff->>Old: Gets original text
- Diff->>New: Gets new text
- Diff->>Diff: Finds differences
- Diff->>You: Shows changes
- ```
- ## A Simple Example
- Let's see a real code comparison:
- ```typescript
- const oldCode = `
- function greet() {
- return "Hello";
- }
- `;
- const newCode = `
- function greet(name) {
- return "Hello " + name;
- }
- `;
- showDiff(oldCode, newCode);
- ```
- This will highlight:
- - The added `(name)` parameter
- - The changed return line
- ## Behind the Scenes
- The diff tool works line-by-line (simplified):
- ```typescript
- function findDifferences(oldText, newText) {
- // 1. Split into lines
- const oldLines = oldText.split('\n');
- const newLines = newText.split('\n');
- // 2. Compare each line
- return compareLines(oldLines, newLines);
- }
- ```
- Key steps:
- 1. Breaks text into lines
- 2. Compares them one by one
- 3. Marks additions and deletions
- ## Viewing Changes
- The system shows differences in an easy-to-read format:
- ```
- function greet() {
- +function greet(name) {
- - return "Hello";
- + return "Hello " + name;
- }
- ```
- Where:
- - `+` marks added lines (green)
- - `-` marks removed lines (red)
- ## Common Uses
- You'll often use Content Diffing to:
- 1. **Review Edits**: See what changed in your code
- 2. **Check Corrections**: Verify Gemini's fixes
- 3. **Compare Versions**: Look at file history
- ## What's Next?
- Now you understand how Content Diffing helps track changes in your files! In [Chapter 64: File System Utilities](64_file_system_utilities_.md), we'll explore more tools for working with files and folders.
- > Pro Tip: Try comparing different versions of a file to see all your changes highlighted!
- ---
- # Chapter 64: File System Utilities
- Welcome back! In [Chapter 63: Content Diffing](63_content_diffing_.md), we learned how to compare different versions of files. Now, let's meet your CLI's **digital GPS** - File System Utilities that help you navigate and organize files effortlessly, just like a map app that shows you the best routes through your computer's folders!
- ## Why Do We Need File System Utilities?
- Imagine you're exploring a new city without a map. You might:
- - Get lost in unfamiliar neighborhoods (folders)
- - Waste time going in circles (repeating searches)
- - Miss important landmarks (files)
- File System Utilities solve these problems by providing:
- 1. **Path Helpers**: Shortcuts for common file operations
- 2. **Smart Navigation**: Tools to find files quickly
- 3. **Safety Checks**: Protection against dangerous locations
- It's like having a friendly tour guide for your computer's file system!
- ## Meet Your File System Guides
- Our utilities offer three main navigation tools:
- 1. **Path Shorteners**: Make long file paths easier to read
- 2. **Relative Paths**: Show how to get from one folder to another
- 3. **Safe Escaping**: Handle spaces in file names properly
- Here's how simple it is to shorten a long path:
- ```typescript
- import { shortenPath } from 'gemini-cli';
- // Make a long path readable
- const short = shortenPath('/users/me/projects/gemini-cli/src/index.ts');
- console.log(short); // "/users/.../gemini-cli/src/index.ts"
- ```
- This keeps the important parts while hiding the middle sections.
- ## How Path Utilities Work
- When you shorten a path, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Utility as Path Utility
- participant Path as Long Path
- You->>Utility: "Shorten this path"
- Utility->>Path: Analyzes structure
- Path-->>Utility: Returns segments
- Utility->>Utility: Keeps start/end
- Utility->>You: Returns shortened version
- ```
- ## A Simple Example
- Let's find the relative path between two folders:
- ```typescript
- import { makeRelative } from 'gemini-cli';
- // How to get from /projects to /projects/gemini-cli/src
- const relative = makeRelative('/projects/gemini-cli/src', '/projects');
- console.log(relative); // "gemini-cli/src"
- ```
- This shows the "directions" from one folder to another.
- ## Behind the Scenes
- The path utilities use simple logic (simplified from our code):
- ```typescript
- function shortenPath(fullPath, maxLength = 35) {
- // 1. Split path into parts
- const parts = fullPath.split('/');
- // 2. If too long, keep first/last parts
- if (fullPath.length > maxLength) {
- return `${parts[0]}/.../${parts[parts.length-1]}`;
- }
- // 3. Otherwise return full path
- return fullPath;
- }
- ```
- Key steps:
- 1. Breaks path into segments
- 2. Checks if it's too long
- 3. Simplifies if needed
- ## Handling Special Cases
- The utilities also manage tricky situations:
- - Paths with spaces (escapes them properly)
- - Home directory shortcuts (converts `~` to full path)
- - Different operating systems (handles Windows/Mac paths)
- ```typescript
- // Escape spaces in a path
- const safePath = escapePath('my documents/file.txt');
- // Returns "my\ documents/file.txt"
- ```
- ## Common Patterns
- You'll often use these utilities to:
- 1. **Display Paths**: Show clean paths in your UI
- 2. **Navigate Folders**: Move between directories
- 3. **Handle User Input**: Process file paths safely
- ## What's Next?
- Now you understand how File System Utilities help navigate your computer's folders! In [Chapter 65: History Management](65_history_management_.md), we'll learn how your CLI remembers past commands and conversations.
- > Pro Tip: Try using `shortenPath` with different lengths to see how it adapts to your needs!
- ---
- # Chapter 65: History Management
- Welcome back! In [Chapter 64: File System Utilities](64_file_system_utilities_.md), we learned how to navigate files and folders in your CLI. Now, let's meet your app's **memory keeper** - History Management that remembers all your past commands and conversations, just like a notebook that keeps track of everything you've discussed with Gemini!
- ## Why Do We Need History Management?
- Imagine you're having a long conversation with a friend. You wouldn't want to:
- - Repeat yourself constantly
- - Forget important details you discussed earlier
- - Lose track of the conversation flow
- History Management solves these problems by:
- 1. Remembering every message in your chat
- 2. Preventing duplicate messages
- 3. Giving each message a unique ID
- 4. Letting you save and load conversations
- It's like having a perfect memory for your CLI chats!
- ## Meet Your Conversation Notebook
- The History Manager works like a smart notebook with three key features:
- 1. **Message Tracking**: Records every question and answer
- 2. **Duplicate Prevention**: Skips identical back-to-back messages
- 3. **ID Assignment**: Gives each message a unique number
- Here's how simple it is to add a message to history:
- ```typescript
- import { useHistory } from 'gemini-cli';
- const { addItem } = useHistory();
- addItem({ type: 'user', text: 'Hello!' }, Date.now());
- ```
- This adds "Hello!" to your chat history with a unique timestamp-based ID.
- ## How History Works
- When you send a message, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant History as History Manager
- participant Chat as Your Chat
- You->>History: "Add this message"
- History->>History: Checks for duplicates
- History->>History: Assigns unique ID
- History->>Chat: Adds to conversation
- Chat->>You: Shows updated history
- ```
- ## A Simple Example
- Let's see how duplicate prevention works:
- ```typescript
- // First message
- addItem({ type: 'user', text: 'Hi!' }, Date.now());
- // Same message again (won't be added)
- addItem({ type: 'user', text: 'Hi!' }, Date.now());
- ```
- The second "Hi!" gets skipped because it's identical to the last message.
- ## Behind the Scenes
- The history manager uses simple counters (simplified from our code):
- ```typescript
- let messageCounter = 0;
- function addMessage(text) {
- // Check if same as last message
- if (lastMessage === text) return;
- // Add with unique ID
- const id = Date.now() + (messageCounter++);
- history.push({ id, text });
- }
- ```
- Key parts:
- 1. Checks for duplicates
- 2. Creates unique IDs
- 3. Adds to history array
- ## Managing Your History
- You can also clear or load saved conversations:
- ```typescript
- // Clear all history
- clearItems();
- // Load saved chat
- loadHistory(savedChat);
- ```
- This lets you start fresh or continue old conversations.
- ## Common Patterns
- You'll often use history management to:
- 1. **Review Past Chats**: See what you discussed earlier
- 2. **Continue Conversations**: Pick up where you left off
- 3. **Save Important Talks**: Keep useful discussions
- ## What's Next?
- Now you understand how History Management keeps track of all your CLI conversations! In [Chapter 66: Memory Management](66_memory_management_.md), we'll learn how your app efficiently handles large amounts of data.
- > Pro Tip: Try using the up/down arrows to navigate through your command history!
- ---
- # Chapter 66: Memory Management
- Welcome back! In [Chapter 65: History Management](65_history_management_.md), we learned how your CLI remembers past conversations. Now, let's meet your app's **digital librarian** - Memory Management that organizes and retrieves reference materials, just like a helpful librarian who knows exactly where every book is stored!
- ## Why Do We Need Memory Management?
- Imagine you're writing a research paper and need to:
- 1. Find notes from last week
- 2. Include quotes from reference books
- 3. Combine information from different sources
- Memory Management does exactly this for your CLI! It:
- - Organizes hierarchical memory files (like a library catalog)
- - Processes imports between files (like following references)
- - Retrieves exactly what you need when you ask
- ## Meet Your Digital Library
- Think of Memory Management as having three simple tools:
- 1. **File Finder**: Locates all your memory files
- 2. **Import Processor**: Combines content from different files
- 3. **Content Organizer**: Structures everything neatly
- Here's how simple it is to find memory files:
- ```typescript
- import { findMemoryFiles } from 'gemini-cli';
- // Find all memory files in current folder
- const files = await findMemoryFiles('./');
- console.log(files); // ["notes.md", "references.md"]
- ```
- This shows all available memory files in your project.
- ## How Memory Works Together
- When you access memory files, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Finder as File Finder
- participant Processor as Import Processor
- participant Files as Your Files
- You->>Finder: "Find memory files"
- Finder->>Files: Searches folders
- Files-->>Finder: Returns file list
- Finder->>Processor: "Combine these files"
- Processor->>You: Returns organized content
- ```
- ## A Simple Example
- Let's see how to combine files with imports:
- ```markdown
- <!-- In main.md -->
- # My Notes
- @references.md
- ```
- ```markdown
- <!-- In references.md -->
- - Source: Gemini CLI Docs
- ```
- The system will combine them into:
- ```
- # My Notes
- - Source: Gemini CLI Docs
- ```
- ## Behind the Scenes
- The import processor works like this (simplified):
- ```typescript
- async function processImports(content) {
- // Find all @import statements
- const imports = content.match(/@(\S+)/g);
- // For each import, read that file
- for (const imp of imports) {
- const importedContent = await readFile(imp);
- content = content.replace(imp, importedContent);
- }
- return content;
- }
- ```
- Key steps:
- 1. Finds `@filename` references
- 2. Reads each imported file
- 3. Combines everything together
- ## Safety Features
- Memory Management includes important protections:
- - Prevents circular imports (A imports B which imports A)
- - Checks file permissions
- - Handles errors gracefully
- ## What's Next?
- Now you understand how Memory Management organizes your CLI's reference materials! In [Chapter 67: Request/Response Formatting](67_request_response_formatting_.md), we'll learn how your CLI structures messages to Gemini's servers.
- > Pro Tip: Try creating simple `.md` files with `@` imports to see how they combine automatically!
- ---
- # Chapter 67: Request/Response Formatting
- Welcome back! In [Chapter 66: Memory Management](66_memory_management_.md), we learned how your CLI organizes and retrieves reference materials. Now, let's meet your app's **package wrapping department** - Request/Response Formatting that carefully prepares messages for Gemini and unpacks its responses, just like gift wrapping presents before sending and carefully unwrapping the replies!
- ## Why Do We Need Request/Response Formatting?
- Imagine you're sending a package to a friend. You wouldn't just throw items loose in a box - you'd:
- 1. Wrap each item carefully (formatting)
- 2. Include clear labels (metadata)
- 3. Pack everything neatly (structure)
- Request/Response Formatting does exactly this for your CLI's messages! It:
- 1. Packages your questions properly for Gemini
- 2. Unpacks Gemini's responses neatly
- 3. Handles special content like files and code
- Without it, your messages might arrive scrambled or Gemini's replies could be hard to understand!
- ## Meet the Gift Wrapping Station
- Our formatting system has two main jobs:
- 1. **Request Wrapping**: Preparing your messages for sending
- 2. **Response Unwrapping**: Making Gemini's replies easy to use
- Here's how simple it is to format a basic question:
- ```typescript
- import { formatRequest } from 'gemini-cli';
- // Wrap a simple question
- const wrappedQuestion = formatRequest("What's 2+2?");
- console.log(wrappedQuestion); // {text: "What's 2+2?"}
- ```
- This creates a properly structured message object ready for Gemini.
- ## How Formatting Works
- When you ask a question, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Wrapper as Request Wrapper
- participant Gemini as Gemini API
- You->>Wrapper: "What's 2+2?"
- Wrapper->>Wrapper: Adds formatting
- Wrapper->>Gemini: Sends neat package
- Gemini-->>Wrapper: Returns response
- Wrapper->>You: Unpacks clean answer
- ```
- ## A Simple Example
- Let's format different types of requests:
- ```typescript
- // Text question
- formatRequest("Hello Gemini!");
- // File content
- formatRequest({file: "notes.txt"});
- // Code snippet
- formatRequest({code: "function hello() { return 'Hi!'; }"});
- ```
- Each gets wrapped appropriately for Gemini to understand.
- ## Behind the Scenes
- The formatter checks content types (simplified from our code):
- ```typescript
- function formatRequest(content) {
- if (typeof content === 'string') {
- return { text: content }; // Simple text
- }
- if (content.file) {
- return { file: readFile(content.file) }; // File content
- }
- if (content.code) {
- return { code: content.code }; // Code block
- }
- }
- ```
- Key parts:
- 1. Handles plain text directly
- 2. Reads files when needed
- 3. Preserves code structure
- ## Handling Responses
- The system also unpacks Gemini's replies:
- ```typescript
- function unpackResponse(response) {
- if (response.text) {
- return response.text; // Simple answer
- }
- if (response.files) {
- return response.files; // File references
- }
- }
- ```
- This ensures you always get responses in a usable format.
- ## Common Patterns
- You'll often use formatting for:
- 1. **Simple Questions**: Basic text queries
- 2. **File Operations**: Sending/receiving files
- 3. **Code Help**: Sharing and discussing code
- ## What's Next?
- Now you understand how Request/Response Formatting prepares messages for Gemini! In [Chapter 68: Gemini Stream Processing](68_gemini_stream_processing_.md), we'll learn how your CLI handles responses that come in multiple parts.
- > Pro Tip: Try formatting different types of content to see how they get packaged for Gemini!
- ---
- # Chapter 68: Gemini Stream Processing
- Welcome back! In [Chapter 67: Request/Response Formatting](67_request_response_formatting_.md), we learned how your CLI packages messages for Gemini. Now, let's meet your app's **conversation manager** - Gemini Stream Processing that handles the back-and-forth flow with Gemini, just like a telephone operator connecting your calls and making sure everyone gets their turn to speak!
- ## Why Do We Need Stream Processing?
- Imagine you're having a phone conversation where:
- - You ask a question ("What's the weather?")
- - Gemini starts answering ("It's currently sunny...")
- - More details keep coming ("...with a high of 75°F...")
- - The answer arrives in pieces over time
- Stream Processing manages this entire flow by:
- 1. Sending your questions to Gemini
- 2. Receiving responses piece by piece
- 3. Showing updates as they arrive
- 4. Handling any tools Gemini needs to use
- Without it, your conversation would feel choppy and disconnected!
- ## Meet the Conversation Flow
- Stream Processing handles three main tasks:
- 1. **Sending**: Your questions to Gemini
- 2. **Receiving**: Responses as they stream in
- 3. **Managing**: Tools or follow-up questions
- Here's how simple it is to start a conversation:
- ```typescript
- import { startStream } from 'gemini-cli';
- // Ask a question and get streaming responses
- const stream = startStream("What's the weather?");
- ```
- This begins the conversation and prepares to receive Gemini's response.
- ## How Streaming Works
- When you ask a question, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Stream as Stream Processor
- participant Gemini as Gemini
- You->>Stream: "What's the weather?"
- Stream->>Gemini: Sends question
- Gemini-->>Stream: "It's currently sunny..."
- Stream->>You: Shows first part
- Gemini-->>Stream: "...with a high of 75°F"
- Stream->>You: Updates with more
- ```
- ## A Simple Example
- Let's see streaming in action:
- ```typescript
- // Start the stream
- const stream = startStream("Tell me about dogs");
- // Handle responses as they arrive
- for await (const chunk of stream) {
- console.log(chunk); // Shows pieces of the answer
- }
- ```
- This will display Gemini's response in parts as they become available.
- ## Behind the Scenes
- The stream processor works in three steps (simplified from our code):
- ```typescript
- async function processStream(question) {
- // 1. Send the question
- const connection = connectToGemini(question);
- // 2. Receive chunks
- for await (const chunk of connection) {
- // 3. Show each piece
- displayChunk(chunk);
- }
- }
- ```
- Key parts:
- 1. Establishes the connection
- 2. Listens for response pieces
- 3. Displays them as they arrive
- ## Handling Special Cases
- The processor also manages:
- - Network interruptions (automatically retries)
- - Long responses (shows "..." while waiting)
- - Tool requests (pauses to run tools)
- ```typescript
- // Example of handling a tool request
- stream.on('tool', (tool) => {
- runTool(tool); // Runs the requested tool
- });
- ```
- ## Common Patterns
- You'll often use stream processing for:
- 1. **Long Answers**: That come in multiple parts
- 2. **Interactive Chats**: Where you respond to Gemini
- 3. **Tool-Using Queries**: That require external actions
- ## What's Next?
- Now you understand how Gemini Stream Processing manages your conversation flow! In [Chapter 69: Extension System](69_extension_system_.md), we'll learn how to add new capabilities to your CLI.
- > Pro Tip: Try asking Gemini a complex question to see the response stream in pieces!
- ---
- # Chapter 69: Extension System
- Welcome back! In [Chapter 68: Gemini Stream Processing](68_gemini_stream_processing_.md), we learned how your CLI manages conversations with Gemini. Now, let's meet your app's **plugin store** - the Extension System that lets you add new features to your CLI, just like installing apps on your phone to get more capabilities!
- ## Why Do We Need Extensions?
- Imagine your CLI is like a basic phone - it can make calls and send texts, but you want more. Extensions let you:
- - Add new tools (like a calculator app)
- - Connect to other services (like social media apps)
- - Customize your experience (like new themes)
- Without extensions, your CLI would be limited to only what comes built-in. With them, you can teach it new tricks!
- ## Meet the Three Simple Parts
- Extensions work through three easy concepts:
- 1. **Extension Packages**: Bundles of new functionality (like app install files)
- 2. **Configuration Files**: Instructions for how to install them
- 3. **Loading System**: The process that adds them to your CLI
- Here's how simple it is to load extensions:
- ```typescript
- import { loadExtensions } from 'gemini-cli';
- // Load all available extensions
- const extensions = loadExtensions();
- console.log(extensions[0].name); // Shows first extension's name
- ```
- This finds and prepares all extensions in your system.
- ## How Extensions Work Together
- When you load extensions, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant Extensions as Extensions Folder
- You->>CLI: "Load extensions"
- CLI->>Extensions: Checks folders
- Extensions-->>CLI: Returns extension list
- CLI->>You: Ready to use new features!
- ```
- ## A Simple Example
- Let's look at a basic extension configuration:
- ```json
- // In gemini-extension.json
- {
- "name": "weather-tool",
- "version": "1.0",
- "contextFileName": "weather.md"
- }
- ```
- This defines:
- - The extension's name
- - Its version
- - A file with instructions
- ## Behind the Scenes
- The extension loader works in three steps (simplified from our code):
- ```typescript
- function loadExtension(folder) {
- // 1. Find config file
- const config = readConfig(folder);
- // 2. Check required fields
- if (!config.name || !config.version) return null;
- // 3. Prepare extension
- return {
- config,
- files: findContextFiles(config)
- };
- }
- ```
- Key parts:
- 1. Looks for configuration
- 2. Validates the extension
- 3. Gets it ready to use
- ## Finding Extensions
- The system checks two main locations:
- 1. Your project folder (for workspace-specific extensions)
- 2. Your home directory (for personal extensions)
- ```typescript
- const extensions = [
- ...loadFromFolder(projectPath),
- ...loadFromFolder(homePath)
- ];
- ```
- This combines extensions from both locations.
- ## Common Extension Uses
- You'll often use extensions to:
- 1. **Add Tools**: Like weather lookup or calculators
- 2. **Connect Services**: Link to other APIs
- 3. **Customize**: Change how your CLI looks or works
- ## What's Next?
- Now you understand how the Extension System lets you add new powers to your CLI! In [Chapter 70: MCP Tools](70_mcp_tools_.md), we'll explore special extensions that connect to remote services.
- > Pro Tip: Try creating a simple `gemini-extension.json` file to see how extensions are configured!
- ---
- # Chapter 70: MCP Tools
- Welcome back! In [Chapter 69: Extension System](69_extension_system_.md), we learned how to add new features to your CLI. Now, let's meet your app's **international translator** - MCP Tools that connect your CLI to powerful remote services, just like having a personal interpreter who helps you communicate with experts around the world!
- ## Why Do We Need MCP Tools?
- Imagine you're traveling in a foreign country and need:
- - A local guide (to show you around)
- - A translator (to help you communicate)
- - A connection to special services (like medical help)
- MCP Tools do exactly this for your CLI! They:
- 1. Connect to remote servers with special tools
- 2. Translate between your CLI and those services
- 3. Let you use powerful features from anywhere
- For example, you could ask Gemini to "Check server status in Tokyo" and an MCP Tool would connect to a Tokyo server to get the answer!
- ## Meet the Remote Helpers
- MCP Tools work through three simple concepts:
- 1. **Discovery**: Finding available remote tools
- 2. **Permission**: Asking before using them
- 3. **Execution**: Running the tools safely
- Here's how simple it is to discover remote tools:
- ```typescript
- import { discoverMcpTools } from 'gemini-cli';
- // Find tools from a server
- const tools = await discoverMcpTools('tokyo-server');
- console.log(tools[0].name); // "server-monitor"
- ```
- This shows all tools available from the "tokyo-server".
- ## How MCP Tools Work
- When you use a remote tool, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant CLI as Your CLI
- participant MCP as MCP Tool
- participant Server as Remote Server
- You->>CLI: "Check Tokyo server"
- CLI->>MCP: Finds the right tool
- MCP->>You: "Allow this connection?"
- You->>MCP: "Yes!"
- MCP->>Server: Runs the check
- Server-->>MCP: Returns status
- MCP->>You: Shows results
- ```
- ## A Simple Example
- Let's use a remote monitoring tool:
- ```typescript
- // Get the server status tool
- const monitor = mcpTools.find(t => t.name === 'server-status');
- // Run it (will ask for permission first)
- const result = await monitor.run({ location: 'tokyo' });
- console.log(result); // "Tokyo server: Online"
- ```
- This safely connects to the remote server and returns its status.
- ## Behind the Scenes
- The MCP Tool system checks permissions (simplified from our code):
- ```typescript
- class McpTool {
- async checkPermission() {
- if (this.trusted) return true; // No need to ask
- // Show confirmation dialog
- return askUser(`Allow ${this.server} to run ${this.name}?`);
- }
- }
- ```
- Key parts:
- 1. Checks if the server is trusted
- 2. Asks for user confirmation if not
- 3. Only runs after getting permission
- ## Safety Features
- MCP Tools include important protections:
- - Always ask before connecting to new servers
- - Remember your permission choices
- - Timeout if responses take too long
- ```typescript
- // Run with 5-second timeout
- await tool.run(params, { timeout: 5000 });
- ```
- ## Common Uses
- You'll often use MCP Tools for:
- 1. **Remote Monitoring**: Checking servers worldwide
- 2. **Specialized Services**: Accessing unique tools
- 3. **Team Collaboration**: Sharing tools securely
- ## What's Next?
- Now you understand how MCP Tools connect your CLI to powerful remote services! In [Chapter 71: File Discovery Service](71_file_discovery_service_.md), we'll learn how your CLI efficiently finds files when you need them.
- > Pro Tip: Try discovering available MCP Tools from different servers to see what special features they offer!
- ---
- # Chapter 71: File Discovery Service
- Welcome back! In [Chapter 70: MCP Tools](70_mcp_tools_.md), we learned how to connect your CLI to powerful remote services. Now, let's meet your app's **digital detective** - the File Discovery Service that helps you quickly find files in your project, just like a searchlight that instantly spots what you're looking for in a dark room!
- ## Why Do We Need File Discovery?
- Imagine you're working on a big coding project with hundreds of files. You need to:
- - Find all JavaScript files (`*.js`)
- - Locate configuration files (`config.*`)
- - Search for specific function names
- Manually looking through folders would take forever! The File Discovery Service solves this by:
- 1. Searching your entire project instantly
- 2. Filtering files by name, type, or content
- 3. Respecting ignore rules (like `.gitignore`)
- It's like having a super-powered search engine just for your code!
- ## Meet the File Finder
- The File Discovery Service has two simple jobs:
- 1. **Finding Files**: Locates all files matching your criteria
- 2. **Filtering Files**: Skips files you want to ignore
- Here's how easy it is to find all JavaScript files:
- ```typescript
- import { findFiles } from 'gemini-cli';
- // Find all .js files
- const jsFiles = await findFiles('*.js');
- console.log(jsFiles); // ["src/index.js", "utils/helper.js", ...]
- ```
- This returns an array of all JavaScript files in your project.
- ## How File Discovery Works
- When you search for files, here's what happens behind the scenes:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Finder as File Finder
- participant Project as Project Files
- You->>Finder: "Find *.js files"
- Finder->>Project: Searches all folders
- Project-->>Finder: Returns matching files
- Finder->>You: Shows JavaScript files
- ```
- ## A Simple Example
- Let's find configuration files:
- ```typescript
- // Find all config files
- const configFiles = await findFiles('config.*');
- console.log(configFiles); // ["config.json", "config.dev.yml"]
- ```
- This searches for any file starting with "config." regardless of extension.
- ## Behind the Scenes
- The service works in three simple steps (simplified from our code):
- ```typescript
- async function findFiles(pattern) {
- // 1. Get all files in project
- const allFiles = getAllFiles();
- // 2. Filter by pattern
- return allFiles.filter(file =>
- file.match(new RegExp(pattern))
- );
- }
- ```
- Key parts:
- 1. Gets every file in your project
- 2. Checks which match your search pattern
- 3. Returns the matches
- ## Smart Filtering
- The service automatically respects ignore rules:
- ```typescript
- // In .gitignore
- node_modules/
- temp/
- // These won't appear in search results!
- await findFiles('*'); // Skips node_modules and temp
- ```
- This prevents cluttering results with files you want to ignore.
- ## Common Uses
- You'll often use file discovery to:
- 1. **Find Source Files**: Locate all `.ts` or `.js` files
- 2. **Search Configs**: Look for configuration files
- 3. **Check Documentation**: Find all `.md` files
- ## What's Next?
- Now you understand how the File Discovery Service helps you quickly find files in your projects! In [Chapter 72: Git Integration](72_git_integration_.md), we'll learn how your CLI works with Git repositories.
- > Pro Tip: Try different search patterns like `*.md` or `test/*.js` to see what files you can discover!
- ---
- # Chapter 72: Git Integration
- Welcome back! In [Chapter 71: File Discovery Service](71_file_discovery_service_.md), we learned how to quickly find files in your project. Now, let's meet your CLI's **time machine** - Git Integration that lets you travel back to previous versions of your code, just like rewinding a movie to see an earlier scene!
- ## Why Do We Need Git Integration?
- Imagine you're writing a story and accidentally delete a paragraph. Wouldn't it be great to:
- - Go back to yesterday's version
- - See what changed
- - Restore what you deleted
- Git Integration does exactly this for your code! It:
- 1. Takes snapshots of your project (called "commits")
- 2. Lets you compare different versions
- 3. Helps undo mistakes by restoring old versions
- It's like having an "undo button" for your entire project!
- ## Meet the Three Time Travel Tools
- Git Integration provides three simple ways to work with code history:
- 1. **Snapshots**: Save the current state of your code
- 2. **Comparison**: See what changed between versions
- 3. **Restore**: Go back to an earlier version
- Here's how easy it is to save a snapshot:
- ```typescript
- import { git } from 'gemini-cli';
- // Save current code state
- await git.saveSnapshot("Added login feature");
- console.log("Snapshot saved!");
- ```
- This creates a permanent record you can return to later.
- ## How Git Integration Works
- When you save a snapshot, here's what happens:
- ```mermaid
- sequenceDiagram
- participant You as You
- participant Git as Git Service
- participant Files as Your Files
- You->>Git: "Save snapshot"
- Git->>Files: Records all file states
- Files-->>Git: Returns file data
- Git->>Git: Stores compressed version
- Git->>You: "Snapshot saved!"
- ```
- ## A Simple Example
- Let's see how to restore an old version:
- ```typescript
- // List all snapshots
- const snapshots = await git.listSnapshots();
- console.log(snapshots); // ["Added login", "Fixed bug", ...]
- // Restore the first one
- await git.restoreSnapshot(snapshots[0]);
- console.log("Back to previous version!");
- ```
- This lets you undo changes and return to any saved state.
- ## Behind the Scenes
- The Git service works like this (simplified):
- ```typescript
- class GitService {
- async saveSnapshot(message) {
- // 1. Record all file changes
- const changes = detectFileChanges();
- // 2. Store them permanently
- storeChanges(message, changes);
- }
- }
- ```
- Key steps:
- 1. Checks what files changed
- 2. Saves them with your message
- 3. Compresses to save space
- ## Safety Features
- Git Integration includes important protections:
- - Never deletes your original files
- - Keeps multiple backup versions
- - Lets you preview changes before restoring
- ```typescript
- // See what would change
- const preview = await git.previewRestore(snapshot);
- console.log(preview.changes); // Files that would be modified
- ```
- ## Common Uses
- You'll often use Git Integration to:
- 1. **Recover Mistakes**: Undo bad changes
- 2. **Compare Versions**: See how code evolved
- 3. **Experiment Safely**: Try ideas knowing you can undo
- ## What's Next?
- Now you understand how Git Integration acts as a time machine for your code! In our next chapters, we'll explore more ways to enhance your CLI experience.
- > Pro Tip: Try making small changes and creating snapshots to see how easy it is to travel through your code's history!
- ---
Add Comment
Please, Sign In to add comment