brainiac 0.0.6 → 0.0.7

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/README.md +136 -6
  4. data/bin/brainiac +382 -11
  5. data/bin/brainiac-completion.bash +1 -1
  6. data/lib/brainiac/agents.rb +15 -38
  7. data/lib/brainiac/config.rb +40 -11
  8. data/lib/brainiac/handlers/discord/api.rb +196 -0
  9. data/lib/brainiac/handlers/discord/config.rb +134 -0
  10. data/lib/brainiac/handlers/discord/delivery.rb +196 -0
  11. data/lib/brainiac/handlers/discord/gateway.rb +212 -0
  12. data/lib/brainiac/handlers/discord/message.rb +933 -0
  13. data/lib/brainiac/handlers/discord/reactions.rb +215 -0
  14. data/lib/brainiac/handlers/discord.rb +14 -1892
  15. data/lib/brainiac/handlers/fizzy/assignment.rb +125 -0
  16. data/lib/brainiac/handlers/fizzy/comments.rb +730 -0
  17. data/lib/brainiac/handlers/fizzy/dedup.rb +74 -0
  18. data/lib/brainiac/handlers/fizzy/deploy.rb +152 -0
  19. data/lib/brainiac/{deployments.rb → handlers/fizzy/deployments.rb} +4 -2
  20. data/lib/brainiac/handlers/fizzy.rb +12 -1290
  21. data/lib/brainiac/handlers/github.rb +149 -212
  22. data/lib/brainiac/handlers/shared/git.rb +203 -0
  23. data/lib/brainiac/handlers/shared/inline_tags.rb +89 -0
  24. data/lib/brainiac/handlers/zoho.rb +79 -76
  25. data/lib/brainiac/helpers.rb +2 -121
  26. data/lib/brainiac/planning.rb +2 -2
  27. data/lib/brainiac/plugins.rb +129 -0
  28. data/lib/brainiac/restart.rb +94 -0
  29. data/lib/brainiac/routes/api.rb +427 -0
  30. data/lib/brainiac/version.rb +1 -1
  31. data/lib/brainiac/zoho_mail_api.rb +2 -1
  32. data/lib/brainiac.rb +7 -0
  33. data/monitor/daemon.rb +4 -27
  34. data/monitor/shared.rb +247 -0
  35. data/monitor/{waybar-deploy-env.rb → waybar/deploy_env.rb} +14 -86
  36. data/monitor/waybar/setup.rb +232 -0
  37. data/monitor/waybar/status.rb +51 -0
  38. data/monitor/{view-logs-rofi.rb → waybar/view_logs.rb} +21 -88
  39. data/monitor/{deploy-env-macos.rb → xbar/deploy_env.rb} +3 -2
  40. data/monitor/xbar/plugin.rb +155 -0
  41. data/monitor/{setup-menubar.rb → xbar/setup.rb} +14 -30
  42. data/receiver.rb +91 -450
  43. data/templates/brainiac.json.example +9 -0
  44. data/templates/cli-providers/kiro.json.example +8 -2
  45. data/templates/plugins.json.example +3 -0
  46. metadata +30 -20
  47. data/lib/user_registry.rb +0 -159
  48. data/monitor/menubar.rb +0 -295
  49. data/monitor/setup-waybar-deploy-envs.rb +0 -121
  50. data/monitor/setup-waybar-deployments.rb +0 -96
  51. data/monitor/setup-waybar-module.rb +0 -113
  52. data/monitor/setup-xbar-plugin.rb +0 -35
  53. data/monitor/view-logs.rb +0 -119
  54. data/monitor/waybar-config-updater.rb +0 -56
  55. data/monitor/waybar-deployments.rb +0 -239
  56. data/monitor/waybar.rb +0 -146
  57. data/monitor/xbar.3s.rb +0 -179
  58. /data/lib/brainiac/{card_index.rb → handlers/fizzy/card_index.rb} +0 -0
  59. /data/monitor/{open-action.sh → xbar/open_action.sh} +0 -0
  60. /data/monitor/{view-logs-macos.rb → xbar/view_logs.rb} +0 -0
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Fizzy card assignment handler.
4
+ #
5
+ # When a card is assigned to a local agent, creates a worktree, builds the prompt,
6
+ # and dispatches the agent to begin work.
7
+
8
+ def handle_card_assigned(payload)
9
+ eventable = payload["eventable"] || {}
10
+ assignees = eventable["assignees"] || []
11
+
12
+ local_names = local_agent_names
13
+ assigned_agent = assignees.map { |a| a["name"] }.find { |name| local_names.include?(name) }
14
+
15
+ assignee_names = assignees.map { |a| a["name"] }.join(", ")
16
+ LOG.info "[Fizzy] Card assigned to: [#{assignee_names}], local agents: [#{local_names.join(", ")}]"
17
+
18
+ unless assigned_agent
19
+ LOG.info "[Fizzy] No local agent matched. Assignees: [#{assignee_names}], Local: [#{local_names.join(", ")}]"
20
+ return [200, { status: "ignored", reason: "wrong assignee" }.to_json]
21
+ end
22
+
23
+ unless authorized?(payload)
24
+ creator_name = payload.dig("creator", "name") || "Unknown"
25
+ notify_unauthorized("card_assigned", creator_name, "card ##{eventable["number"]}")
26
+ return [200, { status: "ignored", reason: "unauthorized" }.to_json]
27
+ end
28
+
29
+ card_number = eventable["number"]
30
+ card_internal_id = eventable["id"]
31
+ title = eventable["title"] || "untitled"
32
+ tags = eventable["tags"] || []
33
+
34
+ project_result = identify_project_by_tags(tags)
35
+ unless project_result
36
+ tag_names = tags.map { |t| t.is_a?(Hash) ? t["name"] : t }.join(", ")
37
+ LOG.warn "No project found for card ##{card_number} with tags: #{tag_names}"
38
+ return [200, { status: "ignored", reason: "no matching project" }.to_json]
39
+ end
40
+
41
+ project_key, project_config = project_result
42
+ repo_path = project_config["repo_path"]
43
+ branch = "fizzy-#{card_number}-#{slugify(title)}"
44
+
45
+ card_key = "card-#{card_number}"
46
+ if session_active?(card_key)
47
+ LOG.info "Skipping card ##{card_number} — agent session already active"
48
+ return [200, { status: "ignored", reason: "session already active" }.to_json]
49
+ end
50
+
51
+ LOG.info "Card ##{card_number} assigned to #{assigned_agent} for project '#{project_key}', " \
52
+ "creating worktree: #{branch} (model: #{detect_model(project_config, tags: tags) || "default"})"
53
+
54
+ react_to_assignment(card_number, repo_path, assigned_agent)
55
+ worktree_path = setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, project_key, assigned_agent)
56
+
57
+ dispatch_assigned_card(
58
+ card_number: card_number, card_internal_id: card_internal_id, title: title, tags: tags,
59
+ branch: branch, worktree_path: worktree_path, project_config: project_config, project_key: project_key,
60
+ agent_name: assigned_agent, model: detect_model(project_config, tags: tags),
61
+ effort: detect_effort(project_config, tags: tags), cli_provider_override: detect_cli_provider(tags: tags)
62
+ )
63
+ end
64
+
65
+ def react_to_assignment(card_number, repo_path, agent_name)
66
+ Thread.new do
67
+ run_cmd("fizzy", "reaction", "create", "--card", card_number.to_s,
68
+ "--content", "👍", chdir: repo_path, env: fizzy_env_for(agent_name))
69
+ rescue StandardError => e
70
+ LOG.warn "Could not add reaction to card: #{e.message}"
71
+ end
72
+ end
73
+
74
+ def setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, project_key, agent_name)
75
+ debounced_repo_fetch(repo_path)
76
+ worktree_path = File.join(File.dirname(repo_path), "#{File.basename(repo_path)}--#{branch}")
77
+ worktree_path = create_or_reuse_worktree(repo_path: repo_path, branch: branch, worktree_path: worktree_path)
78
+
79
+ map = load_card_map
80
+ map[card_internal_id] = {
81
+ "number" => card_number, "branch" => branch, "worktree" => worktree_path,
82
+ "project" => project_key, "agent" => agent_name
83
+ }
84
+ save_card_map(map)
85
+ worktree_path
86
+ end
87
+
88
+ def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branch:, worktree_path:,
89
+ project_config:, project_key:, agent_name:, model:, effort:, cli_provider_override:)
90
+ card_context = prefetch_card_context(card_number, repo_path: project_config["repo_path"], agent_name: agent_name)
91
+ planning_info = detect_planning_mode(text: title, tags: tags, card_internal_id: card_internal_id, card_number: card_number)
92
+
93
+ template_vars = {
94
+ "CARD_NUMBER" => card_number, "CARD_TITLE" => title,
95
+ "BRANCH" => branch, "COMMENT_CREATOR" => agent_name
96
+ }
97
+ brain_ctx = build_brain_context(
98
+ agent_name: agent_name, card_title: title,
99
+ card_number: card_number, project_key: project_key, source: :fizzy
100
+ )
101
+
102
+ prompt = if planning_info
103
+ LOG.info "[Planning] Planning mode active for card ##{card_number}"
104
+ template_vars["CARD_ID"] = planning_info[:card_id]
105
+ render_planning_prompt(PROMPT_CARD_ASSIGNED, template_vars,
106
+ brain_context: brain_ctx, card_context: card_context, agent_name: agent_name)
107
+ else
108
+ template_vars["CARD_ID"] = card_number
109
+ render_prompt(PROMPT_CARD_ASSIGNED, template_vars,
110
+ brain_context: brain_ctx, card_context: card_context, agent_name: agent_name)
111
+ end
112
+
113
+ card_key = "card-#{card_number}"
114
+ pid, log_file = run_agent(prompt,
115
+ project_config: project_config, chdir: worktree_path,
116
+ log_name: "assigned-#{card_number}", model: model, effort: effort,
117
+ agent_name: agent_name, card_number: card_number, source: :fizzy,
118
+ source_context: { card_number: card_number },
119
+ cli_provider: cli_provider_override)
120
+ register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: agent_name)
121
+
122
+ Thread.new { move_card_to_column(card_number, "right_now", project_config: project_config, agent_name: agent_name) }
123
+
124
+ [200, { status: "processed", card: card_number, branch: branch, project: project_key, agent: agent_name }.to_json]
125
+ end