Class: RubynCode::Hooks::SettingsJsonLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/hooks/settings_json_loader.rb

Overview

Loads external hook commands from a Claude Code-compatible settings.json.

Schema (matches Claude Code’s hook config):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "bash|write_file",        // regex or "*"
        "hooks": [
          { "type": "command",
            "command": "/usr/local/bin/policy-check",
            "timeout": 60,
            "env": { "FOO": "bar" }            // optional
          }
        ]
      }
    ],
    "PostToolUse":      [ ... ],
    "UserPromptSubmit": [ ... ],
    "SessionStart":     [ ... ],
    "SessionEnd":       [ ... ],
    "Stop":             [ ... ],
    "SubagentStop":     [ ... ],
    "PreCompact":       [ ... ],
    "Notification":     [ ... ]
  }
}

“matcher” may be:

- a regex string matched against the tool name (PreToolUse/PostToolUse)
  or the session id (other events accept any value);
- "*" to match everything;
- omitted/null to match everything.

The loader does not validate that commands exist on disk — that’s the Executor’s job (it will fail at fire time with a clear error).

Defined Under Namespace

Classes: LoadError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_root:, home_dir: nil) ⇒ SettingsJsonLoader

Returns a new instance of SettingsJsonLoader.

Parameters:

  • project_root (String)

    used to locate .rubyn-code/settings.json

  • home_dir (String, nil) (defaults to: nil)

    override for ~/.rubyn-code; defaults to Defaults::HOME_DIR



53
54
55
56
57
58
59
60
# File 'lib/rubyn_code/hooks/settings_json_loader.rb', line 53

def initialize(project_root:, home_dir: nil)
  @home_dir = home_dir || Config::Defaults::HOME_DIR
  @project_root = project_root
  @search_paths = [
    File.join(@project_root, '.rubyn-code', 'settings.json'),
    File.join(@home_dir, 'settings.json')
  ].freeze
end

Instance Attribute Details

#search_pathsArray<String> (readonly)

Returns paths the loader will try, in order.

Returns:

  • (Array<String>)

    paths the loader will try, in order



49
50
51
# File 'lib/rubyn_code/hooks/settings_json_loader.rb', line 49

def search_paths
  @search_paths
end

Instance Method Details

#loadHash<String, Array<Hash>>

Loads and merges settings.json from project + global.

Project wins for the same matcher/event combination: if both files define a hook for the same event, the project’s hook runs first and the global hook runs after, mirroring Claude Code’s behaviour.

Returns:

  • (Hash<String, Array<Hash>>)

    { event_name => [matcher_group, …] } where each matcher_group is { “matcher” => String, “hooks” => [command_hash, …] }



70
71
72
73
74
75
76
77
78
79
# File 'lib/rubyn_code/hooks/settings_json_loader.rb', line 70

def load
  merged = {}
  @search_paths.each do |path|
    next unless File.exist?(path)

    data = parse_file(path)
    merge_into!(merged, data['hooks'] || {})
  end
  merged
end