From add233c5043264d47ecc6d3339a383f41a241ae8 Mon Sep 17 00:00:00 2001
From: Taylor Mullen <ntaylormullen@google.com>
Date: Tue, 15 Apr 2025 21:41:08 -0700
Subject: Initial commit of Gemini Code CLI

This commit introduces the initial codebase for the Gemini Code CLI, a command-line interface designed to facilitate interaction with the Gemini API for software engineering tasks.

The code was migrated from a previous git repository as a single squashed commit.

Core Features & Components:

*   **Gemini Integration:** Leverages the `@google/genai` SDK to interact with the Gemini models, supporting chat history, streaming responses, and function calling (tools).
*   **Terminal UI:** Built with Ink (React for CLIs) providing an interactive chat interface within the terminal, including input prompts, message display, loading indicators, and tool interaction elements.
*   **Tooling Framework:** Implements a robust tool system allowing Gemini to interact with the local environment. Includes tools for:
    *   File system listing (`ls`)
    *   File reading (`read-file`)
    *   Content searching (`grep`)
    *   File globbing (`glob`)
    *   File editing (`edit`)
    *   File writing (`write-file`)
    *   Executing bash commands (`terminal`)
*   **State Management:** Handles the streaming state of Gemini responses and manages the conversation history.
*   **Configuration:** Parses command-line arguments (`yargs`) and loads environment variables (`dotenv`) for setup.
*   **Project Structure:** Organized into `core`, `ui`, `tools`, `config`, and `utils` directories using TypeScript. Includes basic build (`tsc`) and start scripts.

This initial version establishes the foundation for a powerful CLI tool enabling developers to use Gemini for coding assistance directly in their terminal environment.

---
Created by yours truly: __Gemini Code__
---
 .../messages/ToolConfirmationMessage.tsx           | 101 +++++++++++++++++++++
 1 file changed, 101 insertions(+)
 create mode 100644 packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx

(limited to 'packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx')

diff --git a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
new file mode 100644
index 00000000..a37d2f94
--- /dev/null
+++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
@@ -0,0 +1,101 @@
+import React from 'react';
+import { Box, Text, useInput } from 'ink';
+import SelectInput from 'ink-select-input';
+import { ToolCallConfirmationDetails, ToolEditConfirmationDetails, ToolConfirmationOutcome, ToolExecuteConfirmationDetails } from '../../types.js'; // Adjust path as needed
+import { PartListUnion } from '@google/genai';
+import DiffRenderer from './DiffRenderer.js';
+import { UI_WIDTH } from '../../constants.js';
+
+export interface ToolConfirmationMessageProps {
+  confirmationDetails: ToolCallConfirmationDetails;
+  onSubmit: (value: PartListUnion) => void;
+}
+
+function isEditDetails(props: ToolCallConfirmationDetails): props is ToolEditConfirmationDetails {
+  return (props as ToolEditConfirmationDetails).fileName !== undefined;
+}
+
+interface InternalOption {
+  label: string;
+  value: ToolConfirmationOutcome;
+}
+
+const ToolConfirmationMessage: React.FC<ToolConfirmationMessageProps> = ({ confirmationDetails }) => {
+  const { onConfirm } = confirmationDetails;
+
+  useInput((_, key) => {
+    if (key.escape) {
+      onConfirm(ToolConfirmationOutcome.Cancel);
+    }
+  });
+
+  const handleSelect = (item: InternalOption) => {
+    onConfirm(item.value);
+  };
+
+  let title: string;
+  let bodyContent: React.ReactNode | null = null; // Removed contextDisplay here
+  let question: string;
+  const options: InternalOption[] = [];
+
+  if (isEditDetails(confirmationDetails)) {
+    title = "Edit"; // Title for the outer box
+
+    // Body content is now the DiffRenderer, passing filename to it
+    // The bordered box is removed from here and handled within DiffRenderer
+    bodyContent = (
+        <DiffRenderer diffContent={confirmationDetails.fileDiff} />
+    );
+
+    question = `Apply this change?`;
+    options.push(
+      { label: '1. Yes, apply change', value: ToolConfirmationOutcome.ProceedOnce },
+      { label: "2. Yes, always apply file edits", value: ToolConfirmationOutcome.ProceedAlways },
+      { label: '3. No (esc)', value: ToolConfirmationOutcome.Cancel }
+    );
+
+  } else {
+    const executionProps = confirmationDetails as ToolExecuteConfirmationDetails;
+    title = "Execute Command"; // Title for the outer box
+
+    // For execution, we still need context display and description
+    const commandDisplay = <Text color="cyan">{executionProps.command}</Text>;
+
+    // Combine command and description into bodyContent for layout consistency
+    bodyContent = (
+        <Box flexDirection="column">
+            <Box paddingX={1} marginLeft={1}>{commandDisplay}</Box>
+        </Box>
+    );
+
+    question = `Allow execution?`;
+    const alwaysLabel = `2. Yes, always allow '${executionProps.rootCommand}' commands`;
+    options.push(
+      { label: '1. Yes, allow once', value: ToolConfirmationOutcome.ProceedOnce },
+      { label: alwaysLabel, value: ToolConfirmationOutcome.ProceedAlways },
+      { label: '3. No (esc)', value: ToolConfirmationOutcome.Cancel }
+    );
+  }
+
+  return (
+    <Box flexDirection="column" padding={1} minWidth={UI_WIDTH}>
+      {/* Body Content (Diff Renderer or Command Info) */}
+      {/* No separate context display here anymore for edits */}
+      <Box flexGrow={1} flexShrink={1} overflow="hidden" marginBottom={1}>
+           {bodyContent}
+      </Box>
+
+      {/* Confirmation Question */}
+      <Box marginBottom={1} flexShrink={0}>
+        <Text>{question}</Text>
+      </Box>
+
+      {/* Select Input for Options */}
+      <Box flexShrink={0}>
+        <SelectInput items={options} onSelect={handleSelect} />
+      </Box>
+    </Box>
+  );
+};
+
+export default ToolConfirmationMessage;
\ No newline at end of file
-- 
cgit v1.2.3

