brainiac-basecamp 0.0.9 → 0.0.11
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/lib/brainiac/plugins/basecamp/hooks.rb +122 -17
- data/lib/brainiac/plugins/basecamp/version.rb +1 -1
- data/lib/brainiac/plugins/basecamp.rb +10 -16
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d4d21875fecdd7aa33718a8db5fa446800e8a85924490b6716a455b211d79483
|
|
4
|
+
data.tar.gz: 9601289488c260e891a6df6da2b63be3e9965c9c8235d11c4366622d27a24d0b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f24339950cce469195888d59fbc7ddecb0b75f9a7f8279df58cc2bb681637916525341ce8b9fc86c2f38bb9e8b1718a27c9f164d14afa4acff9376f4394da3eb
|
|
7
|
+
data.tar.gz: 39d9128c65180e56fe30e59d6b384dbc9ce2b7648f8586498b88e7e44b4c516fcea6d06b279bc1956373f84f1a8602aa1fb697699a40b98e699b2c6ef2f97c59
|
|
@@ -214,16 +214,12 @@ module Brainiac
|
|
|
214
214
|
# All gates have reviewed — dispatch implementation agent to address ALL feedback
|
|
215
215
|
LOG.info "[Basecamp:Hooks] All gates responded for card ##{card_number} — dispatching fixes" if defined?(LOG)
|
|
216
216
|
task["status"] = "in_flight"
|
|
217
|
+
task["dispatched_at"] = Time.now.iso8601
|
|
217
218
|
task.delete("changes_debounce_started")
|
|
218
219
|
save_epic_state(epic)
|
|
219
220
|
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
fizzy_user_id = Orchestrator.send(:resolve_fizzy_user_id, impl_agent)
|
|
223
|
-
if fizzy_user_id
|
|
224
|
-
LOG.info "[Basecamp:Hooks] Re-assigning card ##{card_number} to #{impl_agent} for fixes" if defined?(LOG)
|
|
225
|
-
safe_assign_card(card_number, fizzy_user_id)
|
|
226
|
-
end
|
|
221
|
+
# Spawn agent directly — safe_assign_card won't work if already assigned
|
|
222
|
+
dispatch_impl_directly(epic, task)
|
|
227
223
|
else
|
|
228
224
|
# Wait for remaining gates to respond
|
|
229
225
|
responded = (task["gate_approvals"]&.size || 0) + (task["changes_requested_by"]&.size || 0)
|
|
@@ -246,11 +242,11 @@ module Brainiac
|
|
|
246
242
|
if task_reloaded && task_reloaded["status"] == "in_review" && task_reloaded["changes_requested_by"]&.any?
|
|
247
243
|
LOG.info "[Basecamp:Hooks] Debounce timeout for card ##{card_number} — forcing dispatch" if defined?(LOG)
|
|
248
244
|
task_reloaded["status"] = "in_flight"
|
|
245
|
+
task_reloaded["dispatched_at"] = Time.now.iso8601
|
|
249
246
|
task_reloaded.delete("changes_debounce_started")
|
|
250
247
|
save_epic_state(epic_reloaded)
|
|
251
|
-
#
|
|
252
|
-
|
|
253
|
-
safe_assign_card(card_number, fizzy_user_id) if fizzy_user_id
|
|
248
|
+
# Spawn agent directly — safe_assign_card won't work if already assigned
|
|
249
|
+
dispatch_impl_directly(epic_reloaded, task_reloaded)
|
|
254
250
|
end
|
|
255
251
|
rescue StandardError => e
|
|
256
252
|
LOG.error "[Basecamp:Hooks] Debounce dispatch failed: #{e.message}" if defined?(LOG)
|
|
@@ -728,14 +724,123 @@ module Brainiac
|
|
|
728
724
|
end
|
|
729
725
|
end
|
|
730
726
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
727
|
+
# Dispatch the implementation agent directly (spawns via run_agent) to address
|
|
728
|
+
# changes_requested feedback. Used by resume and health-check when the agent is
|
|
729
|
+
# no longer running but the Fizzy card is still assigned (so safe_assign_card
|
|
730
|
+
# would bail out with "already assigned, skipping").
|
|
731
|
+
#
|
|
732
|
+
# @param epic [Hash] Epic state
|
|
733
|
+
# @param task [Hash] Task within the epic
|
|
734
|
+
# @return [void]
|
|
735
|
+
def dispatch_impl_directly(epic, task)
|
|
736
|
+
card_number = task["fizzy_card"]
|
|
737
|
+
agent_name = epic["agent"]
|
|
738
|
+
pr_number = task["pr_number"]
|
|
739
|
+
project_key = task["project"]
|
|
740
|
+
card_key = "changes-requested-#{card_number}"
|
|
741
|
+
|
|
742
|
+
# Guard: don't spawn a duplicate if a session is already running for this task
|
|
743
|
+
session_alive = if defined?(session_active?)
|
|
744
|
+
session_active?(card_key)
|
|
745
|
+
elsif Object.respond_to?(:session_active?, true)
|
|
746
|
+
Object.send(:session_active?, card_key)
|
|
747
|
+
else
|
|
748
|
+
false
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
if session_alive
|
|
752
|
+
LOG.info "[Basecamp:Hooks] Session already active for #{card_key} — skipping dispatch" if defined?(LOG)
|
|
753
|
+
return
|
|
754
|
+
end
|
|
734
755
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
756
|
+
LOG.info "[Basecamp:Hooks] Direct-dispatching #{agent_name} for changes_requested on card ##{card_number}" if defined?(LOG)
|
|
757
|
+
|
|
758
|
+
# Get project config
|
|
759
|
+
projects_file = File.join(ENV.fetch("BRAINIAC_DIR", File.join(Dir.home, ".brainiac")), "projects.json")
|
|
760
|
+
projects = File.exist?(projects_file) ? JSON.parse(File.read(projects_file)) : {}
|
|
761
|
+
project_config = projects[project_key]
|
|
762
|
+
|
|
763
|
+
unless project_config
|
|
764
|
+
LOG.error "[Basecamp:Hooks] No project config for '#{project_key}' — cannot direct-dispatch" if defined?(LOG)
|
|
765
|
+
return
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
repo_path = project_config["repo_path"]
|
|
769
|
+
unless repo_path
|
|
770
|
+
LOG.error "[Basecamp:Hooks] No repo_path for project '#{project_key}' — cannot direct-dispatch" if defined?(LOG)
|
|
771
|
+
return
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
# Find the worktree for this card
|
|
775
|
+
work_items_file = File.join(ENV.fetch("BRAINIAC_DIR", File.join(Dir.home, ".brainiac")), "work_items.json")
|
|
776
|
+
worktree_path = repo_path # Default to main repo
|
|
777
|
+
if File.exist?(work_items_file)
|
|
778
|
+
work_items = JSON.parse(File.read(work_items_file))
|
|
779
|
+
work_item = work_items.values.find { |wi| wi.dig("sources", "fizzy", "card_number") == card_number }
|
|
780
|
+
worktree_path = work_item["worktree"] if work_item&.dig("worktree")
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
# Build prompt
|
|
784
|
+
changers = (task["changes_requested_by"] || []).join(", ")
|
|
785
|
+
prompt = <<~PROMPT
|
|
786
|
+
## Changes Requested — Fizzy Card ##{card_number}
|
|
787
|
+
|
|
788
|
+
Review gates have requested changes on your PR#{pr_number ? " ##{pr_number}" : ""}.
|
|
789
|
+
Reviewers who requested changes: #{changers}
|
|
790
|
+
|
|
791
|
+
Your job:
|
|
792
|
+
1. Read the review feedback: #{pr_number ? "`gh pr view #{pr_number} --comments`" : "check the Fizzy card comments"}
|
|
793
|
+
2. Address all requested changes
|
|
794
|
+
3. Commit and push your fixes
|
|
795
|
+
|
|
796
|
+
After pushing, update the Fizzy card with a brief status comment noting what you fixed.
|
|
797
|
+
PROMPT
|
|
798
|
+
|
|
799
|
+
# Resolve GitHub App token so agent's `gh` commands run as their bot identity
|
|
800
|
+
github_repo = project_config&.dig("github_repo")
|
|
801
|
+
agent_env = github_repo ? ReviewGate.send(:resolve_agent_github_env, agent_name, github_repo) : {}
|
|
802
|
+
|
|
803
|
+
# Spawn the agent directly
|
|
804
|
+
pid = nil
|
|
805
|
+
log_file = nil
|
|
806
|
+
|
|
807
|
+
begin
|
|
808
|
+
pid, log_file = method(:run_agent).call(
|
|
809
|
+
prompt,
|
|
810
|
+
project_config: project_config,
|
|
811
|
+
chdir: worktree_path,
|
|
812
|
+
log_name: "changes-requested-#{card_number}",
|
|
813
|
+
agent_name: agent_name,
|
|
814
|
+
source: :basecamp,
|
|
815
|
+
card_number: card_number,
|
|
816
|
+
env: agent_env
|
|
817
|
+
)
|
|
818
|
+
rescue NameError
|
|
819
|
+
if Object.respond_to?(:run_agent, true)
|
|
820
|
+
pid, log_file = Object.send(:run_agent,
|
|
821
|
+
prompt,
|
|
822
|
+
project_config: project_config,
|
|
823
|
+
chdir: worktree_path,
|
|
824
|
+
log_name: "changes-requested-#{card_number}",
|
|
825
|
+
agent_name: agent_name,
|
|
826
|
+
source: :basecamp,
|
|
827
|
+
card_number: card_number,
|
|
828
|
+
env: agent_env)
|
|
829
|
+
else
|
|
830
|
+
LOG.warn "[Basecamp:Hooks] run_agent not available — direct impl dispatch skipped" if defined?(LOG)
|
|
831
|
+
return
|
|
832
|
+
end
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
# Register session for waybar visibility
|
|
836
|
+
if pid
|
|
837
|
+
if defined?(register_session)
|
|
838
|
+
register_session(card_key, pid, log_file: log_file, agent_name: agent_name)
|
|
839
|
+
elsif Object.respond_to?(:register_session, true)
|
|
840
|
+
Object.send(:register_session, card_key, pid, log_file: log_file, agent_name: agent_name)
|
|
841
|
+
end
|
|
842
|
+
LOG.info "[Basecamp:Hooks] Spawned #{agent_name} (pid #{pid}) for changes_requested on card ##{card_number}" if defined?(LOG)
|
|
843
|
+
end
|
|
739
844
|
end
|
|
740
845
|
|
|
741
846
|
def auto_merge_and_advance(epic, card_number, ctx)
|
|
@@ -129,25 +129,21 @@ module Brainiac
|
|
|
129
129
|
impl_agent = epic["agent"]
|
|
130
130
|
LOG.info "[Basecamp:HealthCheck] Task ##{card_number} in_flight for #{elapsed.round}s — re-dispatching #{impl_agent}" if defined?(LOG)
|
|
131
131
|
|
|
132
|
-
#
|
|
132
|
+
# Spawn the agent directly — safe_assign_card won't work if already assigned
|
|
133
133
|
task["dispatched_at"] = Time.now.iso8601
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Hooks.send(:safe_assign_card, card_number, fizzy_user_id)
|
|
137
|
-
healed_any = true
|
|
138
|
-
end
|
|
134
|
+
Hooks.send(:dispatch_impl_directly, epic, task)
|
|
135
|
+
healed_any = true
|
|
139
136
|
end
|
|
140
137
|
elsif task["changes_requested_by"]&.any?
|
|
141
138
|
# No dispatched_at recorded but changes were requested — legacy state.
|
|
142
139
|
# Always re-dispatch in this case.
|
|
143
140
|
impl_agent = epic["agent"]
|
|
144
141
|
LOG.info "[Basecamp:HealthCheck] Task ##{card_number} in_flight with changes_requested but no dispatched_at — re-dispatching #{impl_agent}" if defined?(LOG)
|
|
142
|
+
|
|
143
|
+
# Spawn the agent directly — safe_assign_card won't work if already assigned
|
|
145
144
|
task["dispatched_at"] = Time.now.iso8601
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
Hooks.send(:safe_assign_card, card_number, fizzy_user_id)
|
|
149
|
-
healed_any = true
|
|
150
|
-
end
|
|
145
|
+
Hooks.send(:dispatch_impl_directly, epic, task)
|
|
146
|
+
healed_any = true
|
|
151
147
|
end
|
|
152
148
|
|
|
153
149
|
when "in_review"
|
|
@@ -329,13 +325,11 @@ module Brainiac
|
|
|
329
325
|
|
|
330
326
|
# Transition to in_flight so the agent gets the right context
|
|
331
327
|
task["status"] = "in_flight"
|
|
328
|
+
task["dispatched_at"] = Time.now.iso8601
|
|
332
329
|
Hooks.send(:save_epic_state, epic)
|
|
333
330
|
|
|
334
|
-
#
|
|
335
|
-
|
|
336
|
-
if fizzy_user_id
|
|
337
|
-
Hooks.send(:safe_assign_card, card_number, fizzy_user_id)
|
|
338
|
-
end
|
|
331
|
+
# Spawn the agent directly — safe_assign_card won't work if already assigned
|
|
332
|
+
Hooks.send(:dispatch_impl_directly, epic, task)
|
|
339
333
|
else
|
|
340
334
|
# No changes requested yet — check if gates need (re-)dispatching
|
|
341
335
|
approvals = task["gate_approvals"]&.size || 0
|