2025-04-18 17:44:24 -07:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright 2025 Google LLC
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*/
|
|
|
|
|
|
2025-08-11 16:12:41 -07:00
|
|
|
import { FunctionDeclaration } from '@google/genai';
|
2025-08-06 10:50:02 -07:00
|
|
|
import { AnyDeclarativeTool, Icon, ToolResult, BaseTool } from './tools.js';
|
2025-05-03 19:57:28 -07:00
|
|
|
import { Config } from '../config/config.js';
|
2025-07-06 05:58:51 +08:00
|
|
|
import { spawn } from 'node:child_process';
|
|
|
|
|
import { StringDecoder } from 'node:string_decoder';
|
2025-05-28 00:43:23 -07:00
|
|
|
import { discoverMcpTools } from './mcp-client.js';
|
|
|
|
|
import { DiscoveredMCPTool } from './mcp-tool.js';
|
2025-07-06 05:58:51 +08:00
|
|
|
import { parse } from 'shell-quote';
|
2025-05-03 19:57:28 -07:00
|
|
|
|
2025-05-28 00:43:23 -07:00
|
|
|
type ToolParams = Record<string, unknown>;
|
2025-05-17 16:53:22 -07:00
|
|
|
|
2025-05-03 19:57:28 -07:00
|
|
|
export class DiscoveredTool extends BaseTool<ToolParams, ToolResult> {
|
|
|
|
|
constructor(
|
|
|
|
|
private readonly config: Config,
|
2025-07-18 14:29:09 -07:00
|
|
|
name: string,
|
2025-05-03 19:57:28 -07:00
|
|
|
readonly description: string,
|
|
|
|
|
readonly parameterSchema: Record<string, unknown>,
|
|
|
|
|
) {
|
|
|
|
|
const discoveryCmd = config.getToolDiscoveryCommand()!;
|
|
|
|
|
const callCommand = config.getToolCallCommand()!;
|
|
|
|
|
description += `
|
2025-05-04 16:26:20 -07:00
|
|
|
|
2025-05-03 19:57:28 -07:00
|
|
|
This tool was discovered from the project by executing the command \`${discoveryCmd}\` on project root.
|
|
|
|
|
When called, this tool will execute the command \`${callCommand} ${name}\` on project root.
|
2025-05-16 16:29:03 -07:00
|
|
|
Tool discovery and call commands can be configured in project or user settings.
|
2025-05-03 19:57:28 -07:00
|
|
|
|
|
|
|
|
When called, the tool call command is executed as a subprocess.
|
|
|
|
|
On success, tool output is returned as a json string.
|
|
|
|
|
Otherwise, the following information is returned:
|
|
|
|
|
|
|
|
|
|
Stdout: Output on stdout stream. Can be \`(empty)\` or partial.
|
|
|
|
|
Stderr: Output on stderr stream. Can be \`(empty)\` or partial.
|
|
|
|
|
Error: Error or \`(none)\` if no error was reported for the subprocess.
|
|
|
|
|
Exit Code: Exit code or \`(none)\` if terminated by signal.
|
|
|
|
|
Signal: Signal number or \`(none)\` if no signal was received.
|
|
|
|
|
`;
|
2025-05-30 14:12:51 -07:00
|
|
|
super(
|
|
|
|
|
name,
|
|
|
|
|
name,
|
|
|
|
|
description,
|
2025-07-17 16:25:23 -06:00
|
|
|
Icon.Hammer,
|
2025-05-30 14:12:51 -07:00
|
|
|
parameterSchema,
|
|
|
|
|
false, // isOutputMarkdown
|
|
|
|
|
false, // canUpdateOutput
|
|
|
|
|
);
|
2025-05-03 19:57:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async execute(params: ToolParams): Promise<ToolResult> {
|
|
|
|
|
const callCommand = this.config.getToolCallCommand()!;
|
|
|
|
|
const child = spawn(callCommand, [this.name]);
|
|
|
|
|
child.stdin.write(JSON.stringify(params));
|
|
|
|
|
child.stdin.end();
|
2025-06-05 06:40:33 -07:00
|
|
|
|
2025-05-03 19:57:28 -07:00
|
|
|
let stdout = '';
|
|
|
|
|
let stderr = '';
|
|
|
|
|
let error: Error | null = null;
|
|
|
|
|
let code: number | null = null;
|
|
|
|
|
let signal: NodeJS.Signals | null = null;
|
2025-06-05 06:40:33 -07:00
|
|
|
|
|
|
|
|
await new Promise<void>((resolve) => {
|
|
|
|
|
const onStdout = (data: Buffer) => {
|
|
|
|
|
stdout += data?.toString();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onStderr = (data: Buffer) => {
|
|
|
|
|
stderr += data?.toString();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onError = (err: Error) => {
|
|
|
|
|
error = err;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onClose = (
|
|
|
|
|
_code: number | null,
|
|
|
|
|
_signal: NodeJS.Signals | null,
|
|
|
|
|
) => {
|
2025-05-03 19:57:28 -07:00
|
|
|
code = _code;
|
|
|
|
|
signal = _signal;
|
2025-06-05 06:40:33 -07:00
|
|
|
cleanup();
|
|
|
|
|
resolve();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const cleanup = () => {
|
|
|
|
|
child.stdout.removeListener('data', onStdout);
|
|
|
|
|
child.stderr.removeListener('data', onStderr);
|
|
|
|
|
child.removeListener('error', onError);
|
|
|
|
|
child.removeListener('close', onClose);
|
|
|
|
|
if (child.connected) {
|
|
|
|
|
child.disconnect();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
child.stdout.on('data', onStdout);
|
|
|
|
|
child.stderr.on('data', onStderr);
|
|
|
|
|
child.on('error', onError);
|
|
|
|
|
child.on('close', onClose);
|
|
|
|
|
});
|
2025-05-03 19:57:28 -07:00
|
|
|
|
|
|
|
|
// if there is any error, non-zero exit code, signal, or stderr, return error details instead of stdout
|
|
|
|
|
if (error || code !== 0 || signal || stderr) {
|
|
|
|
|
const llmContent = [
|
|
|
|
|
`Stdout: ${stdout || '(empty)'}`,
|
|
|
|
|
`Stderr: ${stderr || '(empty)'}`,
|
|
|
|
|
`Error: ${error ?? '(none)'}`,
|
|
|
|
|
`Exit Code: ${code ?? '(none)'}`,
|
|
|
|
|
`Signal: ${signal ?? '(none)'}`,
|
|
|
|
|
].join('\n');
|
|
|
|
|
return {
|
|
|
|
|
llmContent,
|
|
|
|
|
returnDisplay: llmContent,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
llmContent: stdout,
|
|
|
|
|
returnDisplay: stdout,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
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__
2025-04-15 21:41:08 -07:00
|
|
|
|
2025-04-21 12:59:31 -07:00
|
|
|
export class ToolRegistry {
|
2025-08-06 10:50:02 -07:00
|
|
|
private tools: Map<string, AnyDeclarativeTool> = new Map();
|
2025-05-20 11:36:21 -07:00
|
|
|
private config: Config;
|
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__
2025-04-15 21:41:08 -07:00
|
|
|
|
2025-05-20 11:36:21 -07:00
|
|
|
constructor(config: Config) {
|
|
|
|
|
this.config = config;
|
|
|
|
|
}
|
2025-05-03 19:57:28 -07:00
|
|
|
|
2025-04-17 18:06:21 -04:00
|
|
|
/**
|
|
|
|
|
* Registers a tool definition.
|
|
|
|
|
* @param tool - The tool object containing schema and execution logic.
|
|
|
|
|
*/
|
2025-08-06 10:50:02 -07:00
|
|
|
registerTool(tool: AnyDeclarativeTool): void {
|
2025-04-17 18:06:21 -04:00
|
|
|
if (this.tools.has(tool.name)) {
|
2025-07-18 14:29:09 -07:00
|
|
|
if (tool instanceof DiscoveredMCPTool) {
|
|
|
|
|
tool = tool.asFullyQualifiedTool();
|
|
|
|
|
} else {
|
|
|
|
|
// Decide on behavior: throw error, log warning, or allow overwrite
|
|
|
|
|
console.warn(
|
|
|
|
|
`Tool with name "${tool.name}" is already registered. Overwriting.`,
|
|
|
|
|
);
|
|
|
|
|
}
|
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__
2025-04-15 21:41:08 -07:00
|
|
|
}
|
2025-04-17 18:06:21 -04:00
|
|
|
this.tools.set(tool.name, tool);
|
|
|
|
|
}
|
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__
2025-04-15 21:41:08 -07:00
|
|
|
|
2025-08-05 23:59:31 +02:00
|
|
|
private removeDiscoveredTools(): void {
|
|
|
|
|
for (const tool of this.tools.values()) {
|
|
|
|
|
if (tool instanceof DiscoveredTool || tool instanceof DiscoveredMCPTool) {
|
|
|
|
|
this.tools.delete(tool.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-03 19:57:28 -07:00
|
|
|
/**
|
2025-06-02 09:56:32 -07:00
|
|
|
* Discovers tools from project (if available and configured).
|
2025-05-03 19:57:28 -07:00
|
|
|
* Can be called multiple times to update discovered tools.
|
2025-07-25 03:14:45 +02:00
|
|
|
* This will discover tools from the command line and from MCP servers.
|
2025-05-03 19:57:28 -07:00
|
|
|
*/
|
2025-07-25 03:14:45 +02:00
|
|
|
async discoverAllTools(): Promise<void> {
|
2025-05-03 19:57:28 -07:00
|
|
|
// remove any previously discovered tools
|
2025-08-05 23:59:31 +02:00
|
|
|
this.removeDiscoveredTools();
|
|
|
|
|
|
|
|
|
|
this.config.getPromptRegistry().clear();
|
2025-07-06 05:58:51 +08:00
|
|
|
|
|
|
|
|
await this.discoverAndRegisterToolsFromCommand();
|
|
|
|
|
|
|
|
|
|
// discover tools using MCP servers, if configured
|
|
|
|
|
await discoverMcpTools(
|
|
|
|
|
this.config.getMcpServers() ?? {},
|
|
|
|
|
this.config.getMcpServerCommand(),
|
|
|
|
|
this,
|
2025-07-25 20:56:33 +00:00
|
|
|
this.config.getPromptRegistry(),
|
2025-07-14 06:42:22 +02:00
|
|
|
this.config.getDebugMode(),
|
2025-08-08 16:29:06 -07:00
|
|
|
this.config.getWorkspaceContext(),
|
2025-07-06 05:58:51 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-25 03:14:45 +02:00
|
|
|
/**
|
|
|
|
|
* Discovers tools from project (if available and configured).
|
|
|
|
|
* Can be called multiple times to update discovered tools.
|
|
|
|
|
* This will NOT discover tools from the command line, only from MCP servers.
|
|
|
|
|
*/
|
|
|
|
|
async discoverMcpTools(): Promise<void> {
|
|
|
|
|
// remove any previously discovered tools
|
2025-08-05 23:59:31 +02:00
|
|
|
this.removeDiscoveredTools();
|
|
|
|
|
|
|
|
|
|
this.config.getPromptRegistry().clear();
|
2025-07-25 03:14:45 +02:00
|
|
|
|
|
|
|
|
// discover tools using MCP servers, if configured
|
|
|
|
|
await discoverMcpTools(
|
|
|
|
|
this.config.getMcpServers() ?? {},
|
|
|
|
|
this.config.getMcpServerCommand(),
|
|
|
|
|
this,
|
2025-07-25 20:56:33 +00:00
|
|
|
this.config.getPromptRegistry(),
|
2025-07-25 03:14:45 +02:00
|
|
|
this.config.getDebugMode(),
|
2025-08-08 16:29:06 -07:00
|
|
|
this.config.getWorkspaceContext(),
|
2025-07-25 03:14:45 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-22 09:34:56 -04:00
|
|
|
/**
|
|
|
|
|
* Discover or re-discover tools for a single MCP server.
|
|
|
|
|
* @param serverName - The name of the server to discover tools from.
|
|
|
|
|
*/
|
|
|
|
|
async discoverToolsForServer(serverName: string): Promise<void> {
|
|
|
|
|
// Remove any previously discovered tools from this server
|
|
|
|
|
for (const [name, tool] of this.tools.entries()) {
|
|
|
|
|
if (tool instanceof DiscoveredMCPTool && tool.serverName === serverName) {
|
|
|
|
|
this.tools.delete(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-05 23:59:31 +02:00
|
|
|
this.config.getPromptRegistry().removePromptsByServer(serverName);
|
|
|
|
|
|
2025-07-22 09:34:56 -04:00
|
|
|
const mcpServers = this.config.getMcpServers() ?? {};
|
|
|
|
|
const serverConfig = mcpServers[serverName];
|
|
|
|
|
if (serverConfig) {
|
|
|
|
|
await discoverMcpTools(
|
|
|
|
|
{ [serverName]: serverConfig },
|
|
|
|
|
undefined,
|
|
|
|
|
this,
|
2025-07-25 20:56:33 +00:00
|
|
|
this.config.getPromptRegistry(),
|
2025-07-22 09:34:56 -04:00
|
|
|
this.config.getDebugMode(),
|
2025-08-08 16:29:06 -07:00
|
|
|
this.config.getWorkspaceContext(),
|
2025-07-22 09:34:56 -04:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-06 05:58:51 +08:00
|
|
|
private async discoverAndRegisterToolsFromCommand(): Promise<void> {
|
2025-05-04 12:11:19 -07:00
|
|
|
const discoveryCmd = this.config.getToolDiscoveryCommand();
|
2025-07-06 05:58:51 +08:00
|
|
|
if (!discoveryCmd) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const cmdParts = parse(discoveryCmd);
|
|
|
|
|
if (cmdParts.length === 0) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Tool discovery command is empty or contains only whitespace.',
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const proc = spawn(cmdParts[0] as string, cmdParts.slice(1) as string[]);
|
|
|
|
|
let stdout = '';
|
|
|
|
|
const stdoutDecoder = new StringDecoder('utf8');
|
|
|
|
|
let stderr = '';
|
|
|
|
|
const stderrDecoder = new StringDecoder('utf8');
|
|
|
|
|
let sizeLimitExceeded = false;
|
|
|
|
|
const MAX_STDOUT_SIZE = 10 * 1024 * 1024; // 10MB limit
|
|
|
|
|
const MAX_STDERR_SIZE = 10 * 1024 * 1024; // 10MB limit
|
|
|
|
|
|
|
|
|
|
let stdoutByteLength = 0;
|
|
|
|
|
let stderrByteLength = 0;
|
|
|
|
|
|
|
|
|
|
proc.stdout.on('data', (data) => {
|
|
|
|
|
if (sizeLimitExceeded) return;
|
|
|
|
|
if (stdoutByteLength + data.length > MAX_STDOUT_SIZE) {
|
|
|
|
|
sizeLimitExceeded = true;
|
|
|
|
|
proc.kill();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
stdoutByteLength += data.length;
|
|
|
|
|
stdout += stdoutDecoder.write(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
proc.stderr.on('data', (data) => {
|
|
|
|
|
if (sizeLimitExceeded) return;
|
|
|
|
|
if (stderrByteLength + data.length > MAX_STDERR_SIZE) {
|
|
|
|
|
sizeLimitExceeded = true;
|
|
|
|
|
proc.kill();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
stderrByteLength += data.length;
|
|
|
|
|
stderr += stderrDecoder.write(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
|
|
|
proc.on('error', reject);
|
|
|
|
|
proc.on('close', (code) => {
|
|
|
|
|
stdout += stdoutDecoder.end();
|
|
|
|
|
stderr += stderrDecoder.end();
|
|
|
|
|
|
|
|
|
|
if (sizeLimitExceeded) {
|
|
|
|
|
return reject(
|
|
|
|
|
new Error(
|
|
|
|
|
`Tool discovery command output exceeded size limit of ${MAX_STDOUT_SIZE} bytes.`,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (code !== 0) {
|
|
|
|
|
console.error(`Command failed with code ${code}`);
|
|
|
|
|
console.error(stderr);
|
|
|
|
|
return reject(
|
|
|
|
|
new Error(`Tool discovery command failed with exit code ${code}`),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
resolve();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-06-02 13:41:49 -07:00
|
|
|
// execute discovery command and extract function declarations (w/ or w/o "tool" wrappers)
|
2025-05-04 12:11:19 -07:00
|
|
|
const functions: FunctionDeclaration[] = [];
|
2025-07-06 05:58:51 +08:00
|
|
|
const discoveredItems = JSON.parse(stdout.trim());
|
|
|
|
|
|
|
|
|
|
if (!discoveredItems || !Array.isArray(discoveredItems)) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Tool discovery command did not return a JSON array of tools.',
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const tool of discoveredItems) {
|
|
|
|
|
if (tool && typeof tool === 'object') {
|
|
|
|
|
if (Array.isArray(tool['function_declarations'])) {
|
|
|
|
|
functions.push(...tool['function_declarations']);
|
|
|
|
|
} else if (Array.isArray(tool['functionDeclarations'])) {
|
|
|
|
|
functions.push(...tool['functionDeclarations']);
|
|
|
|
|
} else if (tool['name']) {
|
|
|
|
|
functions.push(tool as FunctionDeclaration);
|
|
|
|
|
}
|
2025-06-02 13:41:49 -07:00
|
|
|
}
|
2025-05-04 12:11:19 -07:00
|
|
|
}
|
|
|
|
|
// register each function as a tool
|
|
|
|
|
for (const func of functions) {
|
2025-07-06 05:58:51 +08:00
|
|
|
if (!func.name) {
|
|
|
|
|
console.warn('Discovered a tool with no name. Skipping.');
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const parameters =
|
2025-08-11 16:12:41 -07:00
|
|
|
func.parametersJsonSchema &&
|
|
|
|
|
typeof func.parametersJsonSchema === 'object' &&
|
|
|
|
|
!Array.isArray(func.parametersJsonSchema)
|
|
|
|
|
? func.parametersJsonSchema
|
2025-07-06 05:58:51 +08:00
|
|
|
: {};
|
2025-05-04 12:11:19 -07:00
|
|
|
this.registerTool(
|
|
|
|
|
new DiscoveredTool(
|
|
|
|
|
this.config,
|
2025-07-06 05:58:51 +08:00
|
|
|
func.name,
|
|
|
|
|
func.description ?? '',
|
|
|
|
|
parameters as Record<string, unknown>,
|
2025-05-04 12:11:19 -07:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-07-06 05:58:51 +08:00
|
|
|
} catch (e) {
|
|
|
|
|
console.error(`Tool discovery command "${discoveryCmd}" failed:`, e);
|
|
|
|
|
throw e;
|
2025-05-03 19:57:28 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 18:06:21 -04:00
|
|
|
/**
|
2025-04-19 19:45:42 +01:00
|
|
|
* Retrieves the list of tool schemas (FunctionDeclaration array).
|
|
|
|
|
* Extracts the declarations from the ToolListUnion structure.
|
2025-05-03 19:57:28 -07:00
|
|
|
* Includes discovered (vs registered) tools if configured.
|
2025-04-19 19:45:42 +01:00
|
|
|
* @returns An array of FunctionDeclarations.
|
2025-04-17 18:06:21 -04:00
|
|
|
*/
|
2025-04-19 19:45:42 +01:00
|
|
|
getFunctionDeclarations(): FunctionDeclaration[] {
|
2025-04-17 18:06:21 -04:00
|
|
|
const declarations: FunctionDeclaration[] = [];
|
|
|
|
|
this.tools.forEach((tool) => {
|
|
|
|
|
declarations.push(tool.schema);
|
|
|
|
|
});
|
2025-04-19 19:45:42 +01:00
|
|
|
return declarations;
|
|
|
|
|
}
|
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__
2025-04-15 21:41:08 -07:00
|
|
|
|
2025-08-06 20:34:38 -04:00
|
|
|
/**
|
|
|
|
|
* Retrieves a filtered list of tool schemas based on a list of tool names.
|
|
|
|
|
* @param toolNames - An array of tool names to include.
|
|
|
|
|
* @returns An array of FunctionDeclarations for the specified tools.
|
|
|
|
|
*/
|
|
|
|
|
getFunctionDeclarationsFiltered(toolNames: string[]): FunctionDeclaration[] {
|
|
|
|
|
const declarations: FunctionDeclaration[] = [];
|
|
|
|
|
for (const name of toolNames) {
|
|
|
|
|
const tool = this.tools.get(name);
|
|
|
|
|
if (tool) {
|
|
|
|
|
declarations.push(tool.schema);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return declarations;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-19 19:45:42 +01:00
|
|
|
/**
|
2025-05-03 19:57:28 -07:00
|
|
|
* Returns an array of all registered and discovered tool instances.
|
2025-04-19 19:45:42 +01:00
|
|
|
*/
|
2025-08-06 10:50:02 -07:00
|
|
|
getAllTools(): AnyDeclarativeTool[] {
|
2025-07-15 14:35:35 -04:00
|
|
|
return Array.from(this.tools.values()).sort((a, b) =>
|
|
|
|
|
a.displayName.localeCompare(b.displayName),
|
|
|
|
|
);
|
2025-04-19 19:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
2025-06-02 13:39:25 -07:00
|
|
|
/**
|
|
|
|
|
* Returns an array of tools registered from a specific MCP server.
|
|
|
|
|
*/
|
2025-08-06 10:50:02 -07:00
|
|
|
getToolsByServer(serverName: string): AnyDeclarativeTool[] {
|
|
|
|
|
const serverTools: AnyDeclarativeTool[] = [];
|
2025-06-02 13:39:25 -07:00
|
|
|
for (const tool of this.tools.values()) {
|
|
|
|
|
if ((tool as DiscoveredMCPTool)?.serverName === serverName) {
|
|
|
|
|
serverTools.push(tool);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-15 14:35:35 -04:00
|
|
|
return serverTools.sort((a, b) => a.name.localeCompare(b.name));
|
2025-06-02 13:39:25 -07:00
|
|
|
}
|
|
|
|
|
|
2025-04-17 18:06:21 -04:00
|
|
|
/**
|
|
|
|
|
* Get the definition of a specific tool.
|
|
|
|
|
*/
|
2025-08-06 10:50:02 -07:00
|
|
|
getTool(name: string): AnyDeclarativeTool | undefined {
|
2025-04-17 18:06:21 -04:00
|
|
|
return this.tools.get(name);
|
|
|
|
|
}
|
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__
2025-04-15 21:41:08 -07:00
|
|
|
}
|