Documentation
¶
Overview ¶
Package steer decides whether an agent's search (grep, glob, shell) should be redirected to the code graph. This file holds pure path-scope helpers.
Index ¶
- Constants
- func AllNonCode(paths []string, exts ExtSet) bool
- func AllOutsideRoot(root, cwd string, targets []string) bool
- func Decide(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) hookapi.Decision
- func IsCodePath(path string, exts ExtSet) bool
- func OutsideRoot(root, cwd, target string) bool
- func SessionStartContext(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) string
- func SubagentStartContext(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) string
- type Engine
- func (e *Engine) Close() error
- func (e *Engine) Decide(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) (d hookapi.Decision)
- func (e *Engine) SessionStartContext(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) string
- func (e *Engine) SubagentStartContext(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) string
- type ExtSet
- type GlobClass
- type GlobKind
- type Index
- type Options
- type PatternClass
- type SearchCall
- type ShellAnalysis
- type TargetKind
Constants ¶
const ( // DefaultSoftBudget is the balanced-mode deny budget per (session, // agent) used when config.SoftBudget is not positive. DefaultSoftBudget = 8 // DefaultLookupBudget bounds the graph lookup of one decision. DefaultLookupBudget = 25 * time.Millisecond // LookupLimit is the number of graph results quoted in a reason. LookupLimit = 12 // MaxReasonLen caps a deny reason in bytes. MaxReasonLen = 1200 // RepoMapMaxLines caps the repo_map quoted for an exploration. RepoMapMaxLines = 40 // ReadOutlineMinLines is the size above which a whole-file read of a // code file gets an outline. ReadOutlineMinLines = 400 // ReadOutlineMaxLines caps that outline. ReadOutlineMaxLines = 25 )
Steering limits (PLAN "Steering algoritması").
const MaxStartContextBytes = 600 * 4
MaxStartContextBytes caps SessionStart / SubagentStart context (600 tokens at ~4 bytes per token).
Variables ¶
This section is empty.
Functions ¶
func AllNonCode ¶
AllNonCode reports whether every target is non-code. An empty target list means the current directory and therefore returns false.
func AllOutsideRoot ¶
AllOutsideRoot reports whether every target lies outside root. An empty list means cwd, which is checked instead.
func IsCodePath ¶
IsCodePath reports whether path names a file with an enabled code extension. Directories and extensionless names are not code paths.
func OutsideRoot ¶
OutsideRoot reports whether target (relative to cwd unless absolute) lies outside root. It is pure path arithmetic; symlinks are not resolved.
func SessionStartContext ¶
SessionStartContext is Engine.SessionStartContext with a one-shot engine.
Types ¶
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine makes steering decisions for hook events. It caches opened indexes per repository root; it is safe for concurrent use.
func (*Engine) Decide ¶
func (e *Engine) Decide(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) (d hookapi.Decision)
Decide steers one PreToolUse event (grep, glob, read or shell). Any other event or tool, and every internal error, yields allow.
func (*Engine) SessionStartContext ¶
func (e *Engine) SessionStartContext(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) string
SessionStartContext returns the context injected at session start: index statistics, the MCP tool cheat-sheet, the steering rules of the mode and the top-level repo_map, within MaxStartContextBytes. A missing index is built first (the session start budget allows it). Outside a repository it returns "".
func (*Engine) SubagentStartContext ¶
func (e *Engine) SubagentStartContext(ctx context.Context, ev hookapi.HookEvent, cfg config.Config) string
SubagentStartContext is the subagent variant (Claude's Explore / Plan agents do not read CLAUDE.md). It never builds in the foreground: a missing index is handed to StartBuild and the rules are still returned.
type ExtSet ¶
type ExtSet map[string]struct{}
ExtSet is a set of enabled code file extensions (with leading dot). A nil ExtSet means "every supported language".
func DefaultExtSet ¶
func DefaultExtSet() ExtSet
DefaultExtSet returns the extensions of every supported language.
type GlobClass ¶
type GlobClass struct {
Kind GlobKind
// Name is the literal last segment (GlobLiteral only).
Name string
// Stem is Name without its extension when the glob has a single literal
// expansion; empty otherwise.
Stem string
// Hint is the longest identifier-like literal fragment of a wildcard
// file name (GlobExplore only), e.g. "Service" for "*Service*.java".
Hint string
}
GlobClass is the result of ClassifyGlob.
func ClassifyGlob ¶
ClassifyGlob decides whether a glob is a literal file lookup, a non-code scan or a broad code exploration. Negated globs ("!x") never widen a search and are reported as GlobNonCode.
type Index ¶
type Index interface {
query.Backend
Freshen(ctx context.Context, budget time.Duration) (*index.Result, error)
}
Index is the code graph the engine consults. *index.Indexer implements it.
type Options ¶
type Options struct {
// Open opens the index of a located repository. The default is
// index.Open with the real resolver. Indexes implementing io.Closer are
// closed by Engine.Close.
Open func(ctx context.Context, loc *index.Location, cfg *config.Config) (Index, error)
// StartBuild is the hook point for building a missing index in the
// background (e.g. spawning a detached `graphmaster index --quiet`).
// Decisions never build an index themselves. Nil does nothing.
StartBuild func(root string)
// LookupBudget bounds the graph lookup (default 25ms).
LookupBudget time.Duration
// Now is the session clock (default time.Now).
Now func() time.Time
// Logf receives internal errors; steering always fails open.
Logf func(format string, args ...any)
}
Options configure an Engine. Every field is optional.
type PatternClass ¶
type PatternClass struct {
// SymbolLike is true when the pattern looks like a lookup of a code
// symbol (identifier, qualified name, call, keyword-prefixed definition).
SymbolLike bool
// Idents are the unique identifier tokens in first-seen order, without
// definition keywords or a leading '$'. Filled best-effort for
// non-symbol patterns too.
Idents []string
// Queries are the symbol expressions worth looking up, one per
// alternative / ".*" fragment, e.g. "pkg.Func" or "Foo::bar".
Queries []string
// Norm (pnorm) is the sorted unique Idents joined by a space, case kept.
// Equal norms mean "the same search" for retry detection.
Norm string
// Reason explains a non-symbol verdict; empty when SymbolLike.
Reason string
}
PatternClass is the result of classifying a search pattern.
func ClassifyFixed ¶
func ClassifyFixed(p string) PatternClass
ClassifyFixed classifies a fixed-string pattern (grep -F, rg -F): no anchors, escapes, alternation or ".*" are interpreted.
func ClassifyPattern ¶
func ClassifyPattern(p string) PatternClass
ClassifyPattern classifies a regular-expression search pattern (grep, grep -E, rg, the Grep tool).
func ClassifyPatterns ¶
func ClassifyPatterns(ps []string, fixed bool) PatternClass
ClassifyPatterns classifies several patterns of one search (e.g. multiple -e flags). The set is symbol-like only if every pattern is.
type SearchCall ¶
type SearchCall struct {
// Tool is the canonical tool name: grep, egrep, fgrep, rg, ag, ack,
// "git grep", find, fd, ls, tree or locate.
Tool string
// Patterns are the literal search patterns (content regexes, or file-name
// patterns for NameSearch tools). Dynamic ($VAR) patterns are omitted.
Patterns []string
// Paths are the explicit or implied (".") targets. Nil when the input is
// stdin or an unknown file list (xargs, find -exec).
Paths []string
// Globs are file filters: --include, -g, -t TYPE, -name, -e EXT, ...
Globs []string
// Recursive is true for tree-wide searches (not a single file / stdin).
Recursive bool
// ReadsStdin is true when the tool searches its standard input.
ReadsStdin bool
// Fixed is true for fixed-string matching (-F, -Q, fgrep).
Fixed bool
// NameSearch is true when file names, not contents, are searched.
NameSearch bool
}
SearchCall is one recognised search command inside a shell command line.
type ShellAnalysis ¶
type ShellAnalysis struct {
Searches []SearchCall
// AllReadOnly is true when every command is a known side-effect-free
// command (search tools, cat, head, sort, sed -n, ...) and no output is
// redirected to a file.
AllReadOnly bool
// UnknownDir is true when a cd/pushd/popd or "git -C" moved a command to
// a directory that cannot be resolved statically (no argument, ~, -,
// $VAR). Search scopes are then unknown, so the line is never steered.
UnknownDir bool
}
ShellAnalysis is the result of AnalyzeShell.
func AnalyzeShell ¶
func AnalyzeShell(cmd string) (ShellAnalysis, error)
AnalyzeShell parses a shell command line and reports the searches it runs. A parse error means the command could not be understood; callers must allow it.
func (ShellAnalysis) Steerable ¶
func (a ShellAnalysis) Steerable() bool
Steerable reports whether the command line should be steered: everything is read-only and at least one search walks a tree reading files.
type TargetKind ¶
type TargetKind int
TargetKind classifies a search target (file, directory or path glob).
const ( // TargetTree is a directory or anything that may contain code files. TargetTree TargetKind = iota // TargetCode is a single code file (or a glob limited to code files). TargetCode // TargetNonCode only covers non-code files (docs, configs, stdin...). TargetNonCode )
func ClassifyTarget ¶
func ClassifyTarget(path string, exts ExtSet) TargetKind
ClassifyTarget classifies a single target path without touching the filesystem. Extensionless names are assumed to be directories.
func (TargetKind) String ¶
func (k TargetKind) String() string