brainiac 0.0.1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +2 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +126 -0
- data/README.md +1166 -0
- data/Rakefile +12 -0
- data/bin/brainiac +1521 -0
- data/brainiac.gemspec +30 -0
- data/certs/stowzilla.pem +26 -0
- data/docs/waybar-config.md +96 -0
- data/lib/brainiac/agents.rb +203 -0
- data/lib/brainiac/brain.rb +197 -0
- data/lib/brainiac/card_index.rb +389 -0
- data/lib/brainiac/config.rb +263 -0
- data/lib/brainiac/cron.rb +629 -0
- data/lib/brainiac/deployments.rb +258 -0
- data/lib/brainiac/handlers/discord.rb +1643 -0
- data/lib/brainiac/handlers/fizzy.rb +1249 -0
- data/lib/brainiac/handlers/github.rb +598 -0
- data/lib/brainiac/handlers/zoho.rb +487 -0
- data/lib/brainiac/helpers.rb +760 -0
- data/lib/brainiac/planning.rb +237 -0
- data/lib/brainiac/prompts.rb +620 -0
- data/lib/brainiac/sessions.rb +282 -0
- data/lib/brainiac/skills.rb +276 -0
- data/lib/brainiac/users.rb +76 -0
- data/lib/brainiac/version.rb +6 -0
- data/lib/brainiac/zoho_mail_api.rb +109 -0
- data/lib/brainiac.rb +10 -0
- data/lib/user_registry.rb +159 -0
- data/monitor/daemon.rb +99 -0
- data/monitor/deploy-env-macos.rb +131 -0
- data/monitor/menubar.rb +295 -0
- data/monitor/open-action.sh +15 -0
- data/monitor/setup-menubar.rb +78 -0
- data/monitor/setup-waybar-deploy-envs.rb +121 -0
- data/monitor/setup-waybar-deployments.rb +96 -0
- data/monitor/setup-waybar-module.rb +113 -0
- data/monitor/setup-xbar-plugin.rb +35 -0
- data/monitor/view-logs-macos.rb +210 -0
- data/monitor/view-logs-rofi.rb +194 -0
- data/monitor/view-logs.rb +119 -0
- data/monitor/waybar-config-updater.rb +56 -0
- data/monitor/waybar-deploy-env.rb +206 -0
- data/monitor/waybar-deployments.rb +239 -0
- data/monitor/waybar.rb +146 -0
- data/monitor/xbar.3s.rb +179 -0
- data/receiver.rb +956 -0
- data/templates/agents.json.example +10 -0
- data/templates/discord.json.example +17 -0
- data/templates/fizzy.json.example +24 -0
- data/templates/github.json.example +4 -0
- data/templates/testflight.json.example +8 -0
- data/templates/users.json.example +121 -0
- data/templates/zoho.json.example +27 -0
- data/views/dashboard.erb +437 -0
- data.tar.gz.sig +0 -0
- metadata +235 -0
- metadata.gz.sig +0 -0
data/monitor/xbar.3s.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Brainiac xbar Plugin (macOS menu bar)
|
|
5
|
+
# Reads from monitor daemon socket and outputs xbar-formatted text
|
|
6
|
+
# Filename encodes refresh interval: xbar.3s.rb = every 3 seconds
|
|
7
|
+
#
|
|
8
|
+
# <xbar.title>Brainiac Agent Monitor</xbar.title>
|
|
9
|
+
# <xbar.version>v1.0</xbar.version>
|
|
10
|
+
# <xbar.author>Brainiac</xbar.author>
|
|
11
|
+
# <xbar.desc>Shows active AI agent sessions in the macOS menu bar</xbar.desc>
|
|
12
|
+
# <xbar.dependencies>ruby</xbar.dependencies>
|
|
13
|
+
|
|
14
|
+
require "json"
|
|
15
|
+
require "shellwords"
|
|
16
|
+
require "socket"
|
|
17
|
+
|
|
18
|
+
SOCKET_PATH = "/tmp/brainiac-monitor.sock"
|
|
19
|
+
CONFIG_PATH = File.expand_path("~/.brainiac/waybar.json")
|
|
20
|
+
|
|
21
|
+
def load_agent_config
|
|
22
|
+
config = JSON.parse(File.read(CONFIG_PATH))
|
|
23
|
+
agents = {}
|
|
24
|
+
config["agents"].each do |agent|
|
|
25
|
+
agents[agent["name"].downcase] = { emoji: agent["emoji"], color: agent["color"] }
|
|
26
|
+
end
|
|
27
|
+
[agents, config["default_emoji"] || "❓"]
|
|
28
|
+
rescue StandardError
|
|
29
|
+
[{}, "❓"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
AGENTS, DEFAULT_EMOJI = load_agent_config
|
|
33
|
+
|
|
34
|
+
COLOR_MAP = {
|
|
35
|
+
"red" => "#ff5555", "green" => "#50fa7b", "blue" => "#8be9fd",
|
|
36
|
+
"yellow" => "#f1fa8c", "cyan" => "#8be9fd", "magenta" => "#ff79c6",
|
|
37
|
+
"purple" => "#bd93f9", "pink" => "#ff79c6", "white" => "#f8f8f2"
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
def hex_color(name)
|
|
41
|
+
COLOR_MAP[name] || name
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def fetch_state
|
|
45
|
+
socket = UNIXSocket.new(SOCKET_PATH)
|
|
46
|
+
data = socket.read
|
|
47
|
+
socket.close
|
|
48
|
+
JSON.parse(data)
|
|
49
|
+
rescue Errno::ENOENT
|
|
50
|
+
{ "error" => "daemon not running" }
|
|
51
|
+
rescue StandardError => e
|
|
52
|
+
{ "error" => e.message }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def format_elapsed(seconds)
|
|
56
|
+
return "#{seconds}s" if seconds < 60
|
|
57
|
+
|
|
58
|
+
minutes = seconds / 60
|
|
59
|
+
return "#{minutes}m" if minutes < 60
|
|
60
|
+
|
|
61
|
+
"#{minutes / 60}h"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def format_context(card_key)
|
|
65
|
+
return "" unless card_key
|
|
66
|
+
|
|
67
|
+
if card_key.start_with?("discord-")
|
|
68
|
+
"Discord"
|
|
69
|
+
elsif card_key.start_with?("card-")
|
|
70
|
+
"##{card_key.split("-")[1]}"
|
|
71
|
+
else
|
|
72
|
+
card_key
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def time_ago(iso_string)
|
|
77
|
+
return nil unless iso_string
|
|
78
|
+
|
|
79
|
+
seconds = (Time.now - Time.parse(iso_string)).to_i
|
|
80
|
+
"#{format_elapsed(seconds)} ago"
|
|
81
|
+
rescue StandardError
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
ANSI_REGEX = /\e\[[0-9;]*[a-zA-Z]|\e\[\?[0-9;]*[a-zA-Z]/
|
|
86
|
+
LOG_PREVIEW_LINES = 15
|
|
87
|
+
LOG_LINE_MAX = 80
|
|
88
|
+
LOG_FONT = "SFMono-Regular"
|
|
89
|
+
LOG_SIZE = 12
|
|
90
|
+
|
|
91
|
+
def tail_log(log_file, lines: LOG_PREVIEW_LINES)
|
|
92
|
+
return [] unless log_file && File.exist?(log_file)
|
|
93
|
+
|
|
94
|
+
raw = `tail -n 50 #{log_file.shellescape} 2>/dev/null`
|
|
95
|
+
raw.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
|
96
|
+
.lines
|
|
97
|
+
.map { |l| l.gsub(ANSI_REGEX, "").gsub(/[^[:print:]\t]/, "").strip }
|
|
98
|
+
.reject(&:empty?)
|
|
99
|
+
.last(lines)
|
|
100
|
+
rescue StandardError
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def format_log_line(text)
|
|
105
|
+
text.length > LOG_LINE_MAX ? "#{text[0, LOG_LINE_MAX]}…" : text
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
state = fetch_state
|
|
109
|
+
|
|
110
|
+
if state["error"]
|
|
111
|
+
puts "⚠️ | color=red"
|
|
112
|
+
puts "---"
|
|
113
|
+
puts "Brainiac: #{state["error"]} | color=red"
|
|
114
|
+
exit
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
sessions = state["sessions"] || []
|
|
118
|
+
recent = state["recent"] || []
|
|
119
|
+
view_logs_script = File.join(__dir__, "view-logs-macos.rb")
|
|
120
|
+
|
|
121
|
+
# Menu bar title
|
|
122
|
+
if sessions.any?
|
|
123
|
+
puts sessions.map { |s| AGENTS.dig(s["agent"]&.downcase, :emoji) || DEFAULT_EMOJI }.join(" ")
|
|
124
|
+
else
|
|
125
|
+
puts "💤"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
puts "---"
|
|
129
|
+
|
|
130
|
+
# Active sessions
|
|
131
|
+
if sessions.any?
|
|
132
|
+
puts "Active | size=12"
|
|
133
|
+
sessions.each do |s|
|
|
134
|
+
agent = s["agent"] || "Unknown"
|
|
135
|
+
info = AGENTS[agent.downcase] || {}
|
|
136
|
+
emoji = info[:emoji] || DEFAULT_EMOJI
|
|
137
|
+
color = info[:color] ? " | color=#{hex_color(info[:color])}" : ""
|
|
138
|
+
elapsed = format_elapsed(s["elapsed_seconds"] || 0)
|
|
139
|
+
context = format_context(s["card_key"])
|
|
140
|
+
|
|
141
|
+
puts "#{emoji} #{agent}: #{context} (#{elapsed})#{color}"
|
|
142
|
+
|
|
143
|
+
log_lines = tail_log(s["log_file"])
|
|
144
|
+
if log_lines.any?
|
|
145
|
+
log_lines.each do |line|
|
|
146
|
+
puts "-- #{format_log_line(line)} | font=#{LOG_FONT} size=#{LOG_SIZE}"
|
|
147
|
+
end
|
|
148
|
+
puts "-- ---"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
puts "-- Open Full Log | shell=#{view_logs_script} param1=#{s["log_file"]} terminal=false refresh=false" if s["log_file"]
|
|
152
|
+
end
|
|
153
|
+
else
|
|
154
|
+
puts "No active sessions | size=12"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Recent completed sessions
|
|
158
|
+
if recent.any?
|
|
159
|
+
puts "---"
|
|
160
|
+
puts "Recent | size=12"
|
|
161
|
+
recent.each do |s|
|
|
162
|
+
agent = s["agent"] || "Unknown"
|
|
163
|
+
emoji = AGENTS.dig(agent.downcase, :emoji) || DEFAULT_EMOJI
|
|
164
|
+
context = format_context(s["card_key"])
|
|
165
|
+
ago = time_ago(s["finished_at"]) || "?"
|
|
166
|
+
|
|
167
|
+
puts "#{emoji} #{agent}: #{context} — #{ago}"
|
|
168
|
+
|
|
169
|
+
log_lines = tail_log(s["log_file"])
|
|
170
|
+
if log_lines.any?
|
|
171
|
+
log_lines.each do |line|
|
|
172
|
+
puts "-- #{format_log_line(line)} | font=#{LOG_FONT} size=#{LOG_SIZE}"
|
|
173
|
+
end
|
|
174
|
+
puts "-- ---"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
puts "-- Open Full Log | shell=#{view_logs_script} param1=#{s["log_file"]} terminal=false refresh=false" if s["log_file"]
|
|
178
|
+
end
|
|
179
|
+
end
|