Documentation
¶
Overview ¶
Package geminicli implements the Agent interface for Gemini CLI.
Index ¶
- Constants
- Variables
- func ExtractAllUserPrompts(data []byte) ([]string, error)
- func ExtractAllUserPromptsFromTranscript(transcript *GeminiTranscript) []string
- func ExtractModifiedFiles(data []byte) ([]string, error)
- func ExtractModifiedFilesFromTranscript(transcript *GeminiTranscript) []string
- func GetLastMessageID(data []byte) (string, error)
- func GetLastMessageIDFromFile(path string) (string, error)
- func GetLastMessageIDFromTranscript(transcript *GeminiTranscript) string
- func GetProjectHash(projectRoot string) string
- func NewGeminiCLIAgent() agent.Agent
- func NewReviewer() *reviewtypes.ReviewerTemplate
- func NormalizeTranscript(data []byte) ([]byte, error)
- func SliceFromMessage(data []byte, startMessageIndex int) ([]byte, error)
- type GeminiCLIAgent
- func (g *GeminiCLIAgent) AreHooksInstalled(ctx context.Context) bool
- func (g *GeminiCLIAgent) CalculateTokenUsage(transcriptData []byte, fromOffset int) (*agent.TokenUsage, error)
- func (g *GeminiCLIAgent) ChunkTranscript(ctx context.Context, content []byte, maxSize int) ([][]byte, error)
- func (g *GeminiCLIAgent) Description() string
- func (g *GeminiCLIAgent) DetectPresence(ctx context.Context) (bool, error)
- func (g *GeminiCLIAgent) DiscoverReviewSkills(_ context.Context) ([]agent.DiscoveredSkill, error)
- func (g *GeminiCLIAgent) ExtractModifiedFilesFromOffset(path string, startOffset int) (files []string, currentPosition int, err error)
- func (g *GeminiCLIAgent) FormatResumeCommand(sessionID string) string
- func (g *GeminiCLIAgent) GenerateText(ctx context.Context, prompt string, model string) (string, error)
- func (g *GeminiCLIAgent) GetSessionBaseDir() (string, error)
- func (g *GeminiCLIAgent) GetSessionDir(repoPath string) (string, error)
- func (g *GeminiCLIAgent) GetSessionID(input *agent.HookInput) string
- func (g *GeminiCLIAgent) GetTranscriptPosition(path string) (int, error)
- func (g *GeminiCLIAgent) HookNames() []string
- func (g *GeminiCLIAgent) InstallHooks(ctx context.Context, localDev bool, force bool) (int, error)
- func (g *GeminiCLIAgent) IsPreview() bool
- func (g *GeminiCLIAgent) LaunchCmd(ctx context.Context, initialPrompt string) (*exec.Cmd, error)
- func (g *GeminiCLIAgent) Name() types.AgentName
- func (g *GeminiCLIAgent) ParseHookEvent(_ context.Context, hookName string, stdin io.Reader) (*agent.Event, error)
- func (g *GeminiCLIAgent) ProtectedDirs() []string
- func (g *GeminiCLIAgent) ReadSession(input *agent.HookInput) (*agent.AgentSession, error)
- func (g *GeminiCLIAgent) ReadTranscript(sessionRef string) ([]byte, error)
- func (g *GeminiCLIAgent) ReassembleTranscript(chunks [][]byte) ([]byte, error)
- func (g *GeminiCLIAgent) ResolveSessionFile(sessionDir, agentSessionID string) string
- func (g *GeminiCLIAgent) Type() types.AgentType
- func (g *GeminiCLIAgent) UninstallHooks(ctx context.Context) error
- func (g *GeminiCLIAgent) WriteHookResponse(message string) error
- func (g *GeminiCLIAgent) WriteSession(_ context.Context, session *agent.AgentSession) error
- type GeminiHookEntry
- type GeminiHookMatcher
- type GeminiHooks
- type GeminiHooksConfig
- type GeminiMessage
- type GeminiSettings
- type GeminiToolCall
- type GeminiTranscript
Constants ¶
const ( HookNameSessionStart = "session-start" HookNameSessionEnd = "session-end" HookNameBeforeAgent = "before-agent" HookNameAfterAgent = "after-agent" HookNameBeforeModel = "before-model" HookNameAfterModel = "after-model" HookNameBeforeToolSelection = "before-tool-selection" HookNameBeforeTool = "before-tool" HookNameAfterTool = "after-tool" HookNamePreCompress = "pre-compress" HookNameNotification = "notification" )
Gemini CLI hook names - these become subcommands under `entire hooks gemini`
const ( MessageTypeUser = "user" MessageTypeGemini = "gemini" )
Message type constants for Gemini transcripts
const ( ToolWriteFile = "write_file" ToolEditFile = "edit_file" ToolSaveFile = "save_file" ToolReplace = "replace" )
Tool names used in Gemini CLI that modify files Note: Gemini CLI uses different names in different contexts: - Internal/transcript names: write_file, replace - Display names: WriteFile, Edit
const GeminiSettingsFileName = "settings.json"
GeminiSettingsFileName is the settings file used by Gemini CLI.
Variables ¶
var FileModificationTools = []string{ ToolWriteFile, ToolEditFile, ToolSaveFile, ToolReplace, }
FileModificationTools lists tools that create or modify files in Gemini CLI
Functions ¶
func ExtractAllUserPrompts ¶
ExtractAllUserPrompts extracts all user messages from transcript data
func ExtractAllUserPromptsFromTranscript ¶
func ExtractAllUserPromptsFromTranscript(transcript *GeminiTranscript) []string
ExtractAllUserPromptsFromTranscript extracts all user prompts from a parsed transcript
func ExtractModifiedFiles ¶
ExtractModifiedFiles extracts files modified by tool calls from transcript data
func ExtractModifiedFilesFromTranscript ¶
func ExtractModifiedFilesFromTranscript(transcript *GeminiTranscript) []string
ExtractModifiedFilesFromTranscript extracts files from a parsed transcript
func GetLastMessageID ¶
GetLastMessageID returns the ID of the last message in the transcript. Returns empty string if the transcript is empty or the last message has no ID.
func GetLastMessageIDFromFile ¶
GetLastMessageIDFromFile reads a transcript file and returns the last message's ID. Returns empty string if the file doesn't exist, is empty, or has no messages with IDs.
func GetLastMessageIDFromTranscript ¶
func GetLastMessageIDFromTranscript(transcript *GeminiTranscript) string
GetLastMessageIDFromTranscript returns the ID of the last message in a parsed transcript. Returns empty string if the transcript is empty or the last message has no ID.
func GetProjectHash ¶ added in v0.4.6
GetProjectHash generates a unique hash for a project based on its root path. This matches Gemini CLI's getProjectHash() which uses SHA256 of the project root.
func NewGeminiCLIAgent ¶
func NewReviewer ¶ added in v0.6.1
func NewReviewer() *reviewtypes.ReviewerTemplate
NewReviewer returns the AgentReviewer for gemini.
Argv shape: gemini -p " " (space placeholder to trigger headless mode). Prompt is piped via stdin; per gemini --help the -p flag appends to stdin content, so passing a single space lets stdin carry the actual prompt. Stdout in this mode is the assistant text directly — parsed line-by-line.
func NormalizeTranscript ¶ added in v0.5.3
NormalizeTranscript normalizes user message content fields in-place from [{"text":"..."}] arrays to plain strings, preserving all other transcript fields (timestamps, thoughts, tokens, model, toolCalls, etc.).
This operates on raw JSON rather than using ParseTranscript + re-marshal because GeminiMessage only captures a subset of fields (id, type, content, toolCalls). Round-tripping through the struct would silently drop fields like timestamp, model, and tokens that are present in real Gemini transcripts. The raw approach rewrites only the content values while leaving all other fields untouched.
func SliceFromMessage ¶ added in v0.4.4
SliceFromMessage returns a Gemini transcript scoped to messages starting from startMessageIndex. This is the Gemini equivalent of transcript.SliceFromLine — for Gemini's single JSON blob, scoping is done by message index rather than line offset. Returns the original data if startMessageIndex <= 0. Returns nil, nil if startMessageIndex exceeds the number of messages.
Types ¶
type GeminiCLIAgent ¶
type GeminiCLIAgent struct {
CommandRunner agent.TextCommandRunner
}
GeminiCLIAgent implements the Agent interface for Gemini CLI.
func (*GeminiCLIAgent) AreHooksInstalled ¶
func (g *GeminiCLIAgent) AreHooksInstalled(ctx context.Context) bool
AreHooksInstalled checks if Entire hooks are installed.
func (*GeminiCLIAgent) CalculateTokenUsage ¶ added in v0.4.6
func (g *GeminiCLIAgent) CalculateTokenUsage(transcriptData []byte, fromOffset int) (*agent.TokenUsage, error)
CalculateTokenUsage computes token usage from the transcript starting at the given message offset.
func (*GeminiCLIAgent) ChunkTranscript ¶
func (g *GeminiCLIAgent) ChunkTranscript(ctx context.Context, content []byte, maxSize int) ([][]byte, error)
ChunkTranscript splits a Gemini JSON transcript by distributing messages across chunks. Gemini uses JSON format with a {"messages": [...]} structure, so chunking splits the messages array while preserving the JSON structure in each chunk.
func (*GeminiCLIAgent) Description ¶
func (g *GeminiCLIAgent) Description() string
Description returns a human-readable description.
func (*GeminiCLIAgent) DetectPresence ¶
func (g *GeminiCLIAgent) DetectPresence(ctx context.Context) (bool, error)
DetectPresence checks if Gemini CLI is configured in the repository.
func (*GeminiCLIAgent) DiscoverReviewSkills ¶ added in v0.6.1
func (g *GeminiCLIAgent) DiscoverReviewSkills(_ context.Context) ([]agent.DiscoveredSkill, error)
DiscoverReviewSkills is a stub until the Gemini CLI on-disk extension layout is verified. Returns (nil, nil) so the picker relies on the per-agent install hint for Phase 1.
func (*GeminiCLIAgent) ExtractModifiedFilesFromOffset ¶
func (g *GeminiCLIAgent) ExtractModifiedFilesFromOffset(path string, startOffset int) (files []string, currentPosition int, err error)
ExtractModifiedFilesFromOffset extracts files modified since a given message index. For Gemini (JSON format), offset is the starting message index. Returns:
- files: list of file paths modified by Gemini (from Write/Edit tools)
- currentPosition: total number of messages in the transcript
- error: any error encountered during reading
func (*GeminiCLIAgent) FormatResumeCommand ¶
func (g *GeminiCLIAgent) FormatResumeCommand(sessionID string) string
FormatResumeCommand returns the command to resume a Gemini CLI session.
func (*GeminiCLIAgent) GenerateText ¶ added in v0.5.6
func (g *GeminiCLIAgent) GenerateText(ctx context.Context, prompt string, model string) (string, error)
GenerateText sends a prompt to the Gemini CLI and returns the raw text response.
The prompt is piped to the Gemini CLI via stdin rather than embedded in argv. Per gemini --help, the -p/--prompt flag is appended to any input read from stdin; we pass a single-space placeholder to trigger headless (non-interactive) mode and let stdin carry the actual content, avoiding argv size limits.
func (*GeminiCLIAgent) GetSessionBaseDir ¶ added in v0.5.3
func (g *GeminiCLIAgent) GetSessionBaseDir() (string, error)
GetSessionBaseDir returns the base directory containing per-project session subdirectories. Unlike GetSessionDir, this does NOT use ENTIRE_TEST_GEMINI_PROJECT_DIR because the test override points to a specific project dir, not the base containing all projects.
func (*GeminiCLIAgent) GetSessionDir ¶
func (g *GeminiCLIAgent) GetSessionDir(repoPath string) (string, error)
GetSessionDir returns the directory where Gemini stores session transcripts. Gemini stores sessions in ~/.gemini/tmp/<project-hash>/chats/
func (*GeminiCLIAgent) GetSessionID ¶
func (g *GeminiCLIAgent) GetSessionID(input *agent.HookInput) string
GetSessionID extracts the session ID from hook input.
func (*GeminiCLIAgent) GetTranscriptPosition ¶
func (g *GeminiCLIAgent) GetTranscriptPosition(path string) (int, error)
GetTranscriptPosition returns the current message count of a Gemini transcript. Gemini uses JSON format with a messages array, so position is the message count. Returns 0 if the file doesn't exist or is empty.
func (*GeminiCLIAgent) HookNames ¶ added in v0.4.6
func (g *GeminiCLIAgent) HookNames() []string
HookNames returns the hook verbs Gemini CLI supports. These become subcommands: entire hooks gemini <verb>
func (*GeminiCLIAgent) InstallHooks ¶
InstallHooks installs Gemini CLI hooks in .gemini/settings.json. If force is true, removes existing Entire hooks before installing. Returns the number of hooks installed.
func (*GeminiCLIAgent) IsPreview ¶ added in v0.4.6
func (g *GeminiCLIAgent) IsPreview() bool
func (*GeminiCLIAgent) LaunchCmd ¶ added in v0.6.1
LaunchCmd builds an exec.Cmd for `gemini "<initialPrompt>"`. Stdio is wired to the caller's TTY so the agent runs foreground and the user interacts normally. The call site is expected to Run() and wait. Hooks inherit the parent environment.
func (*GeminiCLIAgent) Name ¶
func (g *GeminiCLIAgent) Name() types.AgentName
Name returns the agent registry key.
func (*GeminiCLIAgent) ParseHookEvent ¶ added in v0.4.6
func (g *GeminiCLIAgent) ParseHookEvent(_ context.Context, hookName string, stdin io.Reader) (*agent.Event, error)
ParseHookEvent translates a Gemini CLI hook into a normalized lifecycle Event. Returns nil if the hook has no lifecycle significance (e.g., pass-through hooks).
func (*GeminiCLIAgent) ProtectedDirs ¶ added in v0.4.3
func (g *GeminiCLIAgent) ProtectedDirs() []string
ProtectedDirs returns directories that Gemini uses for config/state.
func (*GeminiCLIAgent) ReadSession ¶
func (g *GeminiCLIAgent) ReadSession(input *agent.HookInput) (*agent.AgentSession, error)
ReadSession reads a session from Gemini's storage (JSON transcript file). The session data is stored in NativeData as raw JSON bytes.
func (*GeminiCLIAgent) ReadTranscript ¶ added in v0.4.6
func (g *GeminiCLIAgent) ReadTranscript(sessionRef string) ([]byte, error)
ReadTranscript reads the raw JSON transcript bytes for a session.
func (*GeminiCLIAgent) ReassembleTranscript ¶
func (g *GeminiCLIAgent) ReassembleTranscript(chunks [][]byte) ([]byte, error)
ReassembleTranscript merges Gemini JSON chunks by combining their message arrays.
func (*GeminiCLIAgent) ResolveSessionFile ¶ added in v0.4.3
func (g *GeminiCLIAgent) ResolveSessionFile(sessionDir, agentSessionID string) string
ResolveSessionFile returns the path to a Gemini session file. Gemini names files as session-<date>-<shortid>.json where shortid is the first 8 chars of the session UUID. This searches for an existing file matching the pattern, falling back to constructing a filename matching Gemini's convention if no match is found.
func (*GeminiCLIAgent) Type ¶
func (g *GeminiCLIAgent) Type() types.AgentType
Type returns the agent type identifier.
func (*GeminiCLIAgent) UninstallHooks ¶
func (g *GeminiCLIAgent) UninstallHooks(ctx context.Context) error
UninstallHooks removes Entire hooks from Gemini CLI settings.
func (*GeminiCLIAgent) WriteHookResponse ¶ added in v0.5.1
func (g *GeminiCLIAgent) WriteHookResponse(message string) error
WriteHookResponse outputs a hook response message as plain text to stdout.
Why plain text and not JSON? Gemini CLI (as of v0.40.0) double-displays systemMessage when it arrives in JSON form: once via emitHookSystemMessage (rendered with the [hookName] source tag) and again via the SessionStart path's direct historyManager.addItem (rendered without a tag). With plain text, gemini's convertPlainTextToHookOutput synthesizes a systemMessage internally, the JSON-only emitHookSystemMessage event doesn't fire, and the user sees the banner exactly once.
func (*GeminiCLIAgent) WriteSession ¶
func (g *GeminiCLIAgent) WriteSession(_ context.Context, session *agent.AgentSession) error
WriteSession writes a session to Gemini's storage (JSON transcript file). Uses the NativeData field which contains raw JSON bytes.
type GeminiHookEntry ¶
type GeminiHookEntry struct {
Name string `json:"name"`
Type string `json:"type"`
Command string `json:"command"`
}
GeminiHookEntry represents a single hook command. Unlike Claude Code, Gemini CLI requires a "name" field for each hook entry.
type GeminiHookMatcher ¶
type GeminiHookMatcher struct {
Matcher string `json:"matcher,omitempty"`
Hooks []GeminiHookEntry `json:"hooks"`
}
GeminiHookMatcher matches hooks to specific patterns
type GeminiHooks ¶
type GeminiHooks struct {
// Hooks are only executed when hooksConfig.enabled is true in .gemini/settings.json.
SessionStart []GeminiHookMatcher `json:"SessionStart,omitempty"`
SessionEnd []GeminiHookMatcher `json:"SessionEnd,omitempty"`
BeforeAgent []GeminiHookMatcher `json:"BeforeAgent,omitempty"`
AfterAgent []GeminiHookMatcher `json:"AfterAgent,omitempty"`
BeforeModel []GeminiHookMatcher `json:"BeforeModel,omitempty"`
AfterModel []GeminiHookMatcher `json:"AfterModel,omitempty"`
BeforeToolSelection []GeminiHookMatcher `json:"BeforeToolSelection,omitempty"`
BeforeTool []GeminiHookMatcher `json:"BeforeTool,omitempty"`
AfterTool []GeminiHookMatcher `json:"AfterTool,omitempty"`
PreCompress []GeminiHookMatcher `json:"PreCompress,omitempty"`
Notification []GeminiHookMatcher `json:"Notification,omitempty"`
}
GeminiHooks contains all hook configurations
type GeminiHooksConfig ¶
type GeminiHooksConfig struct {
Enabled bool `json:"enabled,omitempty"`
}
GeminiHooksConfig contains tool-related settings
type GeminiMessage ¶
type GeminiMessage struct {
ID string `json:"id,omitempty"` // UUID for the message
Type string `json:"type"` // MessageTypeUser or MessageTypeGemini
Content string `json:"content,omitempty"`
ToolCalls []GeminiToolCall `json:"toolCalls,omitempty"`
}
GeminiMessage represents a single message in the transcript
func (*GeminiMessage) UnmarshalJSON ¶ added in v0.4.5
func (m *GeminiMessage) UnmarshalJSON(data []byte) error
UnmarshalJSON handles both string and array content formats in Gemini transcripts. User messages use: "content": [{"text": "..."}] (array of objects) Gemini messages use: "content": "response text" (string)
type GeminiSettings ¶
type GeminiSettings struct {
HooksConfig GeminiHooksConfig `json:"hooksConfig,omitempty"`
Hooks GeminiHooks `json:"hooks,omitempty"`
}
GeminiSettings represents the .gemini/settings.json structure
type GeminiToolCall ¶
type GeminiToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Args map[string]interface{} `json:"args"`
Status string `json:"status,omitempty"`
}
GeminiToolCall represents a tool call in a gemini message
type GeminiTranscript ¶
type GeminiTranscript struct {
Messages []GeminiMessage `json:"messages"`
}
GeminiTranscript represents the top-level structure of a Gemini session file
func ParseTranscript ¶
func ParseTranscript(data []byte) (*GeminiTranscript, error)
ParseTranscript parses raw JSON content into a transcript structure