brainiac 0.0.7 → 0.0.9
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 +4 -4
- data/Gemfile.lock +2 -2
- data/bin/brainiac +132 -75
- data/lib/brainiac/agents.rb +12 -36
- data/lib/brainiac/brain.rb +6 -6
- data/lib/brainiac/config.rb +2 -67
- data/lib/brainiac/handlers/discord/config.rb +1 -1
- data/lib/brainiac/handlers/discord/delivery.rb +1 -1
- data/lib/brainiac/handlers/discord/gateway.rb +1 -1
- data/lib/brainiac/handlers/discord/message.rb +13 -25
- data/lib/brainiac/handlers/discord/reactions.rb +1 -1
- data/lib/brainiac/handlers/github.rb +49 -169
- data/lib/brainiac/handlers/shared/git.rb +4 -17
- data/lib/brainiac/handlers/shared/inline_tags.rb +1 -1
- data/lib/brainiac/handlers/zoho.rb +29 -82
- data/lib/brainiac/helpers.rb +43 -336
- data/lib/brainiac/hooks.rb +86 -0
- data/lib/brainiac/plugins.rb +27 -2
- data/lib/brainiac/prompts.rb +34 -172
- data/lib/brainiac/restart.rb +30 -12
- data/lib/brainiac/routes/api.rb +2 -18
- data/lib/brainiac/users.rb +1 -7
- data/lib/brainiac/version.rb +1 -1
- data/lib/brainiac.rb +1 -1
- data/monitor/waybar/deploy_env.rb +3 -3
- data/monitor/xbar/plugin.rb +11 -17
- data/receiver.rb +9 -157
- data/templates/agents.json.example +1 -2
- data/templates/brainiac.json.example +0 -1
- data/templates/users.json.example +0 -3
- metadata +2 -10
- data/lib/brainiac/handlers/fizzy/assignment.rb +0 -125
- data/lib/brainiac/handlers/fizzy/card_index.rb +0 -389
- data/lib/brainiac/handlers/fizzy/comments.rb +0 -730
- data/lib/brainiac/handlers/fizzy/dedup.rb +0 -74
- data/lib/brainiac/handlers/fizzy/deploy.rb +0 -152
- data/lib/brainiac/handlers/fizzy/deployments.rb +0 -260
- data/lib/brainiac/handlers/fizzy.rb +0 -14
- data/lib/brainiac/planning.rb +0 -237
- data/templates/fizzy.json.example +0 -24
data/monitor/xbar/plugin.rb
CHANGED
|
@@ -11,8 +11,9 @@ require_relative "../shared"
|
|
|
11
11
|
SELF_PATH = File.realpath(__FILE__)
|
|
12
12
|
AGENTS = load_agent_config.freeze
|
|
13
13
|
CONFIG = load_monitor_config.freeze
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
# URL patterns for different session types — configured in ~/.brainiac/waybar.json or monitor config
|
|
16
|
+
# Plugins can add their patterns here via the config file.
|
|
16
17
|
|
|
17
18
|
LOG_VIEWER_PATH = File.join(File.dirname(SELF_PATH), "view_logs.rb")
|
|
18
19
|
DEPLOY_SCRIPT_PATH = File.join(File.dirname(SELF_PATH), "deploy_env.rb")
|
|
@@ -30,22 +31,15 @@ def full_log_action(log_file)
|
|
|
30
31
|
" | shell=#{OPEN_SCRIPT} param1=#{log_file.shellescape} terminal=false refresh=false"
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
def prompt_url(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"https://app.fizzy.do/#{FIZZY_ACCOUNT_ID}/cards/#{card_num}" if FIZZY_ACCOUNT_ID && card_num
|
|
39
|
-
elsif card_key.start_with?("discord-") && DISCORD_GUILD_ID
|
|
40
|
-
parts = card_key.split("-")
|
|
41
|
-
channel_id = parts[-2]
|
|
42
|
-
message_id = parts[-1]
|
|
43
|
-
"https://discord.com/channels/#{DISCORD_GUILD_ID}/#{channel_id}/#{message_id}" if channel_id && message_id
|
|
44
|
-
end
|
|
34
|
+
def prompt_url(session)
|
|
35
|
+
# Prefer URL provided directly by the source plugin in session data
|
|
36
|
+
return session["url"] if session.is_a?(Hash) && session["url"]
|
|
37
|
+
|
|
38
|
+
nil
|
|
45
39
|
end
|
|
46
40
|
|
|
47
|
-
def prompt_action(
|
|
48
|
-
url = prompt_url(
|
|
41
|
+
def prompt_action(session)
|
|
42
|
+
url = prompt_url(session)
|
|
49
43
|
url ? " | shell=#{OPEN_SCRIPT} param1=#{url} terminal=false refresh=false" : ""
|
|
50
44
|
end
|
|
51
45
|
|
|
@@ -66,7 +60,7 @@ def render_session_submenu(session)
|
|
|
66
60
|
lines << "-- ---" if session["log_file"]
|
|
67
61
|
lines << "-- Tail Log#{log_action(session["log_file"])}" if session["log_file"]
|
|
68
62
|
lines << "-- View Full Log#{full_log_action(session["log_file"])}" if session["log_file"]
|
|
69
|
-
lines << "-- Open Prompt#{prompt_action(session
|
|
63
|
+
lines << "-- Open Prompt#{prompt_action(session)}" unless prompt_url(session).nil?
|
|
70
64
|
wt = worktree_path(session["log_file"], session["card_key"])
|
|
71
65
|
lines << "-- Open Worktree#{worktree_action(session["log_file"], session["card_key"])}" if wt
|
|
72
66
|
lines
|
data/receiver.rb
CHANGED
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
require "sinatra"
|
|
9
9
|
require "json"
|
|
10
10
|
|
|
11
|
+
# The directory this server is running from (supports worktrees)
|
|
12
|
+
SERVER_ROOT = File.expand_path(__dir__)
|
|
13
|
+
|
|
11
14
|
# Load all modules
|
|
15
|
+
require_relative "lib/brainiac/hooks"
|
|
12
16
|
require_relative "lib/brainiac/config"
|
|
13
17
|
require_relative "lib/brainiac/users"
|
|
14
18
|
require_relative "lib/brainiac/agents"
|
|
@@ -16,7 +20,6 @@ require_relative "lib/brainiac/brain"
|
|
|
16
20
|
require_relative "lib/brainiac/skills"
|
|
17
21
|
require_relative "lib/brainiac/sessions"
|
|
18
22
|
require_relative "lib/brainiac/prompts"
|
|
19
|
-
require_relative "lib/brainiac/planning"
|
|
20
23
|
require_relative "lib/brainiac/helpers"
|
|
21
24
|
require_relative "lib/brainiac/cron"
|
|
22
25
|
require_relative "lib/brainiac/restart"
|
|
@@ -32,13 +35,6 @@ end
|
|
|
32
35
|
|
|
33
36
|
# --- Conditional handler loading (based on ~/.brainiac/brainiac.json) ---
|
|
34
37
|
|
|
35
|
-
if handler_enabled?("fizzy")
|
|
36
|
-
require_relative "lib/brainiac/handlers/fizzy"
|
|
37
|
-
require_relative "lib/brainiac/handlers/fizzy/card_index"
|
|
38
|
-
require_relative "lib/brainiac/handlers/fizzy/deployments"
|
|
39
|
-
LOG.info "[Handlers] Fizzy handler enabled"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
38
|
if handler_enabled?("github")
|
|
43
39
|
require_relative "lib/brainiac/handlers/github"
|
|
44
40
|
LOG.info "[Handlers] GitHub handler enabled"
|
|
@@ -86,7 +82,10 @@ if Dir.exist?(CUSTOM_HANDLERS_DIR)
|
|
|
86
82
|
end
|
|
87
83
|
|
|
88
84
|
# --- Load gem-based plugins (brainiac-*) ---
|
|
89
|
-
load_plugins!(
|
|
85
|
+
load_plugins!(Sinatra::Application)
|
|
86
|
+
|
|
87
|
+
# Emit server_started hook — plugins can run startup tasks (backfill, background jobs, etc.)
|
|
88
|
+
Brainiac.emit(:server_started)
|
|
90
89
|
|
|
91
90
|
# --- Sinatra config ---
|
|
92
91
|
set :host_authorization, { permit_all: true }
|
|
@@ -146,90 +145,6 @@ before "/api/*" do
|
|
|
146
145
|
authenticate_dashboard!
|
|
147
146
|
end
|
|
148
147
|
|
|
149
|
-
# --- Fizzy webhook routes ---
|
|
150
|
-
|
|
151
|
-
post "/fizzy/?:board_key?" do
|
|
152
|
-
content_type :json
|
|
153
|
-
request.body.rewind
|
|
154
|
-
payload_body = request.body.read
|
|
155
|
-
board_key = params["board_key"]
|
|
156
|
-
|
|
157
|
-
verify_signature!(request, payload_body, board_key: board_key)
|
|
158
|
-
|
|
159
|
-
payload = JSON.parse(payload_body)
|
|
160
|
-
|
|
161
|
-
event_id = payload["id"]
|
|
162
|
-
action = payload["action"]
|
|
163
|
-
|
|
164
|
-
LOG.info "[Fizzy] Received event #{event_id}: action=#{action}"
|
|
165
|
-
|
|
166
|
-
if already_processed?(event_id)
|
|
167
|
-
LOG.info "Skipping duplicate event #{event_id}"
|
|
168
|
-
halt 200, { status: "duplicate" }.to_json
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
reload_projects!
|
|
172
|
-
reload_agent_registry!
|
|
173
|
-
reload_github_config!
|
|
174
|
-
|
|
175
|
-
case action
|
|
176
|
-
when "card_assigned"
|
|
177
|
-
status_code, body = handle_card_assigned(payload)
|
|
178
|
-
LOG.info "[Fizzy] #{action} response: #{status_code} - #{body}"
|
|
179
|
-
halt status_code, body
|
|
180
|
-
when "comment_created"
|
|
181
|
-
status_code, body = handle_comment(payload)
|
|
182
|
-
LOG.info "[Fizzy] comment_created response: #{status_code} - #{body}"
|
|
183
|
-
halt status_code, body
|
|
184
|
-
when "card_published", "card_triaged"
|
|
185
|
-
eventable = payload["eventable"] || {}
|
|
186
|
-
card_number = eventable["number"]&.to_s
|
|
187
|
-
|
|
188
|
-
# card_triaged never dispatches agents — only card_assigned and @mentions do that.
|
|
189
|
-
# Guards remain as defense-in-depth for any future column-based routing.
|
|
190
|
-
if action == "card_triaged" && card_number
|
|
191
|
-
if self_move_recent?(card_number)
|
|
192
|
-
LOG.info "[Fizzy] Ignoring card_triaged for ##{card_number} — self-move echo"
|
|
193
|
-
halt 200, { status: "ignored", reason: "self_move" }.to_json
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
if card_merged?(card_number)
|
|
197
|
-
LOG.info "[Fizzy] Ignoring card_triaged for ##{card_number} — card already merged"
|
|
198
|
-
halt 200, { status: "ignored", reason: "card_merged" }.to_json
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
card_key = "card-#{card_number}"
|
|
202
|
-
if recently_completed?(card_key)
|
|
203
|
-
LOG.info "[Fizzy] Ignoring card_triaged for ##{card_number} — recently completed"
|
|
204
|
-
halt 200, { status: "ignored", reason: "recently_completed" }.to_json
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
# Only card_published does duplicate detection — card_triaged skips agent dispatch entirely
|
|
209
|
-
if action == "card_published"
|
|
210
|
-
assignees = eventable["assignees"] || []
|
|
211
|
-
if assignees.any? { |a| local_agent_names.include?(a["name"]) }
|
|
212
|
-
status_code, body = handle_card_assigned(payload)
|
|
213
|
-
LOG.info "[Fizzy] #{action} (with assignee) response: #{status_code} - #{body}"
|
|
214
|
-
halt status_code, body
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
status_code, body = handle_card_published(payload)
|
|
219
|
-
LOG.info "[Fizzy] #{action} response: #{status_code} - #{body}"
|
|
220
|
-
halt status_code, body
|
|
221
|
-
else
|
|
222
|
-
LOG.info "[Fizzy] Ignoring unknown action: #{action}"
|
|
223
|
-
halt 200, { status: "ignored", action: action }.to_json
|
|
224
|
-
end
|
|
225
|
-
rescue JSON::ParserError => e
|
|
226
|
-
LOG.error "Invalid JSON: #{e.message}"
|
|
227
|
-
halt 400, { error: "Invalid JSON" }.to_json
|
|
228
|
-
rescue StandardError => e
|
|
229
|
-
LOG.error "Unhandled error: #{e.message}\n#{e.backtrace.first(5).join("\n")}"
|
|
230
|
-
halt 500, { error: e.message }.to_json
|
|
231
|
-
end
|
|
232
|
-
|
|
233
148
|
post "/github" do
|
|
234
149
|
content_type :json
|
|
235
150
|
request.body.rewind
|
|
@@ -252,7 +167,7 @@ post "/github" do
|
|
|
252
167
|
status_code, body = handle_github_pr_merged(payload)
|
|
253
168
|
halt status_code, body
|
|
254
169
|
elsif action == "opened"
|
|
255
|
-
|
|
170
|
+
track_pr_in_work_items(payload)
|
|
256
171
|
halt 200, { status: "processed", action: "pr_tracked" }.to_json
|
|
257
172
|
elsif action == "synchronize"
|
|
258
173
|
status_code, body = handle_github_pr_synchronized(payload)
|
|
@@ -511,64 +426,6 @@ else
|
|
|
511
426
|
end
|
|
512
427
|
end
|
|
513
428
|
|
|
514
|
-
# --- Deployment environment tracking (requires fizzy handler) ---
|
|
515
|
-
|
|
516
|
-
if defined?(DEPLOYMENTS_CONFIG)
|
|
517
|
-
get "/api/deployments" do
|
|
518
|
-
content_type :json
|
|
519
|
-
reload_deployments_config!
|
|
520
|
-
reload_deployment_state!
|
|
521
|
-
{ deployments: deployment_status }.to_json
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
post "/api/deployments/:env" do
|
|
525
|
-
content_type :json
|
|
526
|
-
env_key = params["env"]
|
|
527
|
-
request.body.rewind
|
|
528
|
-
payload = JSON.parse(request.body.read)
|
|
529
|
-
|
|
530
|
-
result = deploy_to_environment(env_key, worktree_path: payload["worktree"], deployed_by: payload["deployed_by"])
|
|
531
|
-
if result[:error]
|
|
532
|
-
halt 404, result.to_json
|
|
533
|
-
else
|
|
534
|
-
{ status: "deployed", env: env_key, deployment: result }.to_json
|
|
535
|
-
end
|
|
536
|
-
rescue JSON::ParserError
|
|
537
|
-
halt 400, { error: "Invalid JSON" }.to_json
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
delete "/api/deployments/:env" do
|
|
541
|
-
content_type :json
|
|
542
|
-
env_key = params["env"]
|
|
543
|
-
state = load_deployment_state
|
|
544
|
-
if state.key?(env_key)
|
|
545
|
-
state[env_key] = { "status" => "available", "cleared_at" => Time.now.iso8601, "last_card" => state[env_key]["card_number"] }
|
|
546
|
-
save_deployment_state(state)
|
|
547
|
-
DEPLOYMENT_STATE.replace(state)
|
|
548
|
-
LOG.info "[Deploy] Manually cleared #{env_key}"
|
|
549
|
-
{ status: "cleared", env: env_key }.to_json
|
|
550
|
-
else
|
|
551
|
-
halt 404, { error: "Unknown environment: #{env_key}" }.to_json
|
|
552
|
-
end
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
post "/api/deployments/:env/deploying" do
|
|
556
|
-
content_type :json
|
|
557
|
-
env_key = params["env"]
|
|
558
|
-
config = DEPLOYMENTS_CONFIG["environments"] || {}
|
|
559
|
-
halt 404, { error: "Unknown environment: #{env_key}" }.to_json unless config.key?(env_key)
|
|
560
|
-
request.body.rewind
|
|
561
|
-
payload = begin
|
|
562
|
-
JSON.parse(request.body.read)
|
|
563
|
-
rescue StandardError
|
|
564
|
-
{}
|
|
565
|
-
end
|
|
566
|
-
mark_deploying(env_key, worktree_path: payload["worktree"] || "")
|
|
567
|
-
LOG.info "[Deploy] #{env_key} marked deploying via API"
|
|
568
|
-
{ status: "deploying", env: env_key }.to_json
|
|
569
|
-
end
|
|
570
|
-
end
|
|
571
|
-
|
|
572
429
|
LOG.info "[Cron] Starting cron thread..."
|
|
573
430
|
start_cron_thread
|
|
574
431
|
|
|
@@ -583,11 +440,6 @@ CURATOR_THREAD = Thread.new do
|
|
|
583
440
|
end
|
|
584
441
|
end
|
|
585
442
|
|
|
586
|
-
if defined?(CARD_INDEX)
|
|
587
|
-
LOG.info "[CardIndex] Starting background backfill..."
|
|
588
|
-
CARD_INDEX.backfill
|
|
589
|
-
end
|
|
590
|
-
|
|
591
443
|
LOG.info "[Monitor] Starting daemon..."
|
|
592
444
|
daemon_path = File.join(__dir__, "monitor", "daemon.rb")
|
|
593
445
|
daemon_pid_file = "/tmp/brainiac-daemon.pid"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brainiac
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Davis
|
|
@@ -149,19 +149,12 @@ files:
|
|
|
149
149
|
- lib/brainiac/handlers/discord/gateway.rb
|
|
150
150
|
- lib/brainiac/handlers/discord/message.rb
|
|
151
151
|
- lib/brainiac/handlers/discord/reactions.rb
|
|
152
|
-
- lib/brainiac/handlers/fizzy.rb
|
|
153
|
-
- lib/brainiac/handlers/fizzy/assignment.rb
|
|
154
|
-
- lib/brainiac/handlers/fizzy/card_index.rb
|
|
155
|
-
- lib/brainiac/handlers/fizzy/comments.rb
|
|
156
|
-
- lib/brainiac/handlers/fizzy/dedup.rb
|
|
157
|
-
- lib/brainiac/handlers/fizzy/deploy.rb
|
|
158
|
-
- lib/brainiac/handlers/fizzy/deployments.rb
|
|
159
152
|
- lib/brainiac/handlers/github.rb
|
|
160
153
|
- lib/brainiac/handlers/shared/git.rb
|
|
161
154
|
- lib/brainiac/handlers/shared/inline_tags.rb
|
|
162
155
|
- lib/brainiac/handlers/zoho.rb
|
|
163
156
|
- lib/brainiac/helpers.rb
|
|
164
|
-
- lib/brainiac/
|
|
157
|
+
- lib/brainiac/hooks.rb
|
|
165
158
|
- lib/brainiac/plugins.rb
|
|
166
159
|
- lib/brainiac/prompts.rb
|
|
167
160
|
- lib/brainiac/restart.rb
|
|
@@ -188,7 +181,6 @@ files:
|
|
|
188
181
|
- templates/cli-providers/grok.json.example
|
|
189
182
|
- templates/cli-providers/kiro.json.example
|
|
190
183
|
- templates/discord.json.example
|
|
191
|
-
- templates/fizzy.json.example
|
|
192
184
|
- templates/github.json.example
|
|
193
185
|
- templates/plugins.json.example
|
|
194
186
|
- templates/roles/code-reviewer.md.example
|
|
@@ -1,125 +0,0 @@
|
|
|
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
|