brainiac-fizzy 0.0.23 → 0.0.25

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49fb9f716295e5635310802446ef24b4ab0fc50a0de0e7ed51aa6d8a66229cb3
4
- data.tar.gz: 877d8bb3380a19038ff7d5783b249e3ef5f8334074985b46bfeba2f82e174be1
3
+ metadata.gz: d280084c82934cffbe0868040f944eab1f244ccc10563db9b7bd8a338f86d175
4
+ data.tar.gz: 47343a66a5232ea0bdc3d5e0ad8244692e7b4a8ee22efc91656f0e06e6a00c8d
5
5
  SHA512:
6
- metadata.gz: cea8aef292a4c13e70d551c666ef541aeb4c017077feff75dbfa47fee6c7cfad65c07050c1360735279120124442c178bae7d7a11cd7b36f71fc2fe597dd6469
7
- data.tar.gz: f39a533e11ab58b15ac93a360026b660c67b612fa7f6e17b58ebf91ad280e17b4eed65ab3076da76406d8d8207e6d85c7fa54eae32554a354bf1c51081074325
6
+ metadata.gz: f6c5ddfde5c2eaf03ad0ce86bd996f6d28d1662be8e486015b16edf6c9a158d91638db521ea6f8d269b795d5f64c590e22cc0905c5fcfda7cb9a68c7494ddfd2
7
+ data.tar.gz: 3371c4fd11abbcdbee4ca7d5b520b1bba0180ad1c61e4172ca77cc95820cef496fc24380a71c97eb0bbe9ce4e5e48fa6934224ad605f393a5db8afb2b6b04f25
@@ -25,12 +25,17 @@ def prefetch_card_context(card_number, repo_path:, agent_name: nil)
25
25
  Brainiac::Plugins::Fizzy::Helpers.prefetch_card_context(card_number, repo_path: repo_path, agent_name: agent_name)
26
26
  end
27
27
 
28
+ def resolve_github_agent_env(agent_name, github_repo)
29
+ Brainiac::Plugins::Fizzy::Helpers.resolve_github_agent_env(agent_name, github_repo)
30
+ end
31
+
28
32
  def fetch_intent_context(card_number, repo_path:, agent_name: nil)
29
33
  Brainiac::Plugins::Fizzy::Helpers.fetch_intent_context(card_number, repo_path: repo_path, agent_name: agent_name)
30
34
  end
31
35
 
32
36
  def move_card_to_column(card_number, column_name, project_config:, agent_name: nil, board_key: nil)
33
- Brainiac::Plugins::Fizzy::Helpers.move_card_to_column(card_number, column_name, project_config: project_config, agent_name: agent_name, board_key: board_key)
37
+ Brainiac::Plugins::Fizzy::Helpers.move_card_to_column(card_number, column_name, project_config: project_config, agent_name: agent_name,
38
+ board_key: board_key)
34
39
  end
35
40
 
36
41
  def append_fizzy_comment_footer(card_number, project_config:, agent_name: nil, since: nil)
@@ -113,7 +113,13 @@ end
113
113
  def setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, project_key, agent_name, board_key: nil)
114
114
  debounced_repo_fetch(repo_path)
115
115
  worktree_path = File.join(File.dirname(repo_path), "#{File.basename(repo_path)}--#{branch}")
116
- worktree_path = create_or_reuse_worktree(repo_path: repo_path, branch: branch, worktree_path: worktree_path)
116
+
117
+ # Allow plugins (e.g., brainiac-basecamp) to override the base branch for epic workflows.
118
+ base_ref = if defined?(resolve_base_branch)
119
+ resolve_base_branch(repo_path: repo_path, card_number: card_number, project_key: project_key)
120
+ end
121
+
122
+ worktree_path = create_or_reuse_worktree(repo_path: repo_path, branch: branch, base_ref: base_ref, worktree_path: worktree_path)
117
123
 
118
124
  source_data = { "card_internal_id" => card_internal_id, "card_number" => card_number }
119
125
  source_data["board_key"] = board_key if board_key
@@ -134,6 +140,15 @@ def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branc
134
140
  "CARD_NUMBER" => card_number, "CARD_TITLE" => title,
135
141
  "BRANCH" => branch, "COMMENT_CREATOR" => agent_name
136
142
  }
143
+
144
+ # Resolve custom PR target (for epic branch workflows)
145
+ pr_target = resolve_pr_target(repo_path: project_config["repo_path"], card_number: card_number, project_key: project_key)
146
+ template_vars["PR_TARGET_INSTRUCTION"] = if pr_target
147
+ "**IMPORTANT: Open the PR targeting the `#{pr_target}` branch " \
148
+ "(not main).** Use: `gh pr create --base #{pr_target}`"
149
+ else
150
+ ""
151
+ end
137
152
  brain_ctx = build_brain_context(
138
153
  agent_name: agent_name, card_title: title,
139
154
  card_number: card_number, project_key: project_key, source: :fizzy
@@ -151,12 +166,17 @@ def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branc
151
166
  end
152
167
 
153
168
  card_key = "card-#{card_number}"
169
+
170
+ # Inject GitHub App token so agent's gh commands run as their bot identity
171
+ github_repo = project_config["github_repo"]
172
+ agent_github_env = resolve_github_agent_env(agent_name, github_repo)
173
+
154
174
  pid, log_file = run_agent(prompt,
155
175
  project_config: project_config, chdir: worktree_path,
156
176
  log_name: "assigned-#{card_number}", model: model, effort: effort,
157
177
  agent_name: agent_name, card_number: card_number, source: :fizzy,
158
178
  source_context: { card_number: card_number, board_key: board_key, dispatched_at: Time.now },
159
- cli_provider: cli_provider_override)
179
+ cli_provider: cli_provider_override, env: agent_github_env)
160
180
  register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: agent_name)
161
181
 
162
182
  Thread.new { move_card_to_column(card_number, "right_now", project_config: project_config, agent_name: agent_name, board_key: board_key) }
@@ -565,7 +565,9 @@ def dispatch_followup_comment(ctx, card_key:, card_number:, work_dir:)
565
565
 
566
566
  register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: ctx.agent_name)
567
567
 
568
- Thread.new { move_card_to_column(card_number, "right_now", project_config: ctx.project_config, agent_name: ctx.agent_name, board_key: ctx.board_key) }
568
+ Thread.new do
569
+ move_card_to_column(card_number, "right_now", project_config: ctx.project_config, agent_name: ctx.agent_name, board_key: ctx.board_key)
570
+ end
569
571
 
570
572
  { status: "follow_up", card: card_number, card_internal_id: ctx.card_internal_id,
571
573
  worktree: work_dir, project: ctx.project_key }
@@ -33,6 +33,22 @@ module Brainiac
33
33
  fizzy_env_for(AI_AGENT_NAME)
34
34
  end
35
35
 
36
+ # Resolve GitHub App token for an agent so gh CLI runs as their bot identity.
37
+ # Uses brainiac-github's AppClient if available.
38
+ def resolve_github_agent_env(agent_name, github_repo)
39
+ return {} unless github_repo
40
+
41
+ if defined?(Brainiac::Plugins::Github::AppClient)
42
+ repo_owner = github_repo.split("/").first
43
+ token = Brainiac::Plugins::Github::AppClient.installation_token_for(agent_name, repo_owner: repo_owner)
44
+ return { "GH_TOKEN" => token } if token
45
+ end
46
+ {}
47
+ rescue StandardError => e
48
+ LOG.warn "[Fizzy] Could not resolve GitHub token for #{agent_name}: #{e.message}" if defined?(LOG)
49
+ {}
50
+ end
51
+
36
52
  def prefetch_card_context(card_number, repo_path:, agent_name: nil)
37
53
  env = fizzy_env_for(agent_name || AI_AGENT_NAME)
38
54
  card_details = fetch_card_details(card_number, repo_path: repo_path, env: env)
@@ -51,7 +51,7 @@ module Brainiac
51
51
  # Retry once after a short delay to account for Fizzy API propagation.
52
52
  # The agent may have posted its comment just before exiting, and the API
53
53
  # might not return it immediately in a list call.
54
- if !found_comment
54
+ unless found_comment
55
55
  sleep 5
56
56
  found_comment = Helpers.append_fizzy_comment_footer(card_number,
57
57
  project_config: ctx[:project_config],
@@ -167,17 +167,63 @@ module Brainiac
167
167
  rescue StandardError => e
168
168
  LOG.error "[Fizzy] Error in pr_merged hook: #{e.message}" if defined?(LOG)
169
169
  end
170
+
171
+ # Also listen for epic branch merges (from brainiac-basecamp)
172
+ # Move card to UAT when merged to any tracked branch
173
+ Brainiac.on(:pr_merged_to_branch) do |ctx|
174
+ card_number = ctx[:card_number]
175
+ next unless card_number
176
+
177
+ # Find the work item to get card info
178
+ branch = ctx[:branch]
179
+ work_item = find_work_item_by_branch(branch) if respond_to?(:find_work_item_by_branch, true)
180
+ work_item ||= Object.respond_to?(:find_work_item_by_branch, true) ? Object.send(:find_work_item_by_branch, branch) : nil
181
+
182
+ next unless work_item
183
+
184
+ _internal_id, card_info = work_item
185
+ card_agent = card_info["agent"]
186
+ board_key = card_info.dig("sources", "fizzy", "board_key")
187
+
188
+ # Load project config
189
+ project_key = card_info.dig("sources", "fizzy", "project") || card_info["project"]
190
+ projects_file = File.join(ENV.fetch("BRAINIAC_DIR", File.join(Dir.home, ".brainiac")), "projects.json")
191
+ projects = File.exist?(projects_file) ? JSON.parse(File.read(projects_file)) : {}
192
+ project_config = projects[project_key] || {}
193
+ repo_path = project_config["repo_path"]
194
+
195
+ next unless repo_path
196
+
197
+ # Move card to UAT (same as main merge)
198
+ LOG.info "[Fizzy] PR merged to #{ctx[:base_branch]} for card ##{card_number} — moving to UAT" if defined?(LOG)
199
+ Helpers.move_card_to_column(card_number, "uat",
200
+ project_config: project_config,
201
+ agent_name: card_agent,
202
+ board_key: board_key)
203
+ record_self_move(card_number)
204
+ rescue StandardError => e
205
+ LOG.error "[Fizzy] Error in pr_merged_to_branch hook: #{e.message}" if defined?(LOG)
206
+ end
170
207
  end
171
208
 
172
209
  # PR review received — post status comment on card
210
+ # Only for changes_requested reviews that need action, not for approvals or gate reviews
173
211
  def register_pr_review_received
174
212
  Brainiac.on(:pr_review_received) do |ctx|
175
213
  card_number = ctx[:card_number]
176
214
  next unless card_number
177
215
 
216
+ # Only post status for changes_requested — approvals don't need a Fizzy comment
217
+ review_state = ctx[:review_state]
218
+ next unless review_state == "changes_requested"
219
+
220
+ # Skip if this is a gate agent review (handled by brainiac-basecamp)
221
+ reviewer = ctx[:reviewer]
222
+ next if reviewer&.match?(/-(brainiac|bot)\b/i)
223
+
178
224
  Thread.new do
179
225
  env = Helpers.fizzy_env_for(ctx[:agent_name])
180
- status_comment = "<p>🔄 Code review received from @#{ctx[:reviewer]}. Updates in progress...</p>"
226
+ status_comment = "<p>🔄 Code review received from @#{reviewer}. Updates in progress...</p>"
181
227
  run_cmd("fizzy", "comment", "create", "--card", card_number.to_s, "--body", status_comment,
182
228
  chdir: ctx[:repo_path], env: env)
183
229
  rescue StandardError => e
@@ -375,7 +421,11 @@ module Brainiac
375
421
  "--board", board_id, "--all", "--json",
376
422
  chdir: Dir.home)
377
423
  unless status.success?
378
- parsed = JSON.parse(stdout) rescue nil
424
+ parsed = begin
425
+ JSON.parse(stdout)
426
+ rescue StandardError
427
+ nil
428
+ end
379
429
  if parsed&.dig("code") == "forbidden"
380
430
  LOG.warn "[Fizzy] Webhook check failed for board '#{board_key}' (admin_token lacks permission)"
381
431
  else
@@ -384,7 +434,7 @@ module Brainiac
384
434
  next
385
435
  end
386
436
 
387
- webhooks = (JSON.parse(stdout)["data"] || [])
437
+ webhooks = JSON.parse(stdout)["data"] || []
388
438
  webhooks.each do |webhook|
389
439
  next unless webhook["name"]&.start_with?("brainiac")
390
440
  next if webhook["active"]
@@ -59,6 +59,7 @@ module Brainiac
59
59
  You have been assigned Fizzy card #{{CARD_NUMBER}}: "{{CARD_TITLE}}".
60
60
  You are on branch "{{BRANCH}}" in a fresh worktree.
61
61
  Implement the task, commit, push, and open a PR (link back to Fizzy).
62
+ {{PR_TARGET_INSTRUCTION}}
62
63
 
63
64
  **Response destination: Post your response as a comment on Fizzy card #{{CARD_NUMBER}}.**
64
65
  Your comment MUST include a concise summary of what you did, a PR link, and the branch name.
@@ -3,7 +3,7 @@
3
3
  module Brainiac
4
4
  module Plugins
5
5
  module Fizzy
6
- VERSION = "0.0.23"
6
+ VERSION = "0.0.25"
7
7
  end
8
8
  end
9
9
  end
@@ -178,7 +178,7 @@ module Brainiac
178
178
  config = DEPLOYMENTS_CONFIG["environments"] || {}
179
179
  halt 404, { error: "Unknown environment: #{env_key}" }.to_json unless config.key?(env_key)
180
180
  request.body.rewind
181
- payload = begin
181
+ begin
182
182
  JSON.parse(request.body.read)
183
183
  rescue StandardError
184
184
  {}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainiac-fizzy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis