brainiac-fizzy 0.0.29 → 0.0.31
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99e73a13d858f22832a0b44acfd689e902e3e35dfc416e891792610f13b42d9f
|
|
4
|
+
data.tar.gz: bfc325433038c58471ebe821c9a27b5554e1c73aa3da8f6974813a9af5769233
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69e3d38e6aba9c10c394c2606020981c414a20bdf766712d07faed4ef2c33012cb1f87abd4b60bc6699c5879bd6cefdc555215dcab6af593e7917e6dfa4f1f62
|
|
7
|
+
data.tar.gz: 76c41f2d36849f4226dfb33a1cbf501f223551fccc1831b9baa9eeef7ff2f03ff2020dbb66b07ce4190430c50448981b1c659e9ec51ba38db388dc7f47ba6b8c
|
|
@@ -27,6 +27,8 @@ module Brainiac
|
|
|
27
27
|
cmd_setup
|
|
28
28
|
when "board"
|
|
29
29
|
cmd_board(args)
|
|
30
|
+
when "env"
|
|
31
|
+
cmd_env(args)
|
|
30
32
|
else
|
|
31
33
|
print_help
|
|
32
34
|
end
|
|
@@ -126,6 +128,66 @@ module Brainiac
|
|
|
126
128
|
end
|
|
127
129
|
end
|
|
128
130
|
|
|
131
|
+
# --- ephemeral env management ---
|
|
132
|
+
|
|
133
|
+
# `brainiac fizzy env setup <card_number>`
|
|
134
|
+
#
|
|
135
|
+
# Manually set up (or refresh tracking for) an ephemeral Belt env for a
|
|
136
|
+
# card that was already worked — no agent, no tokens. Once tracked, PR
|
|
137
|
+
# updates auto-redeploy it via brainiac-github.
|
|
138
|
+
def cmd_env(args)
|
|
139
|
+
sub = args.shift
|
|
140
|
+
case sub
|
|
141
|
+
when "setup", "add"
|
|
142
|
+
env_setup(args)
|
|
143
|
+
else
|
|
144
|
+
puts "Usage: brainiac fizzy env setup <card_number>"
|
|
145
|
+
puts ""
|
|
146
|
+
puts "Commands:"
|
|
147
|
+
puts " setup <card_number> Configure + deploy an ephemeral Belt env for a"
|
|
148
|
+
puts " card that was already worked (no agent dispatch)."
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def env_setup(args)
|
|
153
|
+
card_number = args.shift
|
|
154
|
+
if card_number.nil? || card_number.strip.empty?
|
|
155
|
+
puts "Usage: brainiac fizzy env setup <card_number>"
|
|
156
|
+
return
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
require "net/http"
|
|
160
|
+
require "uri"
|
|
161
|
+
|
|
162
|
+
server_url = detect_server_url
|
|
163
|
+
uri = URI("#{server_url}/api/fizzy/ephemeral-env/#{card_number}")
|
|
164
|
+
|
|
165
|
+
puts "Setting up ephemeral env for card ##{card_number} (no agent)..."
|
|
166
|
+
begin
|
|
167
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
168
|
+
http.read_timeout = 600 # belt deploy can be slow
|
|
169
|
+
response = http.post(uri.path, "")
|
|
170
|
+
data = begin
|
|
171
|
+
JSON.parse(response.body)
|
|
172
|
+
rescue StandardError
|
|
173
|
+
{}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
if response.is_a?(Net::HTTPSuccess) && data["status"] == "ok"
|
|
177
|
+
puts "✓ Ephemeral env '#{data["env"]}' ready#{" (was already configured)" if data["already_configured"]}"
|
|
178
|
+
puts " Worktree: #{data["worktree"]}" if data["worktree"]
|
|
179
|
+
puts " URL: #{data["url"]}" if data["url"]
|
|
180
|
+
puts ""
|
|
181
|
+
puts "Tracked in ephemeral_envs.json — PR updates will auto-redeploy it."
|
|
182
|
+
else
|
|
183
|
+
puts "✗ Failed: #{data["reason"] || response.message}"
|
|
184
|
+
end
|
|
185
|
+
rescue StandardError => e
|
|
186
|
+
puts "Could not reach server at #{server_url}: #{e.message}"
|
|
187
|
+
puts "Is the server running? Check with: brainiac status"
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
129
191
|
# --- board setup (split into phases) ---
|
|
130
192
|
|
|
131
193
|
def board_setup
|
|
@@ -629,6 +691,7 @@ module Brainiac
|
|
|
629
691
|
board list List configured boards and their columns
|
|
630
692
|
board assign <project> <board_key> Assign a project to a board
|
|
631
693
|
board columns <board_key> Refresh columns for a board from Fizzy
|
|
694
|
+
env setup <card_number> Set up an ephemeral Belt env for an already-worked card (no agent)
|
|
632
695
|
|
|
633
696
|
Fizzy handles card assignment, comments, @mentions, cross-agent reviews,
|
|
634
697
|
duplicate detection, and planning mode via webhooks.
|
|
@@ -662,11 +725,13 @@ module Brainiac
|
|
|
662
725
|
# When called with args (the words typed so far after the plugin name),
|
|
663
726
|
# returns context-sensitive completions for nested subcommands.
|
|
664
727
|
def self.completions(args = [])
|
|
665
|
-
return %w[board config setup status] if args.empty?
|
|
728
|
+
return %w[board config env setup status] if args.empty?
|
|
666
729
|
|
|
667
730
|
case args[0]
|
|
668
731
|
when "board"
|
|
669
732
|
board_completions(args[1..])
|
|
733
|
+
when "env"
|
|
734
|
+
args.length <= 1 ? %w[setup add] : []
|
|
670
735
|
else
|
|
671
736
|
[]
|
|
672
737
|
end
|
|
@@ -49,6 +49,9 @@ def handle_card_assigned(payload, board_key: nil)
|
|
|
49
49
|
initial_cli = detect_cli_provider(tags: tags)
|
|
50
50
|
initial_model = detect_model(project_config, tags: tags)
|
|
51
51
|
initial_effort = detect_effort(project_config, tags: tags)
|
|
52
|
+
# Profile ([profile:X]/[p:X]) can be specified inline in the card title.
|
|
53
|
+
# It's a named env bundle (e.g. an alternate kiro-cli account) — see core profiles.rb.
|
|
54
|
+
initial_profile = parse_inline_tags(title.to_s)[:profile]
|
|
52
55
|
|
|
53
56
|
# Persist initial overrides from card tags to the work item
|
|
54
57
|
resolve_work_item_overrides(
|
|
@@ -66,7 +69,7 @@ def handle_card_assigned(payload, board_key: nil)
|
|
|
66
69
|
card_number: card_number, card_internal_id: card_internal_id, title: title, tags: tags,
|
|
67
70
|
branch: branch, worktree_path: worktree_path, project_config: project_config, project_key: project_key,
|
|
68
71
|
agent_name: assigned_agent, model: initial_model,
|
|
69
|
-
effort: initial_effort, cli_provider_override: initial_cli, board_key: board_key
|
|
72
|
+
effort: initial_effort, cli_provider_override: initial_cli, profile: initial_profile, board_key: board_key
|
|
70
73
|
)
|
|
71
74
|
end
|
|
72
75
|
|
|
@@ -136,7 +139,8 @@ def setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, pr
|
|
|
136
139
|
end
|
|
137
140
|
|
|
138
141
|
def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branch:, worktree_path:,
|
|
139
|
-
project_config:, project_key:, agent_name:, model:, effort:, cli_provider_override:,
|
|
142
|
+
project_config:, project_key:, agent_name:, model:, effort:, cli_provider_override:,
|
|
143
|
+
profile: nil, board_key: nil)
|
|
140
144
|
card_context = prefetch_card_context(card_number, repo_path: project_config["repo_path"], agent_name: agent_name)
|
|
141
145
|
planning_info = detect_planning_mode(text: title, tags: tags, card_internal_id: card_internal_id, card_number: card_number)
|
|
142
146
|
|
|
@@ -180,7 +184,7 @@ def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branc
|
|
|
180
184
|
log_name: "assigned-#{card_number}", model: model, effort: effort,
|
|
181
185
|
agent_name: agent_name, card_number: card_number, source: :fizzy,
|
|
182
186
|
source_context: { card_number: card_number, board_key: board_key, dispatched_at: Time.now },
|
|
183
|
-
cli_provider: cli_provider_override, env: agent_github_env)
|
|
187
|
+
cli_provider: cli_provider_override, profile: profile, env: agent_github_env)
|
|
184
188
|
register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: agent_name)
|
|
185
189
|
|
|
186
190
|
Thread.new { move_card_to_column(card_number, "right_now", project_config: project_config, agent_name: agent_name, board_key: board_key) }
|
|
@@ -194,8 +198,13 @@ end
|
|
|
194
198
|
#
|
|
195
199
|
# `belt g environment` is synchronous so the worktree is configured before the
|
|
196
200
|
# agent starts. The actual `belt deploy` runs in the background.
|
|
201
|
+
#
|
|
202
|
+
# When `force: true`, the `deploy` tag requirement is bypassed — the caller is
|
|
203
|
+
# explicitly requesting env setup (e.g. the `brainiac fizzy env setup` CLI or
|
|
204
|
+
# the `/api/fizzy/ephemeral-env/:card` endpoint), so no tag is needed.
|
|
197
205
|
def maybe_create_ephemeral_belt_env(worktree_path:, card_number:, project_key:, tags: nil,
|
|
198
|
-
repo_path: nil, agent_name: nil, fetch_live_tags: false
|
|
206
|
+
repo_path: nil, agent_name: nil, fetch_live_tags: false,
|
|
207
|
+
force: false)
|
|
199
208
|
unless defined?(BeltConfig) && defined?(BeltEnvironment)
|
|
200
209
|
LOG.debug "[EphemeralEnv] Belt utilities not available — skipping"
|
|
201
210
|
return
|
|
@@ -216,14 +225,16 @@ def maybe_create_ephemeral_belt_env(worktree_path:, card_number:, project_key:,
|
|
|
216
225
|
return
|
|
217
226
|
end
|
|
218
227
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
unless force
|
|
229
|
+
resolved_tags = resolve_ephemeral_env_tags(
|
|
230
|
+
tags, card_number: card_number, repo_path: repo_path || worktree_path,
|
|
231
|
+
agent_name: agent_name, fetch_live_tags: fetch_live_tags
|
|
232
|
+
)
|
|
233
|
+
tag_list = tag_names(resolved_tags)
|
|
234
|
+
unless tag_list.include?("deploy")
|
|
235
|
+
LOG.debug "[EphemeralEnv] Card ##{card_number} tags=#{tag_list.inspect} — no deploy tag, skipping"
|
|
236
|
+
return
|
|
237
|
+
end
|
|
227
238
|
end
|
|
228
239
|
|
|
229
240
|
parent_env = BeltConfig.parent_env_for(project_key)
|
|
@@ -266,6 +277,71 @@ def ensure_ephemeral_env_for_comment(ctx, card_number, worktree)
|
|
|
266
277
|
)
|
|
267
278
|
end
|
|
268
279
|
|
|
280
|
+
# Manually set up an ephemeral Belt env for a card that was already worked,
|
|
281
|
+
# without dispatching an agent. Resolves the card's existing worktree from the
|
|
282
|
+
# work item map, configures + deploys the env synchronously, and tracks it in
|
|
283
|
+
# ephemeral_envs.json so PR-update auto-redeploys (brainiac-github) work.
|
|
284
|
+
#
|
|
285
|
+
# Bypasses the `deploy` tag requirement (force: true) — the caller is asking
|
|
286
|
+
# for this explicitly. Returns a result hash suitable for a JSON API response.
|
|
287
|
+
#
|
|
288
|
+
# @param card_number [Integer, String] Fizzy card number
|
|
289
|
+
# @return [Hash] { status:, env:, url:, worktree:, reason: }
|
|
290
|
+
def setup_ephemeral_env_for_card(card_number)
|
|
291
|
+
return { status: "error", reason: "card_number required" } unless card_number
|
|
292
|
+
|
|
293
|
+
return { status: "error", reason: "Belt utilities not available" } unless defined?(BeltConfig) && defined?(BeltEnvironment)
|
|
294
|
+
|
|
295
|
+
card_number = card_number.to_s
|
|
296
|
+
entry = work_item_entry_for_card(card_number)
|
|
297
|
+
return { status: "error", reason: "no work item found for card ##{card_number}" } unless entry
|
|
298
|
+
|
|
299
|
+
worktree = entry["worktree"]
|
|
300
|
+
project_key = entry["project"]
|
|
301
|
+
return { status: "error", reason: "worktree missing for card ##{card_number} (#{worktree.inspect})" } unless worktree && File.directory?(worktree)
|
|
302
|
+
|
|
303
|
+
env_name = BeltConfig.ephemeral_env_for_card(card_number)
|
|
304
|
+
already = BeltEnvironment.environment_configured?(worktree: worktree, env_name: env_name)
|
|
305
|
+
|
|
306
|
+
maybe_create_ephemeral_belt_env(
|
|
307
|
+
worktree_path: worktree, card_number: card_number,
|
|
308
|
+
project_key: project_key, force: true
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# After setup, resolve the public URL the same way deployment lookups do.
|
|
312
|
+
url = defined?(deployment_url_for_card) ? (deployment_url_for_card(card_number) || {})[:url] : nil
|
|
313
|
+
|
|
314
|
+
{
|
|
315
|
+
status: "ok",
|
|
316
|
+
env: env_name,
|
|
317
|
+
url: url,
|
|
318
|
+
worktree: worktree,
|
|
319
|
+
already_configured: already
|
|
320
|
+
}
|
|
321
|
+
rescue StandardError => e
|
|
322
|
+
LOG.error "[EphemeralEnv] Manual setup failed for card ##{card_number}: #{e.message}"
|
|
323
|
+
{ status: "error", reason: e.message }
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Resolve the work item entry for a Fizzy card number from work_items.json.
|
|
327
|
+
# Returns a flattened hash with worktree/branch/project or nil.
|
|
328
|
+
def work_item_entry_for_card(card_number)
|
|
329
|
+
map = load_work_item_map
|
|
330
|
+
match = map.values.find do |entry|
|
|
331
|
+
entry.dig("sources", "fizzy", "card_number").to_s == card_number.to_s
|
|
332
|
+
end
|
|
333
|
+
return nil unless match
|
|
334
|
+
|
|
335
|
+
{
|
|
336
|
+
"worktree" => match["worktree"],
|
|
337
|
+
"branch" => match["branch"],
|
|
338
|
+
"project" => match["project"]
|
|
339
|
+
}
|
|
340
|
+
rescue StandardError => e
|
|
341
|
+
LOG.error "[EphemeralEnv] Could not load work item for card ##{card_number}: #{e.message}" if defined?(LOG)
|
|
342
|
+
nil
|
|
343
|
+
end
|
|
344
|
+
|
|
269
345
|
def belt_app_for_ephemeral?(worktree_path)
|
|
270
346
|
return BeltEnvironment.belt_app?(worktree_path) if defined?(BeltEnvironment) && BeltEnvironment.respond_to?(:belt_app?)
|
|
271
347
|
|
|
@@ -18,7 +18,7 @@ CommentContext = Struct.new(
|
|
|
18
18
|
:project_config, :project_key, :card_number, :worktree,
|
|
19
19
|
:model, :effort, :deploy_intent, :cli_provider_override,
|
|
20
20
|
:comment_vars, :card_tags, :worktree_override, :fresh,
|
|
21
|
-
:board_key,
|
|
21
|
+
:board_key, :profile,
|
|
22
22
|
keyword_init: true
|
|
23
23
|
)
|
|
24
24
|
|
|
@@ -146,6 +146,7 @@ def build_comment_context(eventable:, plain_text:, tags:, card_internal_id:, car
|
|
|
146
146
|
card_tags: card_tags,
|
|
147
147
|
worktree_override: resolve_worktree_override(tags, project_config),
|
|
148
148
|
fresh: tags[:fresh],
|
|
149
|
+
profile: tags[:profile],
|
|
149
150
|
comment_vars: {
|
|
150
151
|
"COMMENT_CREATOR" => creator_name || "Unknown",
|
|
151
152
|
"COMMENT_ID" => comment_id.to_s,
|
|
@@ -411,7 +412,7 @@ def dispatch_cross_agent_review(ctx, card_key:, card_number:, card_assigned_agen
|
|
|
411
412
|
model: ctx.model, effort: ctx.effort, agent_name: ctx.agent_name,
|
|
412
413
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
413
414
|
source: :fizzy, source_context: { card_number: card_number, dispatched_at: Time.now },
|
|
414
|
-
cli_provider: ctx.cli_provider_override)
|
|
415
|
+
cli_provider: ctx.cli_provider_override, profile: ctx.profile)
|
|
415
416
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
416
417
|
|
|
417
418
|
register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: ctx.agent_name)
|
|
@@ -525,6 +526,7 @@ def dispatch_new_mention(ctx, card_key:, card_number:, card_title:, branch:, wor
|
|
|
525
526
|
model: ctx.model, effort: ctx.effort, agent_name: ctx.agent_name,
|
|
526
527
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
527
528
|
source: :fizzy, cli_provider: ctx.cli_provider_override,
|
|
529
|
+
profile: ctx.profile,
|
|
528
530
|
source_context: { card_number: card_number, dispatched_at: Time.now })
|
|
529
531
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
530
532
|
|
|
@@ -563,6 +565,7 @@ def dispatch_followup_comment(ctx, card_key:, card_number:, work_dir:)
|
|
|
563
565
|
model: ctx.model, effort: effort, agent_name: ctx.agent_name,
|
|
564
566
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
565
567
|
source: :fizzy, cli_provider: ctx.cli_provider_override, resume: should_resume,
|
|
568
|
+
profile: ctx.profile,
|
|
566
569
|
source_context: {
|
|
567
570
|
card_number: card_number, card_internal_id: ctx.card_internal_id,
|
|
568
571
|
deploy_intent: ctx.deploy_intent, board_key: ctx.board_key, dispatched_at: Time.now
|
|
@@ -116,6 +116,21 @@ module Brainiac
|
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
+
# Manually set up an ephemeral Belt env for a card that was already
|
|
120
|
+
# worked — no agent dispatch, no tokens. Configures + deploys the env
|
|
121
|
+
# in the card's existing worktree and tracks it so PR-update
|
|
122
|
+
# auto-redeploys keep it fresh.
|
|
123
|
+
app.post "/api/fizzy/ephemeral-env/:card" do
|
|
124
|
+
content_type :json
|
|
125
|
+
card_number = params["card"]
|
|
126
|
+
result = setup_ephemeral_env_for_card(card_number)
|
|
127
|
+
if result[:status] == "ok"
|
|
128
|
+
result.to_json
|
|
129
|
+
else
|
|
130
|
+
halt 422, result.to_json
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
119
134
|
# Deployment API routes (if deployments are configured)
|
|
120
135
|
return unless defined?(DEPLOYMENTS_CONFIG)
|
|
121
136
|
|