Gemini CLI 示例

不确定从何入手?以下示例展示了 Gemini CLI 在不同任务中的用法。结果仅用于演示,实际输出可能不同。

根据照片内容重命名

场景:文件夹中有以下图片:

photos/photo1.png
photos/photo2.png
photos/photo3.png

提示:

请根据图片内容重命名我 “photos” 目录中的所有照片。

执行后,CLI 会请求重命名权限。选择 Yes, allow once.,效果如下:

photos/yellow_flowers.png
photos/antique_dresser.png
photos/green_android_robot.png

阅读代码解释仓库

场景:想通过查看源码了解开源工具(而不仅是 README)。

提示:

克隆 https://github.com/chalk/chalk 仓库,阅读其中关键源码,并解释其工作原理。

CLI 会:

  1. 请求权限执行 git clone
  2. 查找关键源码文件并请求读取权限;
  3. 分析后给出总结。

示例输出:

`chalk` 是一个广受欢迎的 npm 包,用于为终端输出着色。源码大体工作方式如下:

- **核心功能:** 主入口提供可链式调用的 API。每个颜色或修饰(如 `bold``italic`)都是一个 getter,会将对应的 ANSI 转义码压入内部栈。

- **链式 API:** 当调用 `chalk.red.bold('Hello')` 时,你实际上依次访问多个 getter;`red` 添加红色转义码,`bold` 添加粗体转义码。

- **输出生成:** 当链式结果转换为字符串(例如在 `console.log` 中打印)时,最终的 `toString()` 会将所有转义码与原始文本合并,并追加重置码,从而生成可在终端渲染的彩色输出。

合并两张表格

场景:有两份 CSV 文件 Revenue - 2023.csvRevenue - 2024.csv,希望合并为按年份分列的单一文件。

提示:

请将这两份 .csv 合并成一份表格,并让不同年份显示在独立列中。

CLI 会读取原文件并请求写入新文件的权限,授权后得到:

Month,2023,2024
January,0,1000
February,0,1200
March,0,2400
April,900,500
May,1000,800
June,1000,900
July,1200,1000
August,1800,400
September,2000,2000
October,2400,3400
November,3400,1800
December,2100,9000

生成单元测试

场景:已编写登录页,希望补充测试保障覆盖率。

提示:

为 Login.js 编写单元测试。

CLI 会请求写入新文件,并生成如下测试样例:

import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import Login from './Login';

// 模拟登录接口调用
jest.mock('./api', () => ({
  login: jest.fn(),
}));

describe('Login component', () => {
  it('renders the login form correctly', () => {
    const { getByLabelText, getByText } = render(<Login />);

    expect(getByLabelText('Username')).toBeInTheDocument();
    expect(getByLabelText('Password')).toBeInTheDocument();
    expect(getByText('Login')).toBeInTheDocument();
  });

  it('shows an error message with invalid credentials', async () => {
    const { getByLabelText, getByText, findByText } = render(<Login />);
    const usernameInput = getByLabelText('Username');
    const passwordInput = getByLabelText('Password');
    const loginButton = getByText('Login');

    // Mock the API to return an error
    require('./api').login.mockRejectedValue(new Error('Invalid credentials'));

    fireEvent.change(usernameInput, { target: { value: 'testuser' } });
    fireEvent.change(passwordInput, { target: { value: 'wrongpassword' } });
    fireEvent.click(loginButton);

    const errorMessage = await findByText('Invalid credentials');
    expect(errorMessage).toBeInTheDocument();
  });

  it('logs in successfully with valid credentials', async () => {
    const onLoginSuccess = jest.fn();
    const { getByLabelText, getByText } = render(
      <Login onLoginSuccess={onLoginSuccess} />,
    );
    const usernameInput = getByLabelText('Username');
    const passwordInput = getByLabelText('Password');
    const loginButton = getByText('Login');

    // Mock the API to return a success message
    require('./api').login.mockResolvedValue({ success: true });

    fireEvent.change(usernameInput, { target: { value: 'testuser' } });
    fireEvent.change(passwordInput, { target: { value: 'correctpassword' } });
    fireEvent.click(loginButton);

    await waitFor(() => {
      expect(onLoginSuccess).toHaveBeenCalled();
    });
  });

  it('disables the submit button while submitting', async () => {
    const { getByLabelText, getByText } = render(<Login />);
    const usernameInput = getByLabelText('Username');
    const passwordInput = getByLabelText('Password');
    const loginButton = getByText('Login');

    // Mock the API to have a delay
    require('./api').login.mockImplementation(
      () =>
        new Promise((resolve) =>
          setTimeout(() => resolve({ success: true }), 1000),
        ),
    );

    fireEvent.change(usernameInput, { target: { value: 'testuser' } });
    fireEvent.change(passwordInput, { target: { value: 'correctpassword' } });
    fireEvent.click(loginButton);

    expect(loginButton).toBeDisabled();

    await waitFor(() => {
      expect(loginButton).not.toBeDisabled();
    });
  });
});