88 lines
2.1 KiB
Ruby
88 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'json'
|
|
require 'open3'
|
|
|
|
module PluginConfig
|
|
class RuntimeVerifier
|
|
STATUSES = %w[enabled disabled failed_to_load not_present].freeze
|
|
|
|
def initialize(capture3: Open3.method(:capture3))
|
|
@capture3 = capture3
|
|
end
|
|
|
|
def snapshot
|
|
stdout, _stderr, status = @capture3.call('claude', 'plugin', 'list')
|
|
return {} unless status.success?
|
|
|
|
parse_plugin_list(stdout)
|
|
rescue Errno::ENOENT
|
|
{}
|
|
end
|
|
|
|
def verify_status(plugin_key, expected_status)
|
|
current = snapshot
|
|
actual = current[plugin_key] || 'not_present'
|
|
|
|
if actual == expected_status
|
|
{ verified: true, details: "Plugin '#{plugin_key}' status is '#{expected_status}'" }
|
|
else
|
|
{ verified: false, details: "Plugin '#{plugin_key}' expected '#{expected_status}', got '#{actual}'" }
|
|
end
|
|
end
|
|
|
|
def self.diff(before, after)
|
|
all_keys = (before.keys + after.keys).uniq
|
|
changed = 0
|
|
unchanged = 0
|
|
|
|
all_keys.each do |key|
|
|
if before[key] == after[key]
|
|
unchanged += 1
|
|
else
|
|
changed += 1
|
|
end
|
|
end
|
|
|
|
{ changed: changed, unchanged: unchanged }
|
|
end
|
|
|
|
private
|
|
|
|
def parse_plugin_list(output)
|
|
plugins = {}
|
|
|
|
output.each_line do |line|
|
|
line = line.strip
|
|
next if line.empty?
|
|
|
|
# Expected format: "plugin-name@marketplace status"
|
|
# or variations with columns/tabs
|
|
parts = line.split(/\s{2,}|\t/)
|
|
next unless parts.length >= 2
|
|
|
|
key = parts[0].strip
|
|
status = parts[1].strip.downcase
|
|
|
|
next unless key.include?('@')
|
|
|
|
normalized = if STATUSES.include?(status)
|
|
status
|
|
elsif status.include?('enabled')
|
|
'enabled'
|
|
elsif status.include?('disabled')
|
|
'disabled'
|
|
elsif status.include?('fail')
|
|
'failed_to_load'
|
|
else
|
|
status
|
|
end
|
|
|
|
plugins[key] = normalized
|
|
end
|
|
|
|
plugins
|
|
end
|
|
end
|
|
end
|