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 +4 -4
- data/lib/brainiac/plugins/fizzy/delegators.rb +12 -0
- data/lib/brainiac/plugins/fizzy/handlers/assignment.rb +4 -6
- data/lib/brainiac/plugins/fizzy/handlers/comments.rb +25 -37
- data/lib/brainiac/plugins/fizzy/handlers/deploy.rb +4 -5
- data/lib/brainiac/plugins/fizzy/helpers.rb +90 -2
- data/lib/brainiac/plugins/fizzy/hooks.rb +6 -3
- data/lib/brainiac/plugins/fizzy/version.rb +1 -1
- 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: d3d24ce3986d1b5353dca763a8ba29060ecd2dce47065cc2ffdd201d4075ca66
|
|
4
|
+
data.tar.gz: 6f39b2c02369556d1b7914c7a37eebcb98eccf016944ed2ea34bba6dac94ebc4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
233
|
-
|
|
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
|
-
|
|
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
|
-
|
|
313
|
-
|
|
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") ||
|
|
322
|
-
|
|
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 =
|
|
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
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
271
|
-
map.delete(
|
|
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"] }
|