brainiac-fizzy 0.0.13 → 0.0.14
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 +8 -0
- data/lib/brainiac/plugins/fizzy/handlers/assignment.rb +1 -1
- data/lib/brainiac/plugins/fizzy/handlers/comments.rb +3 -3
- data/lib/brainiac/plugins/fizzy/handlers/summarize.rb +149 -0
- data/lib/brainiac/plugins/fizzy/hooks.rb +29 -1
- data/lib/brainiac/plugins/fizzy/prompts.rb +15 -1
- data/lib/brainiac/plugins/fizzy/version.rb +1 -1
- data/lib/brainiac/plugins/fizzy.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 90ffad33201985cb5a94b3460fb635d254e806e435543eeb652b533ff59562a6
|
|
4
|
+
data.tar.gz: 209e7829523442c8ccc7e3a278454ddd008fd16df6f83495e1edd42c0ac9dada
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 207769fa7579c519e38ff9551a5b4fb0ff823c1cb88740b7bd3b7f1a459bfd8c7e9ea97e62fd7a6dbeb8a48218595d08143564be8cd577ff32a264be7a97d947
|
|
7
|
+
data.tar.gz: e5d52c3fc6dcf2427b70030fccdb3a9196b2c00ecf63b934710accbaa3cdfef16a7c98765afac1ae33435d86f58837371097b697e733d8484f8bdee6efdedef7
|
|
@@ -136,6 +136,14 @@ PROMPT_MENTION = Brainiac::Plugins::Fizzy::Prompts::MENTION
|
|
|
136
136
|
PROMPT_CROSS_AGENT_REVIEW = Brainiac::Plugins::Fizzy::Prompts::CROSS_AGENT_REVIEW
|
|
137
137
|
PROMPT_PLANNING_MODE = Brainiac::Plugins::Fizzy::Prompts::PLANNING_MODE
|
|
138
138
|
|
|
139
|
+
# Default Fizzy board column IDs — used as fallback when board_key is nil or
|
|
140
|
+
# the board config doesn't specify column mappings.
|
|
141
|
+
DEFAULT_COLUMN_IDS = {
|
|
142
|
+
"right_now" => "03f5xa5q9fog9592pa1279dts",
|
|
143
|
+
"needs_review" => "03f5ykobhpsd78hbuvajtn8g8",
|
|
144
|
+
"uat" => "03fsmglsr6az06ppyotawsti8"
|
|
145
|
+
}.freeze
|
|
146
|
+
|
|
139
147
|
# Render planning mode prompt — identical to render_prompt but inserts the planning
|
|
140
148
|
# instructions between PROMPT_CORE and the channel rules. This was originally defined
|
|
141
149
|
# in brainiac core's planning.rb but belongs here after the fizzy extraction.
|
|
@@ -152,7 +152,7 @@ def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branc
|
|
|
152
152
|
project_config: project_config, chdir: worktree_path,
|
|
153
153
|
log_name: "assigned-#{card_number}", model: model, effort: effort,
|
|
154
154
|
agent_name: agent_name, card_number: card_number, source: :fizzy,
|
|
155
|
-
source_context: { card_number: card_number },
|
|
155
|
+
source_context: { card_number: card_number, dispatched_at: Time.now },
|
|
156
156
|
cli_provider: cli_provider_override)
|
|
157
157
|
register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: agent_name)
|
|
158
158
|
|
|
@@ -408,7 +408,7 @@ def dispatch_cross_agent_review(ctx, card_key:, card_number:, card_assigned_agen
|
|
|
408
408
|
log_name: "review-#{ctx.agent_name.downcase}-#{card_number || ctx.card_internal_id}",
|
|
409
409
|
model: ctx.model, effort: ctx.effort, agent_name: ctx.agent_name,
|
|
410
410
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
411
|
-
source: :fizzy, source_context: { card_number: card_number },
|
|
411
|
+
source: :fizzy, source_context: { card_number: card_number, dispatched_at: Time.now },
|
|
412
412
|
cli_provider: ctx.cli_provider_override)
|
|
413
413
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
414
414
|
|
|
@@ -514,7 +514,7 @@ def dispatch_new_mention(ctx, card_key:, card_number:, card_title:, branch:, wor
|
|
|
514
514
|
model: ctx.model, effort: ctx.effort, agent_name: ctx.agent_name,
|
|
515
515
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
516
516
|
source: :fizzy, cli_provider: ctx.cli_provider_override,
|
|
517
|
-
source_context: { card_number: card_number })
|
|
517
|
+
source_context: { card_number: card_number, dispatched_at: Time.now })
|
|
518
518
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
519
519
|
|
|
520
520
|
register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: ctx.agent_name)
|
|
@@ -554,7 +554,7 @@ def dispatch_followup_comment(ctx, card_key:, card_number:, work_dir:)
|
|
|
554
554
|
source: :fizzy, cli_provider: ctx.cli_provider_override, resume: should_resume,
|
|
555
555
|
source_context: {
|
|
556
556
|
card_number: card_number, card_internal_id: ctx.card_internal_id,
|
|
557
|
-
deploy_intent: ctx.deploy_intent
|
|
557
|
+
deploy_intent: ctx.deploy_intent, dispatched_at: Time.now
|
|
558
558
|
})
|
|
559
559
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
560
560
|
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
module Brainiac
|
|
6
|
+
module Plugins
|
|
7
|
+
module Fizzy
|
|
8
|
+
# Handles re-dispatch summarize sessions and fallback comment posting.
|
|
9
|
+
# Extracted from Hooks to keep module length manageable.
|
|
10
|
+
module Summarize
|
|
11
|
+
class << self
|
|
12
|
+
# Re-dispatch an agent to post a summary comment when it completed work
|
|
13
|
+
# but didn't comment on the card. Fires async with a 60s timeout.
|
|
14
|
+
# If this session also fails to comment, posts a minimal fallback.
|
|
15
|
+
def dispatch_summarize_session(ctx)
|
|
16
|
+
card_number = ctx[:card_number]
|
|
17
|
+
agent_name = ctx[:agent_name]
|
|
18
|
+
project_config = ctx[:project_config]
|
|
19
|
+
repo_path = project_config["repo_path"]
|
|
20
|
+
session_started_at = ctx[:source_context]&.dig(:dispatched_at)
|
|
21
|
+
|
|
22
|
+
map = load_work_item_map
|
|
23
|
+
work_item = find_work_item(map, card_number)
|
|
24
|
+
|
|
25
|
+
branch = work_item&.dig("branch") || "unknown"
|
|
26
|
+
card_title = work_item&.dig("title") || ctx[:source_context]&.dig(:card_title) || "untitled"
|
|
27
|
+
worktree_path = work_item&.dig("worktree") || repo_path
|
|
28
|
+
|
|
29
|
+
if defined?(LOG)
|
|
30
|
+
LOG.info "[Fizzy] Agent #{agent_name} completed card ##{card_number} without commenting — " \
|
|
31
|
+
"dispatching summarize session"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
pid, log_file = dispatch_summarize_agent(card_number, card_title, branch, agent_name,
|
|
35
|
+
project_config, worktree_path)
|
|
36
|
+
register_session("card-#{card_number}-summarize", pid, log_file: log_file, agent_name: agent_name)
|
|
37
|
+
|
|
38
|
+
monitor_summarize_session(pid, card_number, agent_name, branch, repo_path, session_started_at,
|
|
39
|
+
project_config)
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
LOG.error "[Fizzy] Failed to dispatch summarize session for card ##{card_number}: #{e.message}" if defined?(LOG)
|
|
42
|
+
post_fallback_comment(card_number, work_item&.dig("branch") || "unknown", agent_name, project_config)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check if the agent posted a comment on the card since a given time.
|
|
46
|
+
# If no `since` is provided, checks for any agent comment (legacy behavior).
|
|
47
|
+
def agent_commented_on_card?(card_number, agent_name, repo_path:, since: nil)
|
|
48
|
+
env = Helpers.fizzy_env_for(agent_name)
|
|
49
|
+
output = run_cmd("fizzy", "comment", "list", "--card", card_number.to_s, chdir: repo_path, env: env)
|
|
50
|
+
comments = JSON.parse(output)["data"] || []
|
|
51
|
+
agent_display = agent_display_name(agent_name)
|
|
52
|
+
|
|
53
|
+
agent_comments = comments.select { |c| c["creator_name"]&.downcase == agent_display.downcase }
|
|
54
|
+
return agent_comments.any? unless since
|
|
55
|
+
|
|
56
|
+
agent_comments.any? do |c|
|
|
57
|
+
comment_time = c["created_at"] && Time.parse(c["created_at"])
|
|
58
|
+
comment_time && comment_time > since
|
|
59
|
+
end
|
|
60
|
+
rescue StandardError
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Post a minimal server-generated comment when all else fails.
|
|
65
|
+
def post_fallback_comment(card_number, branch, agent_name, project_config)
|
|
66
|
+
repo_path = project_config["repo_path"]
|
|
67
|
+
env = Helpers.fizzy_env_for(agent_name)
|
|
68
|
+
|
|
69
|
+
pr_url = Helpers.send(:detect_pr_url, branch, project_config)
|
|
70
|
+
body = "<p>✅ Work completed on this card.</p>"
|
|
71
|
+
body += "<p><a href=\"#{pr_url}\">View PR</a></p>" if pr_url
|
|
72
|
+
body += "<p><strong>Branch:</strong> <code>#{branch}</code></p>"
|
|
73
|
+
|
|
74
|
+
run_cmd("fizzy", "comment", "create", "--card", card_number.to_s, "--body", body,
|
|
75
|
+
chdir: repo_path, env: env)
|
|
76
|
+
LOG.info "[Fizzy] Posted fallback comment on card ##{card_number}" if defined?(LOG)
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
LOG.error "[Fizzy] Failed to post fallback comment on card ##{card_number}: #{e.message}" if defined?(LOG)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def find_work_item(map, card_number)
|
|
84
|
+
map.values.find do |info|
|
|
85
|
+
info.is_a?(Hash) &&
|
|
86
|
+
(info.dig("sources", "fizzy", "card_number").to_s == card_number.to_s ||
|
|
87
|
+
info["number"].to_s == card_number.to_s)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def dispatch_summarize_agent(card_number, card_title, branch, agent_name, project_config, worktree_path)
|
|
92
|
+
prompt = render_prompt(Prompts::SUMMARIZE_WORK,
|
|
93
|
+
{ "CARD_NUMBER" => card_number, "CARD_TITLE" => card_title, "BRANCH" => branch },
|
|
94
|
+
brain_context: "", agent_name: agent_name, channel: :fizzy,
|
|
95
|
+
board_key: Config.board_key_for_project(project_config))
|
|
96
|
+
|
|
97
|
+
run_agent(prompt,
|
|
98
|
+
project_config: project_config, chdir: worktree_path,
|
|
99
|
+
log_name: "summarize-#{card_number}", agent_name: agent_name,
|
|
100
|
+
source: :fizzy,
|
|
101
|
+
source_context: { card_number: card_number, skip_summarize_redispatch: true },
|
|
102
|
+
skip_column_move: true)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def monitor_summarize_session(pid, card_number, agent_name, branch, repo_path, session_started_at,
|
|
106
|
+
project_config)
|
|
107
|
+
Thread.new do
|
|
108
|
+
wait_for_process_or_timeout(pid, timeout: 60)
|
|
109
|
+
sleep 2 # Brief pause to let any comment propagate
|
|
110
|
+
|
|
111
|
+
unless agent_commented_on_card?(card_number, agent_name, repo_path: repo_path, since: session_started_at)
|
|
112
|
+
post_fallback_comment(card_number, branch, agent_name, project_config)
|
|
113
|
+
end
|
|
114
|
+
rescue Errno::ECHILD
|
|
115
|
+
# Process already reaped by session manager — check for comment
|
|
116
|
+
sleep 2
|
|
117
|
+
unless agent_commented_on_card?(card_number, agent_name, repo_path: repo_path, since: session_started_at)
|
|
118
|
+
post_fallback_comment(card_number, branch, agent_name, project_config)
|
|
119
|
+
end
|
|
120
|
+
rescue StandardError => e
|
|
121
|
+
LOG.error "[Fizzy] Summarize monitor error for card ##{card_number}: #{e.message}" if defined?(LOG)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def wait_for_process_or_timeout(pid, timeout: 60)
|
|
126
|
+
deadline = Time.now + timeout
|
|
127
|
+
loop do
|
|
128
|
+
result = Process.waitpid2(pid, Process::WNOHANG)
|
|
129
|
+
break if result
|
|
130
|
+
|
|
131
|
+
if Time.now > deadline
|
|
132
|
+
safe_kill(pid)
|
|
133
|
+
break
|
|
134
|
+
end
|
|
135
|
+
sleep 1
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def safe_kill(pid)
|
|
140
|
+
Process.kill("TERM", pid)
|
|
141
|
+
Process.waitpid2(pid)
|
|
142
|
+
rescue Errno::ESRCH, Errno::ECHILD
|
|
143
|
+
# Process already gone
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
3
5
|
module Brainiac
|
|
4
6
|
module Plugins
|
|
5
7
|
module Fizzy
|
|
@@ -25,6 +27,7 @@ module Brainiac
|
|
|
25
27
|
private
|
|
26
28
|
|
|
27
29
|
# After an agent session completes — move card to needs_review, append footer
|
|
30
|
+
# If the agent didn't post a comment, re-dispatch for a summary.
|
|
28
31
|
def register_agent_completed
|
|
29
32
|
Brainiac.on(:agent_completed) do |ctx|
|
|
30
33
|
next unless ctx[:source] == :fizzy
|
|
@@ -43,6 +46,16 @@ module Brainiac
|
|
|
43
46
|
project_config: ctx[:project_config],
|
|
44
47
|
agent_name: ctx[:agent_name])
|
|
45
48
|
|
|
49
|
+
# If the agent didn't post any comment during this session, re-dispatch to summarize from memory.
|
|
50
|
+
# Uses dispatched_at from source_context to only check for comments made during THIS session,
|
|
51
|
+
# not previous sessions on the same card.
|
|
52
|
+
if !ctx[:source_context]&.dig(:skip_summarize_redispatch) &&
|
|
53
|
+
!agent_commented_on_card?(card_number, ctx[:agent_name],
|
|
54
|
+
repo_path: ctx[:project_config]["repo_path"],
|
|
55
|
+
since: ctx[:source_context]&.dig(:dispatched_at))
|
|
56
|
+
dispatch_summarize_session(ctx)
|
|
57
|
+
end
|
|
58
|
+
|
|
46
59
|
# Planning mode finalization
|
|
47
60
|
Planning.finalize_if_needed(ctx[:prompt_file], ctx[:agent_name], ctx[:project_config])
|
|
48
61
|
end
|
|
@@ -240,13 +253,28 @@ module Brainiac
|
|
|
240
253
|
|
|
241
254
|
pid, log_file = run_agent(prompt, project_config: project_config, chdir: repo_path,
|
|
242
255
|
log_name: "uat-#{card_number}", agent_name: agent_name,
|
|
243
|
-
source: :fizzy,
|
|
256
|
+
source: :fizzy,
|
|
257
|
+
source_context: { card_number: card_number, dispatched_at: Time.now },
|
|
258
|
+
skip_column_move: true)
|
|
244
259
|
register_session("card-#{card_number}", pid, log_file: log_file, agent_name: agent_name)
|
|
245
260
|
LOG.info "[Fizzy] Dispatched #{agent_name} for UAT on card ##{card_number}" if defined?(LOG)
|
|
246
261
|
rescue StandardError => e
|
|
247
262
|
LOG.error "[Fizzy] Failed to dispatch UAT agent: #{e.message}" if defined?(LOG)
|
|
248
263
|
end
|
|
249
264
|
|
|
265
|
+
# Delegated to Summarize module for manageable file length.
|
|
266
|
+
def dispatch_summarize_session(ctx)
|
|
267
|
+
Summarize.dispatch_summarize_session(ctx)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def agent_commented_on_card?(card_number, agent_name, repo_path:, since: nil)
|
|
271
|
+
Summarize.agent_commented_on_card?(card_number, agent_name, repo_path: repo_path, since: since)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def post_fallback_comment(card_number, branch, agent_name, project_config)
|
|
275
|
+
Summarize.post_fallback_comment(card_number, branch, agent_name, project_config)
|
|
276
|
+
end
|
|
277
|
+
|
|
250
278
|
def close_uat_cards(card_list, repo_path)
|
|
251
279
|
closed = []
|
|
252
280
|
map = load_work_item_map
|
|
@@ -55,7 +55,9 @@ module Brainiac
|
|
|
55
55
|
You have been assigned Fizzy card #{{CARD_NUMBER}}: "{{CARD_TITLE}}".
|
|
56
56
|
You are on branch "{{BRANCH}}" in a fresh worktree.
|
|
57
57
|
Implement the task, commit, push, and open a PR (link back to Fizzy).
|
|
58
|
-
|
|
58
|
+
|
|
59
|
+
**Response destination: Post your response as a comment on Fizzy card #{{CARD_NUMBER}}.**
|
|
60
|
+
Your comment MUST include a concise summary of what you did, a PR link, and the branch name.
|
|
59
61
|
|
|
60
62
|
**MANDATORY: Always include the branch name in your comment.** Use this format:
|
|
61
63
|
`<p><strong>Branch:</strong> <code>{{BRANCH}}</code></p>`
|
|
@@ -111,6 +113,18 @@ module Brainiac
|
|
|
111
113
|
**IMPORTANT: Do NOT @mention any other agents in your response.**
|
|
112
114
|
PROMPT
|
|
113
115
|
|
|
116
|
+
SUMMARIZE_WORK = <<~'PROMPT'
|
|
117
|
+
You completed work on Fizzy card #{{CARD_NUMBER}} ("{{CARD_TITLE}}") but did not post a comment.
|
|
118
|
+
Read your memory file for this card and write a brief summary comment.
|
|
119
|
+
|
|
120
|
+
**Response destination: Post your response as a comment on Fizzy card #{{CARD_NUMBER}}.**
|
|
121
|
+
Include what you did, any PR link, and the branch name.
|
|
122
|
+
Keep it concise — this is a summary, not a full report.
|
|
123
|
+
|
|
124
|
+
**MANDATORY: Always include the branch name in your comment.** Use this format:
|
|
125
|
+
`<p><strong>Branch:</strong> <code>{{BRANCH}}</code></p>`
|
|
126
|
+
PROMPT
|
|
127
|
+
|
|
114
128
|
UAT_TESTING = <<~'PROMPT'
|
|
115
129
|
PR for card #{{CARD_NUMBER}} ("{{CARD_TITLE}}") has been merged to main (PR #{{PR_NUMBER}}).
|
|
116
130
|
Run any UAT testing steps defined in the card or acceptance criteria.
|
|
@@ -16,6 +16,7 @@ require_relative "fizzy/handlers/dedup"
|
|
|
16
16
|
require_relative "fizzy/handlers/deploy"
|
|
17
17
|
require_relative "fizzy/handlers/card_index"
|
|
18
18
|
require_relative "fizzy/handlers/deployments"
|
|
19
|
+
require_relative "fizzy/handlers/summarize"
|
|
19
20
|
|
|
20
21
|
module Brainiac
|
|
21
22
|
module Plugins
|
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.
|
|
4
|
+
version: 0.0.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Davis
|
|
@@ -98,6 +98,7 @@ files:
|
|
|
98
98
|
- lib/brainiac/plugins/fizzy/handlers/dedup.rb
|
|
99
99
|
- lib/brainiac/plugins/fizzy/handlers/deploy.rb
|
|
100
100
|
- lib/brainiac/plugins/fizzy/handlers/deployments.rb
|
|
101
|
+
- lib/brainiac/plugins/fizzy/handlers/summarize.rb
|
|
101
102
|
- lib/brainiac/plugins/fizzy/helpers.rb
|
|
102
103
|
- lib/brainiac/plugins/fizzy/hooks.rb
|
|
103
104
|
- lib/brainiac/plugins/fizzy/metadata.rb
|