mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
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__
This commit is contained in:
102
packages/cli/src/utils/paths.ts
Normal file
102
packages/cli/src/utils/paths.ts
Normal file
@@ -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 || '.';
|
||||
}
|
||||
Reference in New Issue
Block a user