brainiac-fizzy 0.0.8 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98a0dcf9fc45aff45ad0dd467090b4f7ef96e426ce2862fcf5b9251baf4fc519
4
- data.tar.gz: eb2b8ec913902f3365efefa1424ae271f3e63f94161c0bbaddc116f9c0ec1bcb
3
+ metadata.gz: d3d24ce3986d1b5353dca763a8ba29060ecd2dce47065cc2ffdd201d4075ca66
4
+ data.tar.gz: 6f39b2c02369556d1b7914c7a37eebcb98eccf016944ed2ea34bba6dac94ebc4
5
5
  SHA512:
6
- metadata.gz: 065dd360d8c26815dc3122e652003c40296edd8fcd582ac9d23a8446b3e29bbcff7d2983b468ad4c395b5729d1ee309a26756af663291ea5385ba4325d7d885d
7
- data.tar.gz: 969d24c897c660ef777576c258df0b26d9f86d478525306f53e5836bcb36716ad6b9b9d6133a465efce89a14c4fab51f5b46b3f44e2f563fdbf885d7caaccaad
6
+ metadata.gz: b417b22c6c7150d3cf823225141d00ae41d94d3f2a6e6c3eb736f4db2ea122ce33b46a0c5d237e4315cf29f415b82b31fa58085a1a48e83177288314bdc8df11
7
+ data.tar.gz: 61d02c8a206ecd4c0e3c9680b3f8856914c30b45a16d9a7507b6118c980c0765fa24e96e4018bbb3793dd357e84de99ee39551b3724c7dba421927b8b679b89e
@@ -50,6 +50,18 @@ def detect_planning_mode(text:, tags:, card_internal_id:, card_number:)
50
50
  card_internal_id: card_internal_id, card_number: card_number)
51
51
  end
52
52
 
53
+ def lookup_fizzy_card_info(card_internal_id)
54
+ Brainiac::Plugins::Fizzy::Helpers.lookup_fizzy_card_info(card_internal_id)
55
+ end
56
+
57
+ def update_fizzy_work_item(card_internal_id, updates)
58
+ Brainiac::Plugins::Fizzy::Helpers.update_fizzy_work_item(card_internal_id, updates)
59
+ end
60
+
61
+ def resolve_card_number(internal_id, repo_path:)
62
+ Brainiac::Plugins::Fizzy::Helpers.resolve_card_number(internal_id, repo_path: repo_path)
63
+ end
64
+
53
65
  def verify_fizzy_signature!(request, payload_body, board_key: nil)
54
66
  Brainiac::Plugins::Fizzy::Helpers.verify_signature!(request, payload_body, board_key: board_key)
55
67
  end
@@ -103,12 +103,10 @@ def setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, pr
103
103
  worktree_path = File.join(File.dirname(repo_path), "#{File.basename(repo_path)}--#{branch}")
104
104
  worktree_path = create_or_reuse_worktree(repo_path: repo_path, branch: branch, worktree_path: worktree_path)
105
105
 
106
- map = load_work_item_map
107
- map[card_internal_id] = {
108
- "number" => card_number, "branch" => branch, "worktree" => worktree_path,
109
- "project" => project_key, "agent" => agent_name
110
- }
111
- save_work_item_map(map)
106
+ register_work_item(
107
+ branch: branch, worktree: worktree_path, project: project_key, agent: agent_name,
108
+ source: :fizzy, source_data: { "card_internal_id" => card_internal_id, "card_number" => card_number }
109
+ )
112
110
  worktree_path
113
111
  end
114
112
 
@@ -41,11 +41,9 @@ def handle_comment(payload)
41
41
  agent_result = validate_agent_comment(creator_is_agent, is_api_sourced, creator_name, mentioned_agent, card_internal_id)
42
42
  return agent_result if agent_result
43
43
 
44
- card_info = load_work_item_map[card_internal_id]
44
+ card_info = lookup_fizzy_card_info(card_internal_id)
45
45
  comment_id = eventable["id"]
46
46
 
47
- return [200, { status: "ignored", reason: "not relevant" }.to_json] unless mentioned_agent || card_info
48
-
49
47
  project_config, project_key = resolve_fizzy_project(card_info, card_internal_id, eventable)
50
48
  return [200, { status: "ignored", reason: "no matching project" }.to_json] unless project_config
51
49
 
@@ -158,7 +156,7 @@ end
158
156
  def validate_agent_comment(creator_is_agent, is_api_sourced, creator_name, mentioned_agent, card_internal_id)
159
157
  return nil unless creator_is_agent || is_api_sourced
160
158
 
161
- card_info = load_work_item_map[card_internal_id]
159
+ card_info = lookup_fizzy_card_info(card_internal_id)
162
160
  card_assigned_agent = card_info&.dig("agent")
163
161
 
164
162
  agent_is_assigned = card_assigned_agent && card_assigned_agent.downcase == (creator_name || "").downcase
@@ -207,7 +205,8 @@ end
207
205
 
208
206
  def handle_cancel_command(eventable, card_internal_id)
209
207
  killed = 0
210
- card_number_for_cancel = load_work_item_map.dig(card_internal_id, "number")
208
+ cancel_card_info = lookup_fizzy_card_info(card_internal_id)
209
+ card_number_for_cancel = cancel_card_info&.dig("number")
211
210
  prefixes = ["card-#{card_internal_id}"]
212
211
  prefixes << "card-#{card_number_for_cancel}" if card_number_for_cancel
213
212
 
@@ -229,9 +228,8 @@ def handle_cancel_command(eventable, card_internal_id)
229
228
  end
230
229
 
231
230
  comment_id_for_cancel = eventable["id"]
232
- card_info_for_cancel = load_work_item_map[card_internal_id]
233
- if card_info_for_cancel && card_number_for_cancel && comment_id_for_cancel
234
- repo = (card_info_for_cancel["project"] && PROJECTS.dig(card_info_for_cancel["project"], "repo_path")) ||
231
+ if cancel_card_info && card_number_for_cancel && comment_id_for_cancel
232
+ repo = (cancel_card_info["project"] && PROJECTS.dig(cancel_card_info["project"], "repo_path")) ||
235
233
  DEFAULT_PROJECT["repo_path"]
236
234
  Thread.new do
237
235
  run_cmd("fizzy", "reaction", "create", "--card", card_number_for_cancel.to_s,
@@ -257,9 +255,7 @@ def resolve_fizzy_project(card_info, card_internal_id, eventable)
257
255
  if project_result
258
256
  project_key, project_config = project_result
259
257
  card_info["project"] = project_key
260
- map = load_work_item_map
261
- map[card_internal_id] = card_info
262
- save_work_item_map(map)
258
+ update_fizzy_work_item(card_internal_id, "project" => project_key)
263
259
  LOG.info "Backfilled project '#{project_key}' for card #{card_internal_id} in card map"
264
260
  else
265
261
  LOG.warn "No project found for card #{card_internal_id}"
@@ -305,21 +301,23 @@ def resolve_assigned_agent(card_info, card_internal_id, eventable, project_confi
305
301
  card_assignees = eventable.dig("card", "assignees") || []
306
302
  webhook_agent = card_assignees.map { |a| a["name"] }.find { |name| local_agent_names.include?(name) }
307
303
 
308
- webhook_agent = resolve_agent_via_api(card_info, card_internal_id, project_config) if webhook_agent.nil? && project_config
304
+ webhook_agent = resolve_agent_via_api(card_info, card_internal_id, eventable, project_config) if webhook_agent.nil? && project_config
309
305
 
310
306
  return nil unless webhook_agent
311
307
 
312
- map = load_work_item_map
313
- map[card_internal_id] ||= {}
314
- map[card_internal_id]["agent"] = webhook_agent
315
- save_work_item_map(map)
308
+ card_number = eventable.dig("card", "number")
309
+ update_fizzy_work_item(card_internal_id, { "agent" => webhook_agent }.tap { |h| h["number"] = card_number if card_number })
316
310
  LOG.info "Backfilled agent '#{webhook_agent}' into card map for #{card_internal_id}"
317
311
  webhook_agent
318
312
  end
319
313
 
320
- def resolve_agent_via_api(card_info, card_internal_id, project_config)
321
- api_card_number = card_info&.dig("number") || card_internal_id
322
- return nil unless api_card_number
314
+ def resolve_agent_via_api(card_info, card_internal_id, eventable, project_config)
315
+ api_card_number = card_info&.dig("number") || eventable.dig("card", "number")
316
+ api_card_number ||= resolve_card_number(card_internal_id, repo_path: project_config["repo_path"])
317
+ unless api_card_number
318
+ LOG.warn "Cannot resolve agent via API — no card number available (internal_id: #{card_internal_id})"
319
+ return nil
320
+ end
323
321
 
324
322
  output = run_cmd("fizzy", "card", "show", api_card_number.to_s,
325
323
  chdir: project_config["repo_path"], env: default_fizzy_env)
@@ -435,7 +433,7 @@ def handle_new_mention(ctx)
435
433
  card_title = card_data["title"] || "exploration"
436
434
 
437
435
  if card_number.nil?
438
- map_entry = load_work_item_map[ctx.card_internal_id]
436
+ map_entry = lookup_fizzy_card_info(ctx.card_internal_id)
439
437
  card_number = if map_entry && map_entry["number"]
440
438
  map_entry["number"]
441
439
  else
@@ -461,12 +459,10 @@ def setup_new_mention_worktree(ctx, card_number, card_title)
461
459
  repo_path = ctx.project_config["repo_path"]
462
460
  worktree_path, branch = resolve_or_create_worktree(ctx, card_number, card_title, repo_path)
463
461
 
464
- map = load_work_item_map
465
- map[ctx.card_internal_id] = {
466
- "number" => card_number, "branch" => branch, "worktree" => worktree_path,
467
- "project" => ctx.project_key, "agent" => ctx.agent_name
468
- }
469
- save_work_item_map(map)
462
+ register_work_item(
463
+ branch: branch, worktree: worktree_path, project: ctx.project_key, agent: ctx.agent_name,
464
+ source: :fizzy, source_data: { "card_internal_id" => ctx.card_internal_id, "card_number" => card_number }
465
+ )
470
466
 
471
467
  [worktree_path, branch]
472
468
  end
@@ -567,12 +563,7 @@ end
567
563
 
568
564
  def resolve_and_save_card_number(card_internal_id, project_config)
569
565
  card_number = resolve_card_number(card_internal_id, repo_path: project_config["repo_path"])
570
- if card_number
571
- map = load_work_item_map
572
- map[card_internal_id] ||= {}
573
- map[card_internal_id]["number"] = card_number
574
- save_work_item_map(map)
575
- end
566
+ update_fizzy_work_item(card_internal_id, "number" => card_number) if card_number
576
567
  card_number
577
568
  end
578
569
 
@@ -580,10 +571,7 @@ def find_and_save_worktree(card_internal_id, card_number, project_config)
580
571
  found = find_worktree_for_card(card_number, repo_path: project_config["repo_path"])
581
572
  return nil unless found
582
573
 
583
- map = load_work_item_map
584
- map[card_internal_id] ||= {}
585
- map[card_internal_id].merge!("worktree" => found[:worktree], "branch" => found[:branch])
586
- save_work_item_map(map)
574
+ update_fizzy_work_item(card_internal_id, "worktree" => found[:worktree], "branch" => found[:branch])
587
575
  LOG.info "Found worktree by card number scan: #{found[:worktree]}"
588
576
  found[:worktree]
589
577
  end
@@ -655,7 +643,7 @@ end
655
643
 
656
644
  def resolve_or_create_worktree(ctx, card_number, card_title, repo_path)
657
645
  # Check for existing worktree in card map or on disk
658
- existing_map_entry = load_work_item_map[ctx.card_internal_id]
646
+ existing_map_entry = lookup_fizzy_card_info(ctx.card_internal_id)
659
647
  if existing_map_entry && existing_map_entry["branch"] && existing_map_entry["worktree"] &&
660
648
  File.directory?(existing_map_entry["worktree"])
661
649
  LOG.info "Reusing existing worktree from card map: #{existing_map_entry["worktree"]}"
@@ -7,7 +7,7 @@
7
7
 
8
8
  def handle_deploy_comment(eventable, env_key, card_internal_id)
9
9
  comment_id = eventable["id"]
10
- card_info = load_card_map[card_internal_id]
10
+ card_info = lookup_fizzy_card_info(card_internal_id)
11
11
 
12
12
  # Validate environment exists
13
13
  deploy_config = DEPLOYMENTS_CONFIG["environments"] || {}
@@ -139,10 +139,9 @@ def clone_branch_for_deploy(eventable, card_internal_id, card_info)
139
139
  end
140
140
 
141
141
  # Update card map
142
- map = load_card_map
143
- map[card_internal_id] ||= {}
144
- map[card_internal_id].merge!("number" => card_number, "branch" => branch, "worktree" => worktree_path, "project" => project_key)
145
- save_card_map(map)
142
+ update_fizzy_work_item(card_internal_id,
143
+ "number" => card_number, "branch" => branch,
144
+ "worktree" => worktree_path, "project" => project_key)
146
145
 
147
146
  LOG.info "[Deploy] Cloned branch #{branch} into worktree #{worktree_path} for card ##{card_number}"
148
147
  { worktree: worktree_path, card_number: card_number }
@@ -168,6 +168,91 @@ module Brainiac
168
168
  { card_id: card_number || card_internal_id }
169
169
  end
170
170
 
171
+ # Look up a Fizzy card's work item info by its internal ID.
172
+ # Returns a hash with top-level "number", "agent", "branch", "worktree", "project"
173
+ # keys for backward compatibility with handler code, or nil if not found.
174
+ def lookup_fizzy_card_info(card_internal_id)
175
+ return nil unless card_internal_id
176
+
177
+ result = find_work_item_by_card(card_internal_id)
178
+ return nil unless result
179
+
180
+ _work_item_id, info = result
181
+ # Ensure "number" is at top level for fizzy handler compat
182
+ info["number"] ||= info.dig("sources", "fizzy", "card_number")
183
+ info
184
+ end
185
+
186
+ # Update or create a work item entry for a Fizzy card.
187
+ # Accepts a hash of fields to merge into the existing entry.
188
+ # Handles both new-format (wi-xxx keyed) and creates new entries properly.
189
+ def update_fizzy_work_item(card_internal_id, updates)
190
+ return unless card_internal_id
191
+
192
+ map = load_work_item_map
193
+ result = nil
194
+ work_item_id = nil
195
+
196
+ # Find existing entry by card internal ID
197
+ map.each do |wid, info|
198
+ next unless info.is_a?(Hash)
199
+
200
+ fizzy_source = info.dig("sources", "fizzy")
201
+ next unless fizzy_source && fizzy_source["card_internal_id"] == card_internal_id
202
+
203
+ work_item_id = wid
204
+ result = info
205
+ break
206
+ end
207
+
208
+ card_number = updates.delete("number")
209
+
210
+ if result
211
+ result["sources"]["fizzy"]["card_number"] = card_number if card_number
212
+ result.merge!(updates)
213
+ map[work_item_id] = result
214
+ else
215
+ new_id = generate_work_item_id(branch: updates["branch"], card_number: card_number)
216
+ map[new_id] = {
217
+ "id" => new_id,
218
+ "branch" => updates["branch"],
219
+ "worktree" => updates["worktree"],
220
+ "project" => updates["project"],
221
+ "agent" => updates["agent"],
222
+ "sources" => {
223
+ "fizzy" => {
224
+ "card_internal_id" => card_internal_id,
225
+ "card_number" => card_number
226
+ }.compact
227
+ }
228
+ }.compact.merge(updates.except("branch", "worktree", "project", "agent"))
229
+ end
230
+
231
+ save_work_item_map(map)
232
+ end
233
+
234
+ # Resolve a card number from an internal ID by querying the Fizzy API.
235
+ # Searches card lists to find the matching card.
236
+ def resolve_card_number(internal_id, repo_path:)
237
+ env = default_fizzy_env
238
+ base_cmd = %w[fizzy card list]
239
+ ["--all", "--all --indexed-by closed"].each do |flags|
240
+ cmd = base_cmd + flags.split
241
+ output = run_cmd(*cmd, chdir: repo_path, env: env)
242
+ data = JSON.parse(output)["data"] || []
243
+ match = data.find { |c| c["id"] == internal_id }
244
+ if match
245
+ LOG.info "Resolved card number #{match["number"]} for internal_id #{internal_id}" if defined?(LOG)
246
+ return match["number"]
247
+ end
248
+ rescue StandardError
249
+ next
250
+ end
251
+
252
+ LOG.warn "Could not resolve card number for internal_id #{internal_id}" if defined?(LOG)
253
+ nil
254
+ end
255
+
171
256
  private
172
257
 
173
258
  def detect_branch_from_comment(body, card_number)
@@ -175,9 +260,12 @@ module Brainiac
175
260
  match = body.match(%r{<code>(fizzy-#{card_number}-[^<]+)</code>})
176
261
  return match[1] if match
177
262
 
178
- # Fall back to card map
263
+ # Fall back to card map — check both new and old format
179
264
  map = load_work_item_map
180
- entry = map.values.find { |v| v["number"].to_s == card_number.to_s }
265
+ entry = map.values.find do |v|
266
+ v.dig("sources", "fizzy", "card_number").to_s == card_number.to_s ||
267
+ v["number"].to_s == card_number.to_s
268
+ end
181
269
  entry&.dig("branch")
182
270
  end
183
271
 
@@ -255,7 +255,10 @@ module Brainiac
255
255
  card_number = card["number"]
256
256
  next unless card_number
257
257
 
258
- map_entry = map.values.find { |info| info["number"] == card_number }
258
+ map_entry = map.values.find do |info|
259
+ info.dig("sources", "fizzy", "card_number").to_s == card_number.to_s ||
260
+ info["number"].to_s == card_number.to_s
261
+ end
259
262
  agent_name = map_entry["agent"] if map_entry
260
263
  env = Helpers.fizzy_env_for(agent_name || AI_AGENT_NAME)
261
264
 
@@ -267,8 +270,8 @@ module Brainiac
267
270
  primary_worktree: map_entry&.dig("worktree"), primary_branch: map_entry&.dig("branch"))
268
271
 
269
272
  if map_entry
270
- internal_id = map.key(map_entry)
271
- map.delete(internal_id)
273
+ work_item_id = map.key(map_entry)
274
+ map.delete(work_item_id)
272
275
  end
273
276
 
274
277
  closed << { number: card_number, url: card["url"], title: card["title"] }
@@ -3,7 +3,7 @@
3
3
  module Brainiac
4
4
  module Plugins
5
5
  module Fizzy
6
- VERSION = "0.0.8"
6
+ VERSION = "0.0.9"
7
7
  end
8
8
  end
9
9
  end
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.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis