brainiac 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/README.md +136 -6
  4. data/bin/brainiac +472 -44
  5. data/bin/brainiac-completion.bash +1 -1
  6. data/lib/brainiac/agents.rb +27 -74
  7. data/lib/brainiac/brain.rb +6 -6
  8. data/lib/brainiac/config.rb +40 -76
  9. data/lib/brainiac/handlers/discord/api.rb +196 -0
  10. data/lib/brainiac/handlers/discord/config.rb +134 -0
  11. data/lib/brainiac/handlers/discord/delivery.rb +196 -0
  12. data/lib/brainiac/handlers/discord/gateway.rb +212 -0
  13. data/lib/brainiac/handlers/discord/message.rb +933 -0
  14. data/lib/brainiac/handlers/discord/reactions.rb +215 -0
  15. data/lib/brainiac/handlers/discord.rb +14 -1892
  16. data/lib/brainiac/handlers/github.rb +134 -317
  17. data/lib/brainiac/handlers/shared/git.rb +190 -0
  18. data/lib/brainiac/handlers/shared/inline_tags.rb +89 -0
  19. data/lib/brainiac/handlers/zoho.rb +103 -153
  20. data/lib/brainiac/helpers.rb +43 -455
  21. data/lib/brainiac/hooks.rb +86 -0
  22. data/lib/brainiac/plugins.rb +154 -0
  23. data/lib/brainiac/prompts.rb +34 -172
  24. data/lib/brainiac/restart.rb +112 -0
  25. data/lib/brainiac/routes/api.rb +411 -0
  26. data/lib/brainiac/users.rb +1 -7
  27. data/lib/brainiac/version.rb +1 -1
  28. data/lib/brainiac/zoho_mail_api.rb +2 -1
  29. data/lib/brainiac.rb +8 -1
  30. data/monitor/daemon.rb +4 -27
  31. data/monitor/shared.rb +247 -0
  32. data/monitor/{waybar-deploy-env.rb → waybar/deploy_env.rb} +17 -89
  33. data/monitor/waybar/setup.rb +232 -0
  34. data/monitor/waybar/status.rb +51 -0
  35. data/monitor/{view-logs-rofi.rb → waybar/view_logs.rb} +21 -88
  36. data/monitor/{deploy-env-macos.rb → xbar/deploy_env.rb} +3 -2
  37. data/monitor/xbar/plugin.rb +149 -0
  38. data/monitor/{setup-menubar.rb → xbar/setup.rb} +14 -30
  39. data/receiver.rb +44 -551
  40. data/templates/agents.json.example +1 -2
  41. data/templates/brainiac.json.example +8 -0
  42. data/templates/cli-providers/kiro.json.example +8 -2
  43. data/templates/plugins.json.example +3 -0
  44. data/templates/users.json.example +0 -3
  45. metadata +25 -23
  46. data/lib/brainiac/card_index.rb +0 -389
  47. data/lib/brainiac/deployments.rb +0 -258
  48. data/lib/brainiac/handlers/fizzy.rb +0 -1292
  49. data/lib/brainiac/planning.rb +0 -237
  50. data/lib/user_registry.rb +0 -159
  51. data/monitor/menubar.rb +0 -295
  52. data/monitor/setup-waybar-deploy-envs.rb +0 -121
  53. data/monitor/setup-waybar-deployments.rb +0 -96
  54. data/monitor/setup-waybar-module.rb +0 -113
  55. data/monitor/setup-xbar-plugin.rb +0 -35
  56. data/monitor/view-logs.rb +0 -119
  57. data/monitor/waybar-config-updater.rb +0 -56
  58. data/monitor/waybar-deployments.rb +0 -239
  59. data/monitor/waybar.rb +0 -146
  60. data/monitor/xbar.3s.rb +0 -179
  61. data/templates/fizzy.json.example +0 -24
  62. /data/monitor/{open-action.sh → xbar/open_action.sh} +0 -0
  63. /data/monitor/{view-logs-macos.rb → xbar/view_logs.rb} +0 -0
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # One-time setup: replaces the single brainiac-deployments module
5
- # with per-environment modules so each dot gets its own border/click.
6
-
7
- require "json"
8
- require "fileutils"
9
-
10
- WAYBAR_CONFIG = File.expand_path("~/.config/waybar/config.jsonc")
11
- DEPLOY_SCRIPT = File.expand_path("~/.brainiac/bin/waybar-deploy-env")
12
- DEPLOYMENTS_CONFIG = File.expand_path("~/.brainiac/deployments.json")
13
- WAYBAR_STYLE = File.expand_path("~/.config/waybar/style.css")
14
-
15
- # Create wrapper script that resolves from server.root
16
- wrapper_dir = File.expand_path("~/.brainiac/bin")
17
- FileUtils.mkdir_p(wrapper_dir)
18
- File.write(DEPLOY_SCRIPT, <<~SCRIPT)
19
- #!/usr/bin/env ruby
20
- root_file = File.expand_path("~/.brainiac/server.root")
21
- if File.exist?(root_file)
22
- server_root = File.read(root_file).strip
23
- script = File.join(server_root, "monitor", "waybar-deploy-env.rb")
24
- if File.exist?(script)
25
- ARGV.unshift if ARGV.empty?
26
- load script
27
- exit
28
- end
29
- end
30
- require "json"
31
- puts({ text: "", tooltip: "Brainiac server root not found", class: "error" }.to_json)
32
- SCRIPT
33
- File.chmod(0o755, DEPLOY_SCRIPT)
34
-
35
- def load_config
36
- content = File.read(WAYBAR_CONFIG)
37
- json_content = content.lines.reject { |line| line.strip.start_with?("//") }.join
38
- JSON.parse(json_content)
39
- end
40
-
41
- def save_config(config)
42
- File.write(WAYBAR_CONFIG, JSON.pretty_generate(config))
43
- end
44
-
45
- deployments = JSON.parse(File.read(DEPLOYMENTS_CONFIG))
46
- envs = deployments["environments"].keys
47
-
48
- config = load_config
49
-
50
- # Remove old single deployments module from all bar positions
51
- %w[modules-left modules-center modules-right].each do |pos|
52
- next unless config[pos]
53
-
54
- config[pos].reject! { |m| m.to_s.include?("brainiac-deploy") }
55
- end
56
- config.delete("custom/brainiac-deployments")
57
-
58
- # Remove any existing per-env modules
59
- config.each_key do |key|
60
- config.delete(key) if key.start_with?("custom/brainiac-deploy-")
61
- end
62
-
63
- # Insert per-env modules into modules-center, before custom/brainiac
64
- center = config["modules-center"] || []
65
- zc_idx = center.index("custom/brainiac") || center.length
66
- envs.each_with_index do |env, i|
67
- mod_name = "custom/brainiac-deploy-#{env}"
68
- center.insert(zc_idx + i, mod_name) unless center.include?(mod_name)
69
- end
70
- config["modules-center"] = center
71
-
72
- # Add module configs for each env
73
- envs.each do |env|
74
- mod_name = "custom/brainiac-deploy-#{env}"
75
- config[mod_name] = {
76
- "exec" => "#{DEPLOY_SCRIPT} #{env}",
77
- "return-type" => "json",
78
- "interval" => 30,
79
- "format" => "{}",
80
- "tooltip" => true,
81
- "escape" => false,
82
- "on-click" => "#{DEPLOY_SCRIPT} #{env} --click",
83
- "on-click-right" => "#{DEPLOY_SCRIPT} #{env} --deploy"
84
- }
85
- end
86
-
87
- save_config(config)
88
- puts "✓ Added per-environment deploy modules: #{envs.map { |e| "custom/brainiac-deploy-#{e}" }.join(", ")}"
89
-
90
- # Update CSS — remove old single-module styles, add per-env styles
91
- style = File.read(WAYBAR_STYLE)
92
-
93
- # Remove old block
94
- style.gsub!(%r{/\* Brainiac deployment environment dots \*/.*?(?=\n\n|\n/\*|\z)}m, "")
95
- style.gsub!(/\n*#custom-brainiac-deployments[^{]*\{[^}]*\}\n*/m, "")
96
-
97
- # Add new per-env styles
98
- unless style.include?("#custom-brainiac-deploy-")
99
- css = <<~CSS
100
-
101
- /* Brainiac per-environment deploy dots */
102
- [id^="custom-brainiac-deploy-"] {
103
- font-size: 28px;
104
- padding: 0 6px;
105
- border-radius: 8px;
106
- border: 2px solid transparent;
107
- }
108
-
109
- [id^="custom-brainiac-deploy-"].deploy-recent {
110
- border: 2px solid #4488ff;
111
- }
112
-
113
- [id^="custom-brainiac-deploy-"].deploy-failed {
114
- border: 2px solid #ff4444;
115
- }
116
- CSS
117
- File.write(WAYBAR_STYLE, "#{style.strip}\n#{css}")
118
- puts "✓ Updated waybar CSS with per-environment border styles"
119
- end
120
-
121
- puts "✓ Restart waybar to apply: omarchy restart waybar"
@@ -1,96 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # One-time setup: adds Brainiac deployments module to waybar config
5
- # and repositions the agent session module with more breathing room.
6
-
7
- require "json"
8
-
9
- WAYBAR_CONFIG = File.expand_path("~/.config/waybar/config.jsonc")
10
- DEPLOY_SCRIPT = File.expand_path("~/Code/brainiac/monitor/waybar-deployments.rb")
11
- WAYBAR_STYLE = File.expand_path("~/.config/waybar/style.css")
12
-
13
- def load_config
14
- content = File.read(WAYBAR_CONFIG)
15
- json_content = content.lines.reject { |line| line.strip.start_with?("//") }.join
16
- JSON.parse(json_content)
17
- end
18
-
19
- def save_config(config)
20
- File.write(WAYBAR_CONFIG, JSON.pretty_generate(config))
21
- end
22
-
23
- config = load_config
24
-
25
- # Remove any existing deployment module
26
- config["modules-center"]&.reject! { |m| m.to_s.include?("brainiac-deploy") }
27
- config["modules-right"]&.reject! { |m| m.to_s.include?("brainiac-deploy") }
28
- config.delete("custom/brainiac-deployments")
29
-
30
- # Move agent session module from modules-right to modules-center (after indicators)
31
- if config["modules-right"]&.delete("custom/brainiac")
32
- config["modules-center"] ||= []
33
- config["modules-center"] << "custom/brainiac" unless config["modules-center"].include?("custom/brainiac")
34
- end
35
-
36
- # Add deployments module right before agent sessions in modules-center
37
- center = config["modules-center"] || []
38
- zc_idx = center.index("custom/brainiac")
39
- if zc_idx
40
- center.insert(zc_idx, "custom/brainiac-deployments") unless center.include?("custom/brainiac-deployments")
41
- else
42
- center << "custom/brainiac-deployments" unless center.include?("custom/brainiac-deployments")
43
- end
44
-
45
- # Add module config
46
- config["custom/brainiac-deployments"] = {
47
- "exec" => DEPLOY_SCRIPT,
48
- "return-type" => "json",
49
- "interval" => 30,
50
- "format" => "{}",
51
- "tooltip" => true,
52
- "format-alt" => "{}",
53
- "escape" => false,
54
- "on-click" => "#{DEPLOY_SCRIPT} --click",
55
- "on-click-right" => "#{DEPLOY_SCRIPT} --deploy"
56
- }
57
-
58
- save_config(config)
59
-
60
- # Add CSS for the deployments module
61
- style = File.read(WAYBAR_STYLE)
62
- unless style.include?("#custom-brainiac-deployments")
63
- css = <<~CSS
64
-
65
- /* Brainiac deployment environment dots */
66
- #custom-brainiac-deployments {
67
- margin-left: 100px;
68
- margin-right: 40px;
69
- font-size: 14px;
70
- }
71
- CSS
72
- File.write(WAYBAR_STYLE, style + css)
73
- puts "✓ Added deployment styles to waybar CSS"
74
- end
75
-
76
- # Add padding-right to agent sessions module
77
- unless style.include?("padding-right") && style.include?("#custom-brainiac")
78
- updated_style = File.read(WAYBAR_STYLE)
79
- if updated_style.include?("#custom-brainiac {")
80
- updated_style.sub!(/(#custom-brainiac\s*\{[^}]*)(\})/) do
81
- block = Regexp.last_match(1)
82
- close = Regexp.last_match(2)
83
- if block.include?("padding-right")
84
- "#{block}#{close}"
85
- else
86
- "#{block}\n padding-right: 100px;\n#{close}"
87
- end
88
- end
89
- File.write(WAYBAR_STYLE, updated_style)
90
- puts "✓ Added padding-right to agent session module"
91
- end
92
- end
93
-
94
- puts "✓ Deployments module added to waybar config"
95
- puts " Positioned: [deploy-dots] [agent-sessions] in center bar"
96
- puts " Restart waybar to apply: omarchy restart waybar"
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # One-time setup script to add Brainiac module to waybar config
5
- # Run this once, then the module will update dynamically without config rewrites
6
-
7
- require "json"
8
- require "fileutils"
9
-
10
- WAYBAR_CONFIG = File.expand_path("~/.config/waybar/config.jsonc")
11
- WAYBAR_SCRIPT = File.expand_path("~/.brainiac/bin/waybar-status")
12
-
13
- # Create a wrapper script that resolves the running server's waybar.rb dynamically
14
- wrapper_dir = File.expand_path("~/.brainiac/bin")
15
- FileUtils.mkdir_p(wrapper_dir)
16
- wrapper_path = File.join(wrapper_dir, "waybar-status")
17
- File.write(wrapper_path, <<~SCRIPT)
18
- #!/usr/bin/env ruby
19
- # Resolves the running Brainiac server's waybar module dynamically.
20
- # This allows worktrees / branches to work without reconfiguring waybar.
21
-
22
- root_file = File.expand_path("~/.brainiac/server.root")
23
- if File.exist?(root_file)
24
- server_root = File.read(root_file).strip
25
- waybar_script = File.join(server_root, "monitor", "waybar.rb")
26
- if File.exist?(waybar_script)
27
- load waybar_script
28
- exit
29
- end
30
- end
31
-
32
- # Fallback: no server root known, try the API directly
33
- require "json"
34
- require "net/http"
35
-
36
- begin
37
- uri = URI("http://localhost:4567/api/status")
38
- response = Net::HTTP.get_response(uri)
39
- if response.is_a?(Net::HTTPSuccess)
40
- data = JSON.parse(response.body)
41
- sessions = data["sessions"] || []
42
- if sessions.empty?
43
- puts({ text: "💤", tooltip: "No active agent sessions", class: "idle" }.to_json)
44
- else
45
- puts({ text: "🟢 \#{sessions.size}", tooltip: sessions.map { |s| s["agent"] }.join(", "), class: "working" }.to_json)
46
- end
47
- else
48
- puts({ text: "⚠️", tooltip: "Brainiac Error: HTTP \#{response.code}", class: "error" }.to_json)
49
- end
50
- rescue StandardError => e
51
- puts({ text: "⚠️", tooltip: "Brainiac Error: \#{e.message}", class: "error" }.to_json)
52
- end
53
- SCRIPT
54
- File.chmod(0o755, wrapper_path)
55
-
56
- def load_config
57
- content = File.read(WAYBAR_CONFIG)
58
- # Strip comments for JSON parsing
59
- json_content = content.lines.reject { |line| line.strip.start_with?("//") }.join
60
- JSON.parse(json_content)
61
- end
62
-
63
- def save_config(config)
64
- File.write(WAYBAR_CONFIG, JSON.pretty_generate(config))
65
- end
66
-
67
- # Load current config
68
- config = load_config
69
-
70
- # Remove old brainiac modules if they exist (from all module arrays)
71
- %w[modules-left modules-center modules-right].each do |section|
72
- next unless config[section].is_a?(Array)
73
-
74
- config[section].reject! { |m| ["custom/brainiac", "group/brainiac-agents"].include?(m.to_s) }
75
- end
76
- config.each_key do |key|
77
- config.delete(key) if ["custom/brainiac", "group/brainiac-agents"].include?(key.to_s)
78
- end
79
-
80
- # Add single dynamic module at the end of modules-center (after deploy envs)
81
- config["modules-center"] ||= []
82
- config["modules-center"].push("custom/brainiac")
83
-
84
- # Add module config
85
- config["custom/brainiac"] = {
86
- "exec" => WAYBAR_SCRIPT,
87
- "return-type" => "json",
88
- "interval" => 3,
89
- "format" => "{}",
90
- "tooltip" => true,
91
- "on-click" => File.expand_path("~/.brainiac/bin/waybar-logs").to_s
92
- }
93
-
94
- # Create on-click wrapper too
95
- logs_wrapper = File.expand_path("~/.brainiac/bin/waybar-logs")
96
- File.write(logs_wrapper, <<~SCRIPT)
97
- #!/usr/bin/env ruby
98
- root_file = File.expand_path("~/.brainiac/server.root")
99
- if File.exist?(root_file)
100
- server_root = File.read(root_file).strip
101
- script = File.join(server_root, "monitor", "view-logs-rofi.rb")
102
- exec("ruby", script) if File.exist?(script)
103
- end
104
- warn "Brainiac server root not found"
105
- SCRIPT
106
- File.chmod(0o755, logs_wrapper)
107
-
108
- # Save updated config
109
- save_config(config)
110
-
111
- puts "✓ Brainiac module added to waybar config"
112
- puts " Module will update every 3 seconds without config rewrites"
113
- puts " Restart waybar to apply: omarchy restart waybar"
@@ -1,35 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # One-time setup: symlinks the Brainiac xbar plugin into xbar's plugin directory
5
- # Run this once on macOS after installing xbar
6
-
7
- require "fileutils"
8
-
9
- XBAR_PLUGIN_DIR = File.expand_path("~/Library/Application Support/xbar/plugins")
10
- PLUGIN_SOURCE = File.expand_path("xbar.3s.rb", __dir__)
11
- PLUGIN_DEST = File.join(XBAR_PLUGIN_DIR, "brainiac.3s.rb")
12
-
13
- unless RUBY_PLATFORM.match?(/darwin/i)
14
- puts "⚠ This script is for macOS only (xbar doesn't run on Linux)"
15
- exit 1
16
- end
17
-
18
- unless File.directory?(XBAR_PLUGIN_DIR)
19
- puts "⚠ xbar plugin directory not found: #{XBAR_PLUGIN_DIR}"
20
- puts " Install xbar first: https://xbarapp.com"
21
- exit 1
22
- end
23
-
24
- if File.exist?(PLUGIN_DEST)
25
- puts "Removing existing plugin at #{PLUGIN_DEST}"
26
- File.delete(PLUGIN_DEST)
27
- end
28
-
29
- File.symlink(PLUGIN_SOURCE, PLUGIN_DEST)
30
- File.chmod(0o755, PLUGIN_SOURCE)
31
-
32
- puts "✓ Brainiac xbar plugin installed"
33
- puts " #{PLUGIN_SOURCE} → #{PLUGIN_DEST}"
34
- puts " Refresh interval: 3 seconds"
35
- puts " Restart xbar to activate"
data/monitor/view-logs.rb DELETED
@@ -1,119 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Brainiac Log Viewer
5
- # Shows a rofi menu to select which agent log to tail
6
-
7
- require "json"
8
- require "net/http"
9
- require "socket"
10
-
11
- SOCKET_PATH = "/tmp/brainiac-monitor.sock"
12
- API_URL = "http://localhost:4567/api/status"
13
- CONFIG_PATH = File.expand_path("~/.brainiac/waybar.json")
14
-
15
- # Load agent configuration from JSON
16
- def load_agent_config
17
- config = JSON.parse(File.read(CONFIG_PATH))
18
- agents = {}
19
- config["agents"].each do |agent|
20
- agents[agent["name"].downcase] = agent["emoji"]
21
- end
22
- default_emoji = config["default_emoji"] || "❓"
23
- [agents, default_emoji]
24
- rescue StandardError => e
25
- warn "Failed to load waybar.json: #{e.message}"
26
- [{}, "❓"]
27
- end
28
-
29
- AGENTS, DEFAULT_EMOJI = load_agent_config
30
-
31
- def fetch_state_from_socket
32
- socket = UNIXSocket.new(SOCKET_PATH)
33
- data = socket.read
34
- socket.close
35
- JSON.parse(data)
36
- end
37
-
38
- def fetch_state_from_api
39
- uri = URI(API_URL)
40
- response = Net::HTTP.get_response(uri)
41
- return nil unless response.is_a?(Net::HTTPSuccess)
42
-
43
- JSON.parse(response.body)
44
- end
45
-
46
- def fetch_state
47
- # Prefer socket (daemon mode) — faster, no HTTP overhead
48
- fetch_state_from_socket
49
- rescue Errno::ENOENT, Errno::ECONNREFUSED
50
- # Daemon not running — fall back to direct API call
51
- data = fetch_state_from_api
52
- unless data
53
- puts "Error: Server not reachable"
54
- exit 1
55
- end
56
- data
57
- rescue StandardError => e
58
- puts "Error: #{e.message}"
59
- exit 1
60
- end
61
-
62
- def format_elapsed(seconds)
63
- return "#{seconds}s" if seconds < 60
64
-
65
- minutes = seconds / 60
66
- return "#{minutes}m" if minutes < 60
67
-
68
- hours = minutes / 60
69
- "#{hours}h"
70
- end
71
-
72
- state = fetch_state
73
- sessions = state["sessions"] || []
74
-
75
- if sessions.empty?
76
- system("notify-send", "Brainiac", "No active agent sessions")
77
- exit 0
78
- end
79
-
80
- # If only one session, open it directly
81
- if sessions.size == 1
82
- log_file = sessions[0]["log_file"]
83
- exec("alacritty", "-e", "tail", "-f", log_file) if log_file
84
- exit 0
85
- end
86
-
87
- # Multiple sessions: use fzf if available, otherwise just open the first one
88
- if system("which fzf > /dev/null 2>&1")
89
- # Build fzf menu
90
- options = sessions.map do |s|
91
- agent = s["agent"]
92
- elapsed = format_elapsed(s["elapsed_seconds"])
93
-
94
- card_key = s["card_key"]
95
- context = if card_key.start_with?("discord-")
96
- "Discord chat"
97
- elsif card_key.start_with?("card-")
98
- card_key.split("-")[1]
99
- else
100
- card_key
101
- end
102
-
103
- emoji = AGENTS[agent.downcase] || DEFAULT_EMOJI
104
-
105
- "#{emoji} #{agent}: #{context} (#{elapsed})|#{s["log_file"]}"
106
- end
107
-
108
- menu_text = options.join("\n")
109
- selected = `echo "#{menu_text}" | fzf --prompt="Agent Logs: "`.strip
110
-
111
- unless selected.empty?
112
- log_file = selected.split("|").last
113
- exec("alacritty", "-e", "tail", "-f", log_file)
114
- end
115
- else
116
- # No menu system, just open the first log
117
- log_file = sessions[0]["log_file"]
118
- exec("alacritty", "-e", "tail", "-f", log_file) if log_file
119
- end
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Brainiac Waybar Config Updater
5
- # Dynamically updates waybar config with per-agent modules
6
-
7
- require "json"
8
-
9
- WAYBAR_CONFIG = File.expand_path("~/.config/waybar/config.jsonc")
10
- WAYBAR_SCRIPT = File.expand_path("~/Code/brainiac/monitor/waybar.rb")
11
-
12
- def load_config
13
- content = File.read(WAYBAR_CONFIG)
14
- # Strip comments for JSON parsing
15
- json_content = content.lines.reject { |line| line.strip.start_with?("//") }.join
16
- JSON.parse(json_content)
17
- end
18
-
19
- def save_config(config)
20
- File.write(WAYBAR_CONFIG, JSON.pretty_generate(config))
21
- end
22
-
23
- def brainiac_modules
24
- output = `#{WAYBAR_SCRIPT} --config`
25
- JSON.parse(output)
26
- end
27
-
28
- # Load current config
29
- config = load_config
30
-
31
- # Get dynamic Brainiac modules
32
- brainiac_data = brainiac_modules
33
- modules = brainiac_data["modules"]
34
- module_configs = brainiac_data["config"]
35
-
36
- # Remove old brainiac modules and groups from modules-right
37
- config["modules-right"].reject! { |m| m.to_s.start_with?("custom/brainiac") || m.to_s == "group/brainiac-agents" }
38
-
39
- # Insert new modules at the beginning of modules-right
40
- config["modules-right"] = modules + config["modules-right"]
41
-
42
- # Remove old brainiac module configs and groups
43
- config.each_key do |key|
44
- config.delete(key) if key.to_s.start_with?("custom/brainiac") || key.to_s == "group/brainiac-agents"
45
- end
46
-
47
- # Add new module configs
48
- module_configs.each do |name, cfg|
49
- config[name] = cfg
50
- end
51
-
52
- # Save updated config
53
- save_config(config)
54
-
55
- # Reload waybar
56
- system("killall", "-SIGUSR2", "waybar")