Class: Aircana::HooksManifest

Inherits:
Object
  • Object
show all
Defined in:
lib/aircana/hooks_manifest.rb

Overview

Manages Claude Code plugin hooks manifest (hooks/hooks.json) files

Constant Summary collapse

VALID_EVENTS =
%w[PreToolUse PostToolUse UserPromptSubmit SessionStart Notification].freeze
VALID_HOOK_TYPES =
%w[command validation notification].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(plugin_root) ⇒ HooksManifest

Returns a new instance of HooksManifest.



14
15
16
# File 'lib/aircana/hooks_manifest.rb', line 14

def initialize(plugin_root)
  @plugin_root = plugin_root
end

Instance Attribute Details

#plugin_rootObject (readonly)

Returns the value of attribute plugin_root.



12
13
14
# File 'lib/aircana/hooks_manifest.rb', line 12

def plugin_root
  @plugin_root
end

Class Method Details

.from_settings_format(settings_hooks) ⇒ Object

Converts old settings.local.json hook format to hooks.json format



103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/aircana/hooks_manifest.rb', line 103

def self.from_settings_format(settings_hooks)
  hooks_config = {}

  settings_hooks.each do |event, hook_groups|
    hooks_config[event] = hook_groups.map do |group|
      {
        "hooks" => group["hooks"],
        "matcher" => group["matcher"]
      }.compact
    end
  end

  hooks_config
end

Instance Method Details

#add_hook(event:, hook_entry:, matcher: nil) ⇒ Object

Adds a hook to the manifest



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/aircana/hooks_manifest.rb', line 49

def add_hook(event:, hook_entry:, matcher: nil)
  validate_event!(event)
  validate_hook_entry!(hook_entry)

  current_data = read || {}
  current_data[event] ||= []

  hook_config = build_hook_config(hook_entry, matcher)
  current_data[event] << hook_config

  write_manifest(current_data)
  manifest_path
end

#create(hooks_config = {}) ⇒ Object

Creates a new hooks manifest with the given hooks configuration



19
20
21
22
23
24
# File 'lib/aircana/hooks_manifest.rb', line 19

def create(hooks_config = {})
  validate_hooks_config!(hooks_config)
  write_manifest(hooks_config)

  manifest_path
end

#exists?Boolean

Checks if the hooks manifest exists

Returns:

  • (Boolean)


79
80
81
# File 'lib/aircana/hooks_manifest.rb', line 79

def exists?
  File.exist?(manifest_path)
end

#hooks_dirObject

Returns the hooks directory



89
90
91
# File 'lib/aircana/hooks_manifest.rb', line 89

def hooks_dir
  File.join(plugin_root, "hooks")
end

#manifest_pathObject

Returns the path to the hooks manifest



84
85
86
# File 'lib/aircana/hooks_manifest.rb', line 84

def manifest_path
  File.join(plugin_root, "hooks", "hooks.json")
end

#readObject

Reads the existing hooks manifest



27
28
29
30
31
32
33
34
35
# File 'lib/aircana/hooks_manifest.rb', line 27

def read
  return nil unless exists?

  data = JSON.parse(File.read(manifest_path))
  # Unwrap top-level "hooks" key to maintain consistent internal API
  data["hooks"] || data
rescue JSON::ParserError => e
  raise Aircana::Error, "Invalid JSON in hooks manifest: #{e.message}"
end

#remove_hook(event:, command:) ⇒ Object

Removes a hook from the manifest



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/aircana/hooks_manifest.rb', line 64

def remove_hook(event:, command:)
  current_data = read
  return manifest_path unless current_data && current_data[event]

  current_data[event].reject! do |hook_group|
    hook_group["hooks"]&.any? { |h| h["command"] == command }
  end

  current_data.delete(event) if current_data[event].empty?

  write_manifest(current_data)
  manifest_path
end

#update(hooks_config = {}) ⇒ Object

Updates the hooks manifest with new values



38
39
40
41
42
43
44
45
46
# File 'lib/aircana/hooks_manifest.rb', line 38

def update(hooks_config = {})
  current_data = read || {}
  updated_data = deep_merge(current_data, hooks_config)

  validate_hooks_config!(updated_data)
  write_manifest(updated_data)

  manifest_path
end

#validate!Object

Validates the current manifest structure



94
95
96
97
98
99
100
# File 'lib/aircana/hooks_manifest.rb', line 94

def validate!
  data = read
  return true unless data # Empty manifest is valid

  validate_hooks_config!(data)
  true
end