Documentation
¶
Overview ¶
Package cursor implements the Agent interface for Cursor.
Index ¶
- Constants
- Variables
- func ExtractModifiedFiles(lines []transcript.Line) []string
- func NewCursorAgent() agent.Agent
- type CursorAgent
- func (c *CursorAgent) AreHooksInstalled(ctx context.Context) (bool, error)
- func (c *CursorAgent) CallerSessionEnvVar() string
- func (c *CursorAgent) ChunkTranscript(_ context.Context, content []byte, maxSize int) ([][]byte, error)
- func (c *CursorAgent) Description() string
- func (c *CursorAgent) DetectPresence(ctx context.Context) (bool, error)
- func (c *CursorAgent) ExtractModifiedFilesFromOffset(_ context.Context, path string, startOffset int) ([]string, int, error)
- func (c *CursorAgent) ExtractPrompts(sessionRef string, fromOffset int) ([]string, error)
- func (c *CursorAgent) ExtractSummary(sessionRef string) (string, error)
- func (c *CursorAgent) FormatResumeCommand(_ string) string
- func (c *CursorAgent) GenerateText(ctx context.Context, prompt string, model string) (string, error)
- func (c *CursorAgent) GetSessionBaseDir() (string, error)
- func (c *CursorAgent) GetSessionDir(repoPath string) (string, error)
- func (c *CursorAgent) GetSessionID(input *agent.HookInput) string
- func (c *CursorAgent) GetSupportedHooks() []agent.HookType
- func (c *CursorAgent) GetTranscriptPosition(path string) (int, error)
- func (c *CursorAgent) HookConfigRelPath() string
- func (c *CursorAgent) HookNames() []string
- func (c *CursorAgent) InstallHooks(ctx context.Context, force bool) (int, error)
- func (c *CursorAgent) Name() types.AgentName
- func (c *CursorAgent) ParseHookEvent(ctx context.Context, hookName string, stdin io.Reader) (*agent.Event, error)
- func (c *CursorAgent) PrepareTranscript(ctx context.Context, sessionRef string) error
- func (c *CursorAgent) ProtectedDirs() []string
- func (c *CursorAgent) ReadSession(input *agent.HookInput) (*agent.AgentSession, error)
- func (c *CursorAgent) ReadTranscript(sessionRef string) ([]byte, error)
- func (c *CursorAgent) ReassembleTranscript(chunks [][]byte) ([]byte, error)
- func (c *CursorAgent) ResolveSessionFile(sessionDir, agentSessionID string) string
- func (c *CursorAgent) SidecarImages(ctx context.Context, sessionRef string) ([]agent.CompactedTranscriptAsset, error)
- func (c *CursorAgent) Type() types.AgentType
- func (c *CursorAgent) UninstallHooks(ctx context.Context) error
- func (c *CursorAgent) WriteSession(_ context.Context, session *agent.AgentSession) error
- type CursorHookEntry
- type CursorHooks
- type CursorHooksFile
Constants ¶
const ( HookNameSessionStart = "session-start" HookNameSessionEnd = "session-end" HookNameBeforeSubmitPrompt = "before-submit-prompt" HookNameStop = "stop" HookNamePreCompact = "pre-compact" HookNameSubagentStart = "subagent-start" HookNameSubagentStop = "subagent-stop" )
Cursor hook names - these become subcommands under `entire hooks cursor`
const HooksFileName = "hooks.json"
HooksFileName is the hooks file used by Cursor.
Variables ¶
var FileModificationTools = []string{"Write", "StrReplace"}
FileModificationTools lists the Cursor tool names that create or modify files.
Captured from a real Cursor session (testdata/real_session_tool_use.jsonl): Write creates or overwrites a file, StrReplace edits one in place. Cursor's read-only tools (Read, Grep, Glob, Shell) are deliberately absent — Shell can of course modify files, but the transcript records only the command string, so attributing files to it would mean parsing shell, not reading a path.
Cursor's names differ from Claude Code's (Write/Edit), so this list cannot be shared with claudecode.FileModificationTools.
Functions ¶
func ExtractModifiedFiles ¶ added in v0.10.3
func ExtractModifiedFiles(lines []transcript.Line) []string
ExtractModifiedFiles extracts the files modified by Cursor tool calls in the given transcript lines, in first-seen order and deduplicated.
Cursor records tool_use content blocks in the same shape as Claude Code (message.content[i].type == "tool_use", with name and input), so this mirrors claudecode.ExtractModifiedFiles. The divergences are the tool names and the input key — see FileModificationTools and toolInput.
func NewCursorAgent ¶
NewCursorAgent creates a new Cursor agent instance.
Types ¶
type CursorAgent ¶
type CursorAgent struct {
CommandRunner agent.TextCommandRunner
}
CursorAgent implements the Agent interface for Cursor.
func (*CursorAgent) AreHooksInstalled ¶
func (c *CursorAgent) AreHooksInstalled(ctx context.Context) (bool, error)
AreHooksInstalled checks if Entire hooks are installed.
A missing config file is an answer, not a failure: that file is where the state lives, so its absence means no hooks. Anything that stops us reading the answer — an unreadable file, malformed config — is returned as an error, since "we could not tell" and "there are none" are different things to a caller deciding whether hooks can be left alone.
func (*CursorAgent) CallerSessionEnvVar ¶ added in v0.11.0
func (c *CursorAgent) CallerSessionEnvVar() string
CallerSessionEnvVar names the variable holding the session ID Cursor publishes into the environment of the processes its shell tool spawns, alongside CURSOR_AGENT. It is the same conversation ID every Cursor lifecycle event reports as its session ID, so it resolves against session state without translation.
func (*CursorAgent) ChunkTranscript ¶
func (c *CursorAgent) ChunkTranscript(_ context.Context, content []byte, maxSize int) ([][]byte, error)
ChunkTranscript splits a JSONL transcript at line boundaries.
func (*CursorAgent) Description ¶
func (c *CursorAgent) Description() string
Description returns a human-readable description.
func (*CursorAgent) DetectPresence ¶
func (c *CursorAgent) DetectPresence(ctx context.Context) (bool, error)
DetectPresence checks if Cursor is configured in the repository.
func (*CursorAgent) ExtractModifiedFilesFromOffset ¶ added in v0.5.0
func (c *CursorAgent) ExtractModifiedFilesFromOffset(_ context.Context, path string, startOffset int) ([]string, int, error)
ExtractModifiedFilesFromOffset extracts files modified by tool calls appearing at or after startOffset, and returns the transcript's current line count.
A missing transcript is not an error: Cursor reports transcript_path as null in CLI mode, so ResolveSessionFile predicts a path that may not exist yet, and this runs on capture paths that must fail open (matching GetTranscriptPosition).
func (*CursorAgent) ExtractPrompts ¶ added in v0.5.0
func (c *CursorAgent) ExtractPrompts(sessionRef string, fromOffset int) ([]string, error)
ExtractPrompts extracts user prompts from the transcript starting at the given line offset. Cursor uses the same JSONL format as Claude Code; the shared transcript package normalizes "role" → "type" and strips <user_query> tags.
func (*CursorAgent) ExtractSummary ¶ added in v0.5.0
func (c *CursorAgent) ExtractSummary(sessionRef string) (string, error)
ExtractSummary extracts the last assistant message as a session summary.
func (*CursorAgent) FormatResumeCommand ¶
func (c *CursorAgent) FormatResumeCommand(_ string) string
FormatResumeCommand returns an instruction to resume a Cursor session. Cursor is a GUI IDE, so there's no CLI command to resume a session directly.
func (*CursorAgent) GenerateText ¶ added in v0.5.6
func (c *CursorAgent) GenerateText(ctx context.Context, prompt string, model string) (string, error)
GenerateText sends a prompt to the Cursor agent CLI and returns the raw text response.
The prompt is piped via stdin rather than as a positional argument, avoiding argv size limits. --print triggers non-interactive mode; --force --trust are required for headless operation per cursor-agent --help.
func (*CursorAgent) GetSessionBaseDir ¶ added in v0.5.3
func (c *CursorAgent) GetSessionBaseDir() (string, error)
GetSessionBaseDir returns the base directory containing per-project session subdirectories. Unlike GetSessionDir, this does NOT use test overrides because the override points to a specific project dir, not the base containing all projects.
func (*CursorAgent) GetSessionDir ¶
func (c *CursorAgent) GetSessionDir(repoPath string) (string, error)
GetSessionDir returns the directory where Cursor stores session transcripts. No relocation variable applies. Cursor's CLI bundle does resolve a data dir from CURSOR_DATA_DIR and advertises <data>/projects/<hash>/agent-transcripts to the model, but the transcript files are written by its native file service, which stays anchored on the real home: with the variable set, cursor-agent 2026.09.08 still writes them under ~/.cursor (verified locally). Following the variable here would point resume, attach and owner detection at a directory Cursor never writes to.
func (*CursorAgent) GetSessionID ¶
func (c *CursorAgent) GetSessionID(input *agent.HookInput) string
GetSessionID extracts the session ID from hook input.
func (*CursorAgent) GetSupportedHooks ¶
func (c *CursorAgent) GetSupportedHooks() []agent.HookType
GetSupportedHooks returns the hook types Cursor supports.
func (*CursorAgent) GetTranscriptPosition ¶ added in v0.5.0
func (c *CursorAgent) GetTranscriptPosition(path string) (int, error)
GetTranscriptPosition returns the current line count of a Cursor transcript. Cursor uses the same JSONL format as Claude Code, so position is the number of lines. Uses bufio.Reader to handle arbitrarily long lines (no size limit). Returns 0 if the file doesn't exist or is empty.
func (*CursorAgent) HookConfigRelPath ¶ added in v0.10.6
func (c *CursorAgent) HookConfigRelPath() string
HookConfigRelPath implements agent.HookConfigLocator.
func (*CursorAgent) HookNames ¶
func (c *CursorAgent) HookNames() []string
HookNames returns the hook verbs Cursor supports. These become subcommands: entire hooks cursor <verb>
func (*CursorAgent) InstallHooks ¶
InstallHooks installs Cursor hooks in .cursor/hooks.json. If force is true, removes existing Entire hooks before installing. Returns the number of hooks installed. Unknown top-level fields and hook types are preserved on round-trip.
func (*CursorAgent) Name ¶
func (c *CursorAgent) Name() types.AgentName
Name returns the agent registry key.
func (*CursorAgent) ParseHookEvent ¶
func (c *CursorAgent) ParseHookEvent(ctx context.Context, hookName string, stdin io.Reader) (*agent.Event, error)
ParseHookEvent translates a Cursor hook into a normalized lifecycle Event. Returns nil if the hook has no lifecycle significance.
func (*CursorAgent) PrepareTranscript ¶ added in v0.5.2
func (c *CursorAgent) PrepareTranscript(ctx context.Context, sessionRef string) error
PrepareTranscript waits for Cursor's transcript file to be flushed to disk. Cursor writes transcripts asynchronously; during mid-turn commits the file may not yet contain data. This polls until the file exists and is non-empty, or until the timeout expires.
func (*CursorAgent) ProtectedDirs ¶
func (c *CursorAgent) ProtectedDirs() []string
ProtectedDirs returns directories that Cursor uses for config/state.
func (*CursorAgent) ReadSession ¶
func (c *CursorAgent) ReadSession(input *agent.HookInput) (*agent.AgentSession, error)
ReadSession reads a session from Cursor's storage (JSONL transcript file). ModifiedFiles is populated from the transcript's tool_use blocks; see ExtractModifiedFiles. Git status remains the broader signal, since Cursor can also change files through Shell commands that record no path.
func (*CursorAgent) ReadTranscript ¶
func (c *CursorAgent) ReadTranscript(sessionRef string) ([]byte, error)
ReadTranscript reads the raw JSONL transcript bytes for a session.
func (*CursorAgent) ReassembleTranscript ¶
func (c *CursorAgent) ReassembleTranscript(chunks [][]byte) ([]byte, error)
ReassembleTranscript concatenates JSONL chunks with newlines.
func (*CursorAgent) ResolveSessionFile ¶
func (c *CursorAgent) ResolveSessionFile(sessionDir, agentSessionID string) string
ResolveSessionFile returns the path to a Cursor session file. Cursor IDE uses a nested layout: <dir>/<id>/<id>.jsonl Cursor CLI uses a flat layout: <dir>/<id>.jsonl We prefer nested if the file OR directory exists (the directory may be created before the file is flushed), otherwise fall back to flat.
func (*CursorAgent) SidecarImages ¶ added in v0.9.0
func (c *CursorAgent) SidecarImages(ctx context.Context, sessionRef string) ([]agent.CompactedTranscriptAsset, error)
SidecarImages captures images that Cursor stores outside the JSONL transcript. Cursor keeps pasted/generated images in a per-session SQLite blob store (~/.cursor/chats/<workspace>/<session>/store.db), not the transcript Entire condenses, so they would otherwise be lost from the checkpoint. This locates that store for the session, shells out to the sqlite3 binary to read the image blobs, and returns them as checkpoint assets.
It is best-effort: when the store, the sqlite3 binary, or the expected schema is absent, or the store is too large, it returns no images and no error. sessionRef is the transcript path.
func (*CursorAgent) Type ¶
func (c *CursorAgent) Type() types.AgentType
Type returns the agent type identifier.
func (*CursorAgent) UninstallHooks ¶
func (c *CursorAgent) UninstallHooks(ctx context.Context) error
UninstallHooks removes Entire hooks from Cursor HooksFileName. Unknown top-level fields and hook types are preserved on round-trip.
func (*CursorAgent) WriteSession ¶
func (c *CursorAgent) WriteSession(_ context.Context, session *agent.AgentSession) error
WriteSession writes a session to Cursor's storage (JSONL transcript file).
type CursorHookEntry ¶
type CursorHookEntry struct {
Command string `json:"command"`
Matcher string `json:"matcher,omitempty"`
}
CursorHookEntry represents a single hook command. Cursor hooks have a command string and an optional matcher field for filtering by tool name.
type CursorHooks ¶
type CursorHooks struct {
SessionStart []CursorHookEntry `json:"sessionStart,omitempty"`
SessionEnd []CursorHookEntry `json:"sessionEnd,omitempty"`
BeforeSubmitPrompt []CursorHookEntry `json:"beforeSubmitPrompt,omitempty"`
Stop []CursorHookEntry `json:"stop,omitempty"`
PreCompact []CursorHookEntry `json:"preCompact,omitempty"`
SubagentStart []CursorHookEntry `json:"subagentStart,omitempty"`
SubagentStop []CursorHookEntry `json:"subagentStop,omitempty"`
}
CursorHooks contains all hook configurations using camelCase keys.
type CursorHooksFile ¶
type CursorHooksFile struct {
Version int `json:"version"`
Hooks CursorHooks `json:"hooks"`
}
CursorHooksFile represents the .cursor/HooksFileName structure. Cursor uses a flat JSON file with version and hooks sections.