package ccsettings // Matching is approval.ParseRule's, the one reading of Claude Code's rule // grammar in Codey: a rule in a settings file means what the same rule means // given to --allowedTools, rather than two parsers drifting apart on what // Bash(git:*) covers. This file only adapts it to the two questions a rule // set asks. import ( "encoding/json" "github.com/johannSo/codey/internal/approval" ) // Match is the result of checking one rule against one call. type Match int const ( NoMatch Match = iota Matched // Unsure means the call cannot be pinned down well enough to say — an // opaque shell command, a word built at run time. An allow rule treats it // as no match; a deny or ask rule treats it as a reason to ask. Unsure ) // matchMode is which kind of rule is asking. It matters for compound shell // commands: an allow rule covers "a && b" only if it covers both, while a // deny or ask rule catches it if it catches either — and catches a command it // cannot see all the way through if anything that can be read out of it // matches. type matchMode int const ( forAllow matchMode = iota forRestrict ) // compiled is one parsed rule. type compiled interface { Match(tool string, input json.RawMessage, mode matchMode) Match } // matchEnv is what relative rule paths are resolved against. type matchEnv struct { home, root string } // compile parses a rule. An error means the rule names something Codey has no // equivalent for, or uses a specifier it does not understand; the caller // reports it and the rule takes no part. func compile(rule string, env matchEnv) (compiled, error) { r, err := approval.ParseRule(rule) if err != nil { return nil, err } r.Root, r.Home = env.root, env.home return shared{r}, nil } type shared struct{ r approval.Rule } func (s shared) Match(tool string, input json.RawMessage, mode matchMode) Match { if mode == forAllow { if s.r.Matches(tool, input) { return Matched } return NoMatch } switch { case s.r.Touches(tool, input): return Matched case s.r.Unsure(tool, input): return Unsure } return NoMatch }