brainiac-fizzy 0.0.30 → 0.0.32
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/handlers/assignment.rb +20 -11
- data/lib/brainiac/plugins/fizzy/handlers/comments.rb +8 -3
- data/lib/brainiac/plugins/fizzy/handlers/deployments.rb +39 -0
- data/lib/brainiac/plugins/fizzy/version.rb +1 -1
- data/lib/brainiac/plugins/fizzy.rb +2 -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: 7db11f41fae35db895516e80e9de7e4c8c058523bd8bcc11b5b6a64b00462c41
|
|
4
|
+
data.tar.gz: 8cff0f7ca421e7ca5a20344a83f0f89a0a6cce4102f2daa5cc5d4fc5c2f1a2ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 66bb5070c162be023a3ed046e9748f4fdf1197841aeb47a07c8b660e3759a48aa01773b587edb68bd762f6ab863280c44578f3ba1cc4c654e4fc9ce74946ccac
|
|
7
|
+
data.tar.gz: 9232d4131f5298d4a3e9190c39c360e0a02296ad05b40dacf12be5b64599517af001b94c56bbd9b032fcfafc89b004e6800f6a2a6372868e20e8dc74da5cd996
|
|
@@ -47,8 +47,11 @@ def handle_card_assigned(payload, board_key: nil)
|
|
|
47
47
|
worktree_path = setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, project_key, assigned_agent, board_key: board_key)
|
|
48
48
|
|
|
49
49
|
initial_cli = detect_cli_provider(tags: tags)
|
|
50
|
-
initial_model =
|
|
50
|
+
initial_model, initial_model_explicit = detect_model_explicit(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,8 @@ 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,
|
|
73
|
+
explicit_model: initial_model_explicit
|
|
70
74
|
)
|
|
71
75
|
end
|
|
72
76
|
|
|
@@ -136,7 +140,8 @@ def setup_assigned_worktree(repo_path, branch, card_internal_id, card_number, pr
|
|
|
136
140
|
end
|
|
137
141
|
|
|
138
142
|
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:,
|
|
143
|
+
project_config:, project_key:, agent_name:, model:, effort:, cli_provider_override:,
|
|
144
|
+
profile: nil, board_key: nil, explicit_model: nil)
|
|
140
145
|
card_context = prefetch_card_context(card_number, repo_path: project_config["repo_path"], agent_name: agent_name)
|
|
141
146
|
planning_info = detect_planning_mode(text: title, tags: tags, card_internal_id: card_internal_id, card_number: card_number)
|
|
142
147
|
|
|
@@ -180,7 +185,8 @@ def dispatch_assigned_card(card_number:, card_internal_id:, title:, tags:, branc
|
|
|
180
185
|
log_name: "assigned-#{card_number}", model: model, effort: effort,
|
|
181
186
|
agent_name: agent_name, card_number: card_number, source: :fizzy,
|
|
182
187
|
source_context: { card_number: card_number, board_key: board_key, dispatched_at: Time.now },
|
|
183
|
-
cli_provider: cli_provider_override, env: agent_github_env
|
|
188
|
+
cli_provider: cli_provider_override, profile: profile, env: agent_github_env,
|
|
189
|
+
explicit_model: explicit_model)
|
|
184
190
|
register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: agent_name)
|
|
185
191
|
|
|
186
192
|
Thread.new { move_card_to_column(card_number, "right_now", project_config: project_config, agent_name: agent_name, board_key: board_key) }
|
|
@@ -286,9 +292,7 @@ end
|
|
|
286
292
|
def setup_ephemeral_env_for_card(card_number)
|
|
287
293
|
return { status: "error", reason: "card_number required" } unless card_number
|
|
288
294
|
|
|
289
|
-
unless defined?(BeltConfig) && defined?(BeltEnvironment)
|
|
290
|
-
return { status: "error", reason: "Belt utilities not available" }
|
|
291
|
-
end
|
|
295
|
+
return { status: "error", reason: "Belt utilities not available" } unless defined?(BeltConfig) && defined?(BeltEnvironment)
|
|
292
296
|
|
|
293
297
|
card_number = card_number.to_s
|
|
294
298
|
entry = work_item_entry_for_card(card_number)
|
|
@@ -296,9 +300,7 @@ def setup_ephemeral_env_for_card(card_number)
|
|
|
296
300
|
|
|
297
301
|
worktree = entry["worktree"]
|
|
298
302
|
project_key = entry["project"]
|
|
299
|
-
unless worktree && File.directory?(worktree)
|
|
300
|
-
return { status: "error", reason: "worktree missing for card ##{card_number} (#{worktree.inspect})" }
|
|
301
|
-
end
|
|
303
|
+
return { status: "error", reason: "worktree missing for card ##{card_number} (#{worktree.inspect})" } unless worktree && File.directory?(worktree)
|
|
302
304
|
|
|
303
305
|
env_name = BeltConfig.ephemeral_env_for_card(card_number)
|
|
304
306
|
already = BeltEnvironment.environment_configured?(worktree: worktree, env_name: env_name)
|
|
@@ -390,7 +392,14 @@ def create_and_deploy_ephemeral_env(worktree_path:, env_name:, parent_env:, card
|
|
|
390
392
|
LOG.info "[EphemeralEnv] Configured #{env_name} in worktree, deploying in background"
|
|
391
393
|
|
|
392
394
|
Thread.new do
|
|
393
|
-
|
|
395
|
+
# First provisioning of a fresh env must be a full deploy — it stands up
|
|
396
|
+
# S3/CloudFront/backend. The frontend-only shortcut is only safe once the
|
|
397
|
+
# env is actually live (probe the derived public URL). Otherwise `belt
|
|
398
|
+
# deploy frontend` runs against a bucket that doesn't exist yet and fails
|
|
399
|
+
# with "Could not determine S3 bucket."
|
|
400
|
+
frontend_only =
|
|
401
|
+
ephemeral_env_live?(worktree_path, env_name) &&
|
|
402
|
+
BeltEnvironment.frontend_only_changes?(worktree: worktree_path)
|
|
394
403
|
BeltEnvironment.deploy(worktree: worktree_path, env_name: env_name, frontend_only: frontend_only)
|
|
395
404
|
rescue StandardError => e
|
|
396
405
|
LOG.error "[EphemeralEnv] Error deploying '#{env_name}': #{e.message}"
|
|
@@ -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, :explicit_model,
|
|
22
22
|
keyword_init: true
|
|
23
23
|
)
|
|
24
24
|
|
|
@@ -110,7 +110,7 @@ def build_comment_context(eventable:, plain_text:, tags:, card_internal_id:, car
|
|
|
110
110
|
clean_text = tags[:clean_text]
|
|
111
111
|
|
|
112
112
|
inline_cli = detect_cli_provider(text: plain_text, tags: card_tags)
|
|
113
|
-
inline_model =
|
|
113
|
+
inline_model, inline_model_explicit = detect_model_explicit(project_config, text: plain_text)
|
|
114
114
|
inline_effort = detect_effort(project_config, tags: card_tags, text: plain_text)
|
|
115
115
|
|
|
116
116
|
# Resolve overrides against the work item — merges stored overrides with inline tags
|
|
@@ -141,11 +141,13 @@ def build_comment_context(eventable:, plain_text:, tags:, card_internal_id:, car
|
|
|
141
141
|
board_key: board_key,
|
|
142
142
|
model: effective_model,
|
|
143
143
|
effort: effective_effort,
|
|
144
|
+
explicit_model: inline_model_explicit,
|
|
144
145
|
deploy_intent: deploy_intent,
|
|
145
146
|
cli_provider_override: effective_cli,
|
|
146
147
|
card_tags: card_tags,
|
|
147
148
|
worktree_override: resolve_worktree_override(tags, project_config),
|
|
148
149
|
fresh: tags[:fresh],
|
|
150
|
+
profile: tags[:profile],
|
|
149
151
|
comment_vars: {
|
|
150
152
|
"COMMENT_CREATOR" => creator_name || "Unknown",
|
|
151
153
|
"COMMENT_ID" => comment_id.to_s,
|
|
@@ -411,7 +413,8 @@ def dispatch_cross_agent_review(ctx, card_key:, card_number:, card_assigned_agen
|
|
|
411
413
|
model: ctx.model, effort: ctx.effort, agent_name: ctx.agent_name,
|
|
412
414
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
413
415
|
source: :fizzy, source_context: { card_number: card_number, dispatched_at: Time.now },
|
|
414
|
-
cli_provider: ctx.cli_provider_override
|
|
416
|
+
cli_provider: ctx.cli_provider_override, profile: ctx.profile,
|
|
417
|
+
explicit_model: ctx.explicit_model)
|
|
415
418
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
416
419
|
|
|
417
420
|
register_session(card_key, pid, log_file: log_file, supersede_key: card_key, agent_name: ctx.agent_name)
|
|
@@ -525,6 +528,7 @@ def dispatch_new_mention(ctx, card_key:, card_number:, card_title:, branch:, wor
|
|
|
525
528
|
model: ctx.model, effort: ctx.effort, agent_name: ctx.agent_name,
|
|
526
529
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
527
530
|
source: :fizzy, cli_provider: ctx.cli_provider_override,
|
|
531
|
+
profile: ctx.profile, explicit_model: ctx.explicit_model,
|
|
528
532
|
source_context: { card_number: card_number, dispatched_at: Time.now })
|
|
529
533
|
return [200, { status: "dispatch_failed", agent: ctx.agent_name, card: card_number }.to_json] unless pid
|
|
530
534
|
|
|
@@ -563,6 +567,7 @@ def dispatch_followup_comment(ctx, card_key:, card_number:, work_dir:)
|
|
|
563
567
|
model: ctx.model, effort: effort, agent_name: ctx.agent_name,
|
|
564
568
|
card_number: card_number, comment_id: ctx.comment_id,
|
|
565
569
|
source: :fizzy, cli_provider: ctx.cli_provider_override, resume: should_resume,
|
|
570
|
+
profile: ctx.profile, explicit_model: ctx.explicit_model,
|
|
566
571
|
source_context: {
|
|
567
572
|
card_number: card_number, card_internal_id: ctx.card_internal_id,
|
|
568
573
|
deploy_intent: ctx.deploy_intent, board_key: ctx.board_key, dispatched_at: Time.now
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "shellwords"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "uri"
|
|
4
6
|
|
|
5
7
|
# Deployment environment tracking.
|
|
6
8
|
# Tracks which dev environments have active card deploys and which are available.
|
|
@@ -383,3 +385,40 @@ def parse_tfvars(contents)
|
|
|
383
385
|
end
|
|
384
386
|
vars
|
|
385
387
|
end
|
|
388
|
+
|
|
389
|
+
# Is a Belt env's frontend actually live? Derives the public URL from the
|
|
390
|
+
# worktree's infrastructure/<env>/terraform.tfvars and does a HEAD request.
|
|
391
|
+
#
|
|
392
|
+
# This is the honest signal for "already provisioned": a live site means the
|
|
393
|
+
# S3 bucket / CloudFront / backend exist, so the frontend-only deploy shortcut
|
|
394
|
+
# is safe. Anything else (never applied, DNS/CloudFront still propagating,
|
|
395
|
+
# connection refused) reads as not-live and callers should do a full deploy.
|
|
396
|
+
#
|
|
397
|
+
# A false negative during CloudFront/DNS/ACM propagation just triggers a
|
|
398
|
+
# (redundant but harmless) full deploy — never a skipped provisioning step.
|
|
399
|
+
def ephemeral_env_live?(worktree_path, env_name, timeout: 5)
|
|
400
|
+
tfvars = File.join(worktree_path, "infrastructure", env_name, "terraform.tfvars")
|
|
401
|
+
return false unless File.exist?(tfvars)
|
|
402
|
+
|
|
403
|
+
url = ephemeral_url_from_tfvars(tfvars)
|
|
404
|
+
return false unless url
|
|
405
|
+
|
|
406
|
+
frontend_url_live?(url, timeout: timeout)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# HEAD the URL; treat any 2xx/3xx as live. Any error (refused, timeout,
|
|
410
|
+
# NXDOMAIN, TLS failure) means not live. HEAD keeps us from pulling the bundle.
|
|
411
|
+
def frontend_url_live?(url, timeout: 5)
|
|
412
|
+
uri = URI.parse(url)
|
|
413
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
414
|
+
http.use_ssl = (uri.scheme == "https")
|
|
415
|
+
http.open_timeout = timeout
|
|
416
|
+
http.read_timeout = timeout
|
|
417
|
+
|
|
418
|
+
response = http.request_head(uri.request_uri.empty? ? "/" : uri.request_uri)
|
|
419
|
+
code = response.code.to_i
|
|
420
|
+
code >= 200 && code < 400
|
|
421
|
+
rescue StandardError => e
|
|
422
|
+
LOG.info "[Fizzy:Deploy] Frontend probe for #{url} not live: #{e.class}: #{e.message}" if defined?(LOG)
|
|
423
|
+
false
|
|
424
|
+
end
|
|
@@ -103,7 +103,8 @@ module Brainiac
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
# Card index API (duplicate detection)
|
|
106
|
-
app.get "/api/card-index" do
|
|
106
|
+
app.get "/api/card-index" do
|
|
107
|
+
content_type :json
|
|
107
108
|
halt 404, { error: "Card index not available" }.to_json unless defined?(CARD_INDEX)
|
|
108
109
|
|
|
109
110
|
query = params["q"]
|