brainiac-fizzy 0.0.1

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.
@@ -0,0 +1,371 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brainiac
4
+ module Plugins
5
+ module Fizzy
6
+ # Registers all Fizzy lifecycle hooks with the core event system.
7
+ module Hooks
8
+ class << self
9
+ def register_all!
10
+ register_agent_completed
11
+ register_agent_crashed
12
+ register_pre_dispatch
13
+ register_brain_context
14
+ register_pr_merged
15
+ register_pr_review_received
16
+ register_pr_synchronized
17
+ register_production_deployed
18
+ register_create_work_item
19
+ register_server_started
20
+ register_detect_cli_provider
21
+ register_detect_effort
22
+ end
23
+
24
+ private
25
+
26
+ # After an agent session completes — move card to needs_review, append footer
27
+ def register_agent_completed
28
+ Brainiac.on(:agent_completed) do |ctx|
29
+ next unless ctx[:source] == :fizzy
30
+
31
+ card_number = ctx[:card_number]
32
+ next unless card_number && ctx[:exit_status]&.zero? && !ctx[:signaled]
33
+
34
+ unless ctx[:skip_column_move] || work_item_merged?(card_number)
35
+ Helpers.move_card_to_column(card_number, "needs_review",
36
+ project_config: ctx[:project_config],
37
+ agent_name: ctx[:agent_name])
38
+ record_self_move(card_number)
39
+ end
40
+
41
+ Helpers.append_fizzy_comment_footer(card_number,
42
+ project_config: ctx[:project_config],
43
+ agent_name: ctx[:agent_name])
44
+
45
+ # Planning mode finalization
46
+ Planning.finalize_if_needed(ctx[:prompt_file], ctx[:agent_name], ctx[:project_config])
47
+ end
48
+ end
49
+
50
+ # Agent crashed — post crash comment on Fizzy card
51
+ def register_agent_crashed
52
+ Brainiac.on(:agent_crashed) do |ctx|
53
+ next unless ctx[:source] == :fizzy
54
+
55
+ card_number = ctx[:source_context]&.dig(:card_number)
56
+ next unless card_number
57
+
58
+ repo_path = ctx[:project_config]&.dig("repo_path") || Dir.pwd
59
+ snippet = ctx[:snippet]
60
+ body = "<p>💥 <strong>#{ctx[:agent_name]} crashed</strong> (exit code #{ctx[:exit_status]})</p>" \
61
+ "<p>Log: <code>#{ctx[:log_file]}</code></p>"
62
+ if snippet
63
+ escaped = snippet[-1500..].to_s.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
64
+ body += "<pre>#{escaped}</pre>"
65
+ end
66
+
67
+ env = Helpers.fizzy_env_for(ctx[:agent_name])
68
+ run_cmd("fizzy", "comment", "create", "--card", card_number.to_s, "--body", body,
69
+ chdir: repo_path, env: env)
70
+ LOG.info "[Fizzy] Posted crash comment on card ##{card_number}" if defined?(LOG)
71
+
72
+ :fizzy # Signal that we handled this source
73
+ rescue StandardError => e
74
+ LOG.error "[Fizzy] Failed to post crash comment: #{e.message}" if defined?(LOG)
75
+ nil
76
+ end
77
+ end
78
+
79
+ # Before agent dispatch — copy .fizzy.yaml and clean attachments
80
+ def register_pre_dispatch
81
+ Brainiac.on(:pre_dispatch) do |ctx|
82
+ Helpers.ensure_fizzy_yaml!(ctx[:chdir], ctx[:project_config])
83
+ Thread.new { Helpers.scrub_invalid_attachments!(ctx[:chdir]) }
84
+ end
85
+ end
86
+
87
+ # Brain context building — inject fizzy CLI knowledge when source is fizzy
88
+ def register_brain_context
89
+ Brainiac.on(:build_brain_context) do |ctx|
90
+ fizzy_relevant = ctx[:source] == :fizzy ||
91
+ [ctx[:card_title], ctx[:comment_body]].any? { |s| s&.match?(/fizzy/i) }
92
+ fizzy_relevant ? ["fizzy CLI commands"] : []
93
+ end
94
+ end
95
+
96
+ # PR merged — post comment on Fizzy card, move to UAT, dispatch UAT agent
97
+ def register_pr_merged
98
+ Brainiac.on(:pr_merged) do |ctx|
99
+ card_number = ctx[:card_number]
100
+ next unless card_number
101
+
102
+ card_info = ctx[:card_info]
103
+ card_agent = card_info["agent"]
104
+ env = Helpers.fizzy_env_for(card_agent)
105
+ repo_path = ctx[:repo_path]
106
+
107
+ # Post PR link comment
108
+ pr_url = ctx[:pr_url]
109
+ pr_title = ctx[:pr_title]
110
+ branch = ctx[:branch]
111
+ comment_body = "<p>PR merged into main: <a href=\"#{pr_url}\">#{pr_title}</a></p>" \
112
+ "<p>Branch: <code>#{branch}</code></p>"
113
+ run_cmd("fizzy", "comment", "create", "--card", card_number.to_s, "--body", comment_body,
114
+ chdir: repo_path, env: env)
115
+
116
+ # Move card to UAT
117
+ Helpers.move_card_to_column(card_number, "uat",
118
+ project_config: ctx[:project_config],
119
+ agent_name: card_agent)
120
+ record_self_move(card_number)
121
+
122
+ # Clear deployment tracking
123
+ clear_deployment_for_card(card_number) if respond_to?(:clear_deployment_for_card)
124
+
125
+ # Dispatch UAT agent
126
+ dispatch_fizzy_uat_agent(ctx)
127
+ rescue StandardError => e
128
+ LOG.error "[Fizzy] Error in pr_merged hook: #{e.message}" if defined?(LOG)
129
+ end
130
+ end
131
+
132
+ # PR review received — post status comment on card
133
+ def register_pr_review_received
134
+ Brainiac.on(:pr_review_received) do |ctx|
135
+ card_number = ctx[:card_number]
136
+ next unless card_number
137
+
138
+ Thread.new do
139
+ env = Helpers.fizzy_env_for(ctx[:agent_name])
140
+ status_comment = "<p>🔄 Code review received from @#{ctx[:reviewer]}. Updates in progress...</p>"
141
+ run_cmd("fizzy", "comment", "create", "--card", card_number.to_s, "--body", status_comment,
142
+ chdir: ctx[:repo_path], env: env)
143
+ rescue StandardError => e
144
+ LOG.warn "[Fizzy] Could not post review status: #{e.message}" if defined?(LOG)
145
+ end
146
+ end
147
+ end
148
+
149
+ # Production deployed — close UAT cards
150
+ def register_production_deployed
151
+ Brainiac.on(:production_deployed) do |ctx|
152
+ project_config = ctx[:project_config]
153
+ repo_path = project_config["repo_path"]
154
+ board_key = Config.board_key_for_project(project_config)
155
+ next [] unless board_key
156
+
157
+ uat_col = Config.board_column_id(board_key, "uat")
158
+ next [] unless uat_col
159
+
160
+ env = Helpers.default_fizzy_env
161
+ output = run_cmd("fizzy", "card", "list", "--column", uat_col, "--all",
162
+ chdir: repo_path, env: env)
163
+ card_list = JSON.parse(output)["data"] || []
164
+ next [] if card_list.empty?
165
+
166
+ closed = close_uat_cards(card_list, repo_path)
167
+ closed
168
+ rescue StandardError => e
169
+ LOG.error "[Fizzy] Error closing UAT cards: #{e.message}" if defined?(LOG)
170
+ []
171
+ end
172
+ end
173
+
174
+ # Create work item (from Zoho triage) — create a Fizzy card
175
+ def register_create_work_item
176
+ Brainiac.on(:create_work_item) do |ctx|
177
+ board_id = ctx[:board_id]
178
+ title = ctx[:title]
179
+ description = ctx[:description]
180
+ tags = ctx[:tags] || []
181
+ assign_to = ctx[:assign_to]
182
+
183
+ # Resolve tag IDs
184
+ agent_env = agent_env_for("Threepio")
185
+ spawn_env = agent_env.empty? ? {} : agent_env
186
+ tag_ids = resolve_tag_ids(tags, spawn_env)
187
+
188
+ cmd = ["fizzy", "card", "create", "--board", board_id, "--title", title, "--description", description]
189
+ cmd.push("--tag-ids", tag_ids.join(",")) unless tag_ids.empty?
190
+
191
+ output, status = Open3.capture2e(spawn_env, *cmd)
192
+ next nil unless status.success?
193
+
194
+ card_data = JSON.parse(output)
195
+ card_number = card_data.dig("data", "number")
196
+
197
+ # Assign if requested
198
+ assign_card(card_number, assign_to, spawn_env) if card_number && assign_to
199
+
200
+ { number: card_number, url: card_data.dig("data", "url"), title: title }
201
+ rescue StandardError => e
202
+ LOG.error "[Fizzy] Failed to create card: #{e.message}" if defined?(LOG)
203
+ nil
204
+ end
205
+ end
206
+
207
+ # --- Private helpers ---
208
+
209
+ def dispatch_fizzy_uat_agent(ctx)
210
+ card_number = ctx[:card_number]
211
+ card_info = ctx[:card_info]
212
+ project_config = ctx[:project_config]
213
+ project_key = ctx[:project_key]
214
+ repo_path = ctx[:repo_path]
215
+
216
+ agent_name = card_info["agent"] || agent_name_for(project_config)
217
+ card_title = card_info["title"] || ctx[:pr_title]
218
+
219
+ prompt = render_prompt(Prompts::UAT_TESTING,
220
+ { "CARD_NUMBER" => card_number, "CARD_TITLE" => card_title,
221
+ "PR_NUMBER" => ctx[:pull_request]["number"].to_s },
222
+ brain_context: build_brain_context(agent_name: agent_name, card_number: card_number,
223
+ card_title: card_title, project_key: project_key),
224
+ agent_name: agent_name, channel: :fizzy,
225
+ board_key: Config.board_key_for_project(project_config))
226
+
227
+ pid, log_file = run_agent(prompt, project_config: project_config, chdir: repo_path,
228
+ log_name: "uat-#{card_number}", agent_name: agent_name,
229
+ source: :fizzy, source_context: { card_number: card_number }, skip_column_move: true)
230
+ register_session("card-#{card_number}", pid, log_file: log_file, agent_name: agent_name)
231
+ LOG.info "[Fizzy] Dispatched #{agent_name} for UAT on card ##{card_number}" if defined?(LOG)
232
+ rescue StandardError => e
233
+ LOG.error "[Fizzy] Failed to dispatch UAT agent: #{e.message}" if defined?(LOG)
234
+ end
235
+
236
+ def close_uat_cards(card_list, repo_path)
237
+ closed = []
238
+ map = load_work_item_map
239
+
240
+ card_list.each do |card|
241
+ card_number = card["number"]
242
+ next unless card_number
243
+
244
+ map_entry = map.values.find { |info| info["number"] == card_number }
245
+ agent_name = map_entry["agent"] if map_entry
246
+ env = Helpers.fizzy_env_for(agent_name || AI_AGENT_NAME)
247
+
248
+ run_cmd("fizzy", "comment", "create", "--card", card_number.to_s,
249
+ "--body", "<p>✅ Deployed to production. Closing card.</p>", chdir: repo_path, env: env)
250
+ run_cmd("fizzy", "card", "close", card_number.to_s, chdir: repo_path, env: env)
251
+
252
+ cleanup_work_item_worktrees(card_number, repo_path: repo_path,
253
+ primary_worktree: map_entry&.dig("worktree"), primary_branch: map_entry&.dig("branch"))
254
+
255
+ if map_entry
256
+ internal_id = map.key(map_entry)
257
+ map.delete(internal_id)
258
+ end
259
+
260
+ closed << { number: card_number, url: card["url"], title: card["title"] }
261
+ end
262
+
263
+ save_work_item_map(map) if closed.any?
264
+ closed
265
+ end
266
+
267
+ def resolve_tag_ids(tag_names, spawn_env)
268
+ output, status = Open3.capture2e(spawn_env, "fizzy", "tag", "list", "--all")
269
+ return [] unless status.success?
270
+
271
+ all_tags = JSON.parse(output)["data"] || []
272
+ tag_names.filter_map do |name|
273
+ tag = all_tags.find { |t| t["title"].downcase == name.downcase }
274
+ tag&.dig("id")
275
+ end
276
+ rescue StandardError
277
+ []
278
+ end
279
+
280
+ def assign_card(card_number, agent_name, spawn_env)
281
+ users = Config.current["authorized_users"] || []
282
+ user = users.find { |u| u["name"]&.downcase == agent_name.downcase }
283
+ return unless user
284
+
285
+ Open3.capture2e(spawn_env, "fizzy", "card", "assign", card_number.to_s, "--user", user["id"])
286
+ end
287
+
288
+ # Server started — run card index backfill
289
+ def register_server_started
290
+ Brainiac.on(:server_started) do
291
+ if defined?(CARD_INDEX)
292
+ LOG.info "[Fizzy:CardIndex] Starting background backfill..."
293
+ CARD_INDEX.backfill
294
+ end
295
+ end
296
+ end
297
+
298
+ # Detect CLI provider from Fizzy card tags (e.g., cli-grok tag)
299
+ def register_detect_cli_provider
300
+ Brainiac.on(:detect_cli_provider) do |ctx|
301
+ tags = ctx[:tags] || []
302
+ result = nil
303
+ tags.each do |tag|
304
+ name = (tag.is_a?(Hash) ? tag["name"] : tag).to_s.downcase
305
+ if name.start_with?("cli-")
306
+ result = name.sub("cli-", "")
307
+ break
308
+ end
309
+ end
310
+ result
311
+ end
312
+ end
313
+
314
+ # Detect effort level from Fizzy card tags (e.g., effort-high tag)
315
+ def register_detect_effort
316
+ Brainiac.on(:detect_effort) do |ctx|
317
+ tags = ctx[:tags] || []
318
+ allowed = ctx[:allowed] || []
319
+ result = nil
320
+ tags.each do |tag|
321
+ name = (tag.is_a?(Hash) ? tag["name"] : tag).to_s.downcase
322
+ next unless name.start_with?("effort-")
323
+
324
+ level = name.sub("effort-", "")
325
+ if allowed.include?(level)
326
+ result = level
327
+ break
328
+ end
329
+ end
330
+ result
331
+ end
332
+ end
333
+
334
+ # PR synchronized — handle auto-deploy if card is on a deploy env
335
+ def register_pr_synchronized
336
+ Brainiac.on(:pr_synchronized) do |ctx|
337
+ next unless defined?(DEPLOYMENTS_CONFIG)
338
+
339
+ card_number = ctx[:card_number]
340
+ worktree = ctx[:worktree]
341
+ next unless worktree && File.directory?(worktree)
342
+
343
+ state = load_deployment_state
344
+ config = DEPLOYMENTS_CONFIG["environments"] || {}
345
+ env_key = state.find { |_k, v| v["card_number"] == card_number && v["status"] == "occupied" }&.first
346
+ next unless env_key
347
+
348
+ env_owner = config.dig(env_key, "owner")
349
+ next unless env_owner && env_owner.downcase == AI_AGENT_NAME.downcase
350
+ next if on_deploy_cooldown?(env_key)
351
+
352
+ touch_deploy_cooldown(env_key)
353
+ system("git", "pull", "--ff-only", chdir: worktree)
354
+
355
+ deploy_script = File.join(worktree, "scripts", "deploy.sh")
356
+ next unless File.exist?(deploy_script)
357
+
358
+ LOG.info "[Fizzy:Deploy] Auto-deploying card ##{card_number} to #{env_key} (PR updated)"
359
+ mark_deploying(env_key, worktree_path: worktree)
360
+ run_pr_sync_deploy(env_key, card_number, worktree, config)
361
+ true
362
+ rescue StandardError => e
363
+ LOG.error "[Fizzy:Deploy] PR sync deploy error: #{e.message}" if defined?(LOG)
364
+ nil
365
+ end
366
+ end
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brainiac
4
+ module Plugins
5
+ module Fizzy
6
+ # Planning mode — generates plans from agent sessions and creates Fizzy steps.
7
+ module Planning
8
+ PLANS_DIR = File.join(
9
+ ENV.fetch("BRAINIAC_DIR", File.join(Dir.home, ".brainiac")),
10
+ "plans"
11
+ )
12
+
13
+ class << self
14
+ # Called from :agent_completed hook after session finishes.
15
+ # Checks if a plan file was produced and creates Fizzy steps from it.
16
+ def finalize_if_needed(prompt_file, agent_name, project_config)
17
+ return unless prompt_file && File.exist?(prompt_file)
18
+
19
+ prompt_content = File.read(prompt_file)
20
+ card_id_match = prompt_content.match(/CARD_ID.*?(\d+|discord-[\w-]+)/)
21
+ return unless card_id_match
22
+
23
+ card_id = card_id_match[1]
24
+ plan_file = File.join(PLANS_DIR, "card-#{card_id}-plan.md")
25
+ return unless File.exist?(plan_file)
26
+
27
+ LOG.info "[Fizzy:Planning] Plan file detected for card #{card_id}, finalizing..." if defined?(LOG)
28
+ finalize_plan(card_id: card_id, agent_name: agent_name, project_config: project_config)
29
+ end
30
+
31
+ def finalize_plan(card_id:, agent_name:, project_config:)
32
+ plan_file = File.join(PLANS_DIR, "card-#{card_id}-plan.md")
33
+ return { success: false, error: "No plan file" } unless File.exist?(plan_file)
34
+
35
+ plan_content = File.read(plan_file)
36
+ tasks = extract_tasks(plan_content)
37
+ return { success: false, error: "No tasks found in plan" } if tasks.empty?
38
+
39
+ card_number = card_id.match?(/^\d+$/) ? card_id.to_i : nil
40
+ return { success: false, error: "No card number" } unless card_number
41
+
42
+ repo_path = project_config["repo_path"]
43
+ env = Helpers.fizzy_env_for(agent_name || AI_AGENT_NAME)
44
+
45
+ tasks.each do |task_title|
46
+ run_cmd("fizzy", "step", "create", "--card", card_number.to_s, "--content", task_title,
47
+ chdir: repo_path, env: env)
48
+ end
49
+
50
+ LOG.info "[Fizzy:Planning] Created #{tasks.size} steps for card ##{card_number}" if defined?(LOG)
51
+ { success: true, tasks: tasks }
52
+ rescue StandardError => e
53
+ LOG.error "[Fizzy:Planning] Failed to finalize plan: #{e.message}" if defined?(LOG)
54
+ { success: false, error: e.message }
55
+ end
56
+
57
+ private
58
+
59
+ def extract_tasks(plan_content)
60
+ tasks = []
61
+ plan_content.each_line do |line|
62
+ if line.match?(/^###\s+Task\s+\d+/)
63
+ title = line.sub(/^###\s+Task\s+\d+:\s*/, "").strip
64
+ tasks << title unless title.empty?
65
+ end
66
+ end
67
+ tasks
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brainiac
4
+ module Plugins
5
+ module Fizzy
6
+ # Fizzy-specific prompt constants.
7
+ # Registered with core via Brainiac.register_channel_prompt(:fizzy, ...).
8
+ module Prompts
9
+ CHANNEL = <<~PROMPT
10
+ ## Fizzy Channel Rules
11
+
12
+ ### Standard Procedure
13
+ - If you have questions, ask them in the card's comments.
14
+ - Only assign a fizzy card if it is currently unassigned and you are requested to work on it.
15
+
16
+ ### Column Transitions
17
+ Brainiac handles column moves automatically — do NOT move cards between columns yourself.
18
+ Cards move to "Right Now" when you're dispatched and to "Needs Review" when your session ends.
19
+
20
+ ### Formatting
21
+ **Fizzy comments use HTML, NOT Markdown.** Use `<h2>`/`<h3>` for sections, `<p>` for paragraphs, `<ul><li>` for lists, `<pre data-language="ruby">` for code blocks, `<strong>` for emphasis. Never use markdown syntax in Fizzy comments.
22
+
23
+ ### Screenshots (MANDATORY for UI changes)
24
+ If you touched any `.js`, `.jsx`, `.css`, or `.html` in a web app directory and `./scripts/screenshot-page.sh` exists, screenshot every affected page.
25
+
26
+ ### Retrieving Full Comment Text
27
+ If you need the full text of a truncated comment, run: `fizzy comment show COMMENT_ID --card CARD_NUMBER`
28
+
29
+ ### Card Memory Discipline (CRITICAL for long-running cards)
30
+ When writing your memory file for a Fizzy card session, include:
31
+ - The original card scope/requirements
32
+ - Any scope changes from comments
33
+ - Any card body edits detected during pre-post check
34
+ - The current scope/focus as of this session
35
+ PROMPT
36
+
37
+ PRE_POST_CHECK = <<~PROMPT
38
+ ## Pre-Post Comment Check (MANDATORY — do this BEFORE posting your comment)
39
+
40
+ Re-fetch the card to see if anything changed while you were working:
41
+
42
+ ```bash
43
+ fizzy card show {{CARD_NUMBER}}
44
+ fizzy comment list --card {{CARD_NUMBER}}
45
+ ```
46
+
47
+ Compare against the card context from the start of your session. Check for:
48
+ - Card body changes (new acceptance criteria, clarified scope)
49
+ - New comments (requirements changes, adjustments, new context)
50
+
51
+ If nothing changed, proceed normally.
52
+ PROMPT
53
+
54
+ CARD_ASSIGNED = <<~'PROMPT'
55
+ You have been assigned Fizzy card #{{CARD_NUMBER}}: "{{CARD_TITLE}}".
56
+ You are on branch "{{BRANCH}}" in a fresh worktree.
57
+ Implement the task, commit, push, and open a PR (link back to Fizzy).
58
+ When you're done, post a comment on the card with a concise summary, PR link, and branch name.
59
+
60
+ **MANDATORY: Always include the branch name in your comment.** Use this format:
61
+ `<p><strong>Branch:</strong> <code>{{BRANCH}}</code></p>`
62
+ PROMPT
63
+
64
+ FOLLOWUP_WORKTREE = <<~'PROMPT'
65
+ There's a new comment on Fizzy card #{{CARD_NUMBER}} that you've already started working on.
66
+ You are in the existing worktree for this card.
67
+
68
+ The comment from {{COMMENT_CREATOR}} (comment ID: {{COMMENT_ID}}):
69
+ """
70
+ {{COMMENT_BODY}}
71
+ """
72
+
73
+ Focus your response on the comment above. If you've already addressed this in a previous session, reply confirming it's done.
74
+ Otherwise, make the requested changes, commit, push, and update the PR.
75
+ PROMPT
76
+
77
+ FOLLOWUP_NO_WORKTREE = <<~PROMPT
78
+ There's a new comment on a Fizzy card (internal_id: "{{CARD_INTERNAL_ID}}").
79
+
80
+ The comment from {{COMMENT_CREATOR}} (comment ID: {{COMMENT_ID}}):
81
+ """
82
+ {{COMMENT_BODY}}
83
+ """
84
+
85
+ Focus your response on the comment above. If you've already addressed this, reply confirming it's done.
86
+ Otherwise, respond accordingly.
87
+ PROMPT
88
+
89
+ MENTION = <<~PROMPT
90
+ You were mentioned in a comment on a Fizzy card with internal_id "{{CARD_INTERNAL_ID}}"{{CARD_NUMBER_TEXT}}.
91
+ You are on branch "{{BRANCH}}" in a dedicated worktree.
92
+
93
+ Investigate the codebase and respond accordingly.
94
+ PROMPT
95
+
96
+ CROSS_AGENT_REVIEW = <<~'PROMPT'
97
+ You were tagged in a comment on Fizzy card #{{CARD_NUMBER}} (internal_id: "{{CARD_INTERNAL_ID}}").
98
+ This card is being worked on by {{CARD_AGENT}} — you're being brought in for your perspective.
99
+
100
+ The comment from {{COMMENT_CREATOR}} (comment ID: {{COMMENT_ID}}):
101
+ """
102
+ {{COMMENT_BODY}}
103
+ """
104
+
105
+ You are in your own worktree at `{{WORKTREE_PATH}}` on branch `{{BRANCH}}`.
106
+ Respond to what's being asked — code review, opinion, debugging help, or sanity check.
107
+
108
+ **IMPORTANT: Do NOT @mention any other agents in your response.**
109
+ PROMPT
110
+
111
+ UAT_TESTING = <<~'PROMPT'
112
+ PR for card #{{CARD_NUMBER}} ("{{CARD_TITLE}}") has been merged to main (PR #{{PR_NUMBER}}).
113
+ Run any UAT testing steps defined in the card or acceptance criteria.
114
+ Post results as a comment on the card.
115
+ PROMPT
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brainiac
4
+ module Plugins
5
+ module Fizzy
6
+ VERSION = "0.0.1"
7
+ end
8
+ end
9
+ end