diff options
| author | Taylor Mullen <[email protected]> | 2025-04-15 21:41:08 -0700 |
|---|---|---|
| committer | Taylor Mullen <[email protected]> | 2025-04-17 13:19:55 -0400 |
| commit | add233c5043264d47ecc6d3339a383f41a241ae8 (patch) | |
| tree | 3d80d412ed805007132cf44257bbd7667005dcd8 /packages/cli/src/utils/paths.ts | |
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__
Diffstat (limited to 'packages/cli/src/utils/paths.ts')
| -rw-r--r-- | packages/cli/src/utils/paths.ts | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/packages/cli/src/utils/paths.ts b/packages/cli/src/utils/paths.ts new file mode 100644 index 00000000..a5368463 --- /dev/null +++ b/packages/cli/src/utils/paths.ts @@ -0,0 +1,102 @@ +import process from 'node:process'; +import path from 'node:path'; // Import the 'path' module + +/** + * Returns the target directory, using the provided argument or the current working directory. + */ +export function getTargetDirectory(targetDirArg: string | undefined): string { + return targetDirArg || process.cwd(); +} + +/** + * Shortens a path string if it exceeds maxLen, prioritizing the start and end segments. + * Example: /path/to/a/very/long/file.txt -> /path/.../long/file.txt + */ +export function shortenPath(filePath: string, maxLen: number = 35): string { + if (filePath.length <= maxLen) { + return filePath; + } + + const parsedPath = path.parse(filePath); + const root = parsedPath.root; + const separator = path.sep; + + // Get segments of the path *after* the root + const relativePath = filePath.substring(root.length); + const segments = relativePath.split(separator).filter(s => s !== ''); // Filter out empty segments + + // Handle cases with no segments after root (e.g., "/", "C:\") or only one segment + if (segments.length <= 1) { + // Fallback to simple start/end truncation for very short paths or single segments + const keepLen = Math.floor((maxLen - 3) / 2); + // Ensure keepLen is not negative if maxLen is very small + if (keepLen <= 0) { + return filePath.substring(0, maxLen - 3) + '...'; + } + const start = filePath.substring(0, keepLen); + const end = filePath.substring(filePath.length - keepLen); + return `${start}...${end}`; + } + + const firstDir = segments[0]; + const startComponent = root + firstDir; + + const endPartSegments: string[] = []; + // Base length: startComponent + separator + "..." + let currentLength = startComponent.length + separator.length + 3; + + // Iterate backwards through segments (excluding the first one) + for (let i = segments.length - 1; i >= 1; i--) { + const segment = segments[i]; + // Length needed if we add this segment: current + separator + segment + const lengthWithSegment = currentLength + separator.length + segment.length; + + if (lengthWithSegment <= maxLen) { + endPartSegments.unshift(segment); // Add to the beginning of the end part + currentLength = lengthWithSegment; + } else { + // Adding this segment would exceed maxLen + break; + } + } + + // Construct the final path + let result = startComponent + separator + '...'; + if (endPartSegments.length > 0) { + result += separator + endPartSegments.join(separator); + } + + // As a final check, if the result is somehow still too long (e.g., startComponent + ... is too long) + // fallback to simple truncation of the original path + if (result.length > maxLen) { + const keepLen = Math.floor((maxLen - 3) / 2); + if (keepLen <= 0) { + return filePath.substring(0, maxLen - 3) + '...'; + } + const start = filePath.substring(0, keepLen); + const end = filePath.substring(filePath.length - keepLen); + return `${start}...${end}`; + } + + + return result; +} + +/** + * Calculates the relative path from a root directory to a target path. + * Ensures both paths are resolved before calculating. + * Returns '.' if the target path is the same as the root directory. + * + * @param targetPath The absolute or relative path to make relative. + * @param rootDirectory The absolute path of the directory to make the target path relative to. + * @returns The relative path from rootDirectory to targetPath. + */ +export function makeRelative(targetPath: string, rootDirectory: string): string { + const resolvedTargetPath = path.resolve(targetPath); + const resolvedRootDirectory = path.resolve(rootDirectory); + + const relativePath = path.relative(resolvedRootDirectory, resolvedTargetPath); + + // If the paths are the same, path.relative returns '', return '.' instead + return relativePath || '.'; +} |
