brainiac-fizzy 0.0.29 → 0.0.30

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: 93dfc73c8a3984f834883fbc59057446f220cf640ef14feecdc3882eab0f5e79
4
- data.tar.gz: 16dccf767e981ab8b7ec4f4c9ad570a6af713fe9deb410f0e3163f8745def891
3
+ metadata.gz: 8e54fe3a10cd6e39be3f52862b1625e2532be592e5480c11f685423910a75b91
4
+ data.tar.gz: 77cc0b0ce8a518bde93484bf8513f538f9a26f4412479556d80f83de3ae5c545
5
5
  SHA512:
6
- metadata.gz: dfabf4b7239f9fa9181fb327c24660e7c39c0a1558151362330ff67c8c334ba9565239e5da35c1335c67bd5dfdd246cacf8295509e6e61c86b9afb0f2f6be43d
7
- data.tar.gz: ebafbeceb274b07e70f23f69d8b7123af573d646e58d92eb756b693bf2cf4d87a12ab7fc79ddca3ced785c54d3beca9c8c602a4c655d0158067cc952d441a90f
6
+ metadata.gz: 71c5abb12093956521a3ebdf78566d416d1c3ed33293d6c402a5236462b524042af9a259a3cda7fbf1930c80b93e7be68462952aed0f61393a1eb84b055a851a
7
+ data.tar.gz: 1ecc72a231ccef4c9fadbc279fe561628fda23151aad9b8b64afd65cd151d7ec612d95c25daa008958176b0e922b582602689f6c0754a0474643a4216131055c
@@ -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
@@ -194,8 +194,13 @@ end
194
194
  #
195
195
  # `belt g environment` is synchronous so the worktree is configured before the
196
196
  # agent starts. The actual `belt deploy` runs in the background.
197
+ #
198
+ # When `force: true`, the `deploy` tag requirement is bypassed — the caller is
199
+ # explicitly requesting env setup (e.g. the `brainiac fizzy env setup` CLI or
200
+ # the `/api/fizzy/ephemeral-env/:card` endpoint), so no tag is needed.
197
201
  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)
202
+ repo_path: nil, agent_name: nil, fetch_live_tags: false,
203
+ force: false)
199
204
  unless defined?(BeltConfig) && defined?(BeltEnvironment)
200
205
  LOG.debug "[EphemeralEnv] Belt utilities not available — skipping"
201
206
  return
@@ -216,14 +221,16 @@ def maybe_create_ephemeral_belt_env(worktree_path:, card_number:, project_key:,
216
221
  return
217
222
  end
218
223
 
219
- resolved_tags = resolve_ephemeral_env_tags(
220
- tags, card_number: card_number, repo_path: repo_path || worktree_path,
221
- agent_name: agent_name, fetch_live_tags: fetch_live_tags
222
- )
223
- tag_list = tag_names(resolved_tags)
224
- unless tag_list.include?("deploy")
225
- LOG.debug "[EphemeralEnv] Card ##{card_number} tags=#{tag_list.inspect} — no deploy tag, skipping"
226
- return
224
+ unless force
225
+ resolved_tags = resolve_ephemeral_env_tags(
226
+ tags, card_number: card_number, repo_path: repo_path || worktree_path,
227
+ agent_name: agent_name, fetch_live_tags: fetch_live_tags
228
+ )
229
+ tag_list = tag_names(resolved_tags)
230
+ unless tag_list.include?("deploy")
231
+ LOG.debug "[EphemeralEnv] Card ##{card_number} tags=#{tag_list.inspect} — no deploy tag, skipping"
232
+ return
233
+ end
227
234
  end
228
235
 
229
236
  parent_env = BeltConfig.parent_env_for(project_key)
@@ -266,6 +273,75 @@ def ensure_ephemeral_env_for_comment(ctx, card_number, worktree)
266
273
  )
267
274
  end
268
275
 
276
+ # Manually set up an ephemeral Belt env for a card that was already worked,
277
+ # without dispatching an agent. Resolves the card's existing worktree from the
278
+ # work item map, configures + deploys the env synchronously, and tracks it in
279
+ # ephemeral_envs.json so PR-update auto-redeploys (brainiac-github) work.
280
+ #
281
+ # Bypasses the `deploy` tag requirement (force: true) — the caller is asking
282
+ # for this explicitly. Returns a result hash suitable for a JSON API response.
283
+ #
284
+ # @param card_number [Integer, String] Fizzy card number
285
+ # @return [Hash] { status:, env:, url:, worktree:, reason: }
286
+ def setup_ephemeral_env_for_card(card_number)
287
+ return { status: "error", reason: "card_number required" } unless card_number
288
+
289
+ unless defined?(BeltConfig) && defined?(BeltEnvironment)
290
+ return { status: "error", reason: "Belt utilities not available" }
291
+ end
292
+
293
+ card_number = card_number.to_s
294
+ entry = work_item_entry_for_card(card_number)
295
+ return { status: "error", reason: "no work item found for card ##{card_number}" } unless entry
296
+
297
+ worktree = entry["worktree"]
298
+ 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
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
 
@@ -3,7 +3,7 @@
3
3
  module Brainiac
4
4
  module Plugins
5
5
  module Fizzy
6
- VERSION = "0.0.29"
6
+ VERSION = "0.0.30"
7
7
  end
8
8
  end
9
9
  end
@@ -103,8 +103,7 @@ module Brainiac
103
103
  end
104
104
 
105
105
  # Card index API (duplicate detection)
106
- app.get "/api/card-index" do
107
- content_type :json
106
+ app.get "/api/card-index" do content_type :json
108
107
  halt 404, { error: "Card index not available" }.to_json unless defined?(CARD_INDEX)
109
108
 
110
109
  query = params["q"]
@@ -116,6 +115,21 @@ module Brainiac
116
115
  end
117
116
  end
118
117
 
118
+ # Manually set up an ephemeral Belt env for a card that was already
119
+ # worked — no agent dispatch, no tokens. Configures + deploys the env
120
+ # in the card's existing worktree and tracks it so PR-update
121
+ # auto-redeploys keep it fresh.
122
+ app.post "/api/fizzy/ephemeral-env/:card" do
123
+ content_type :json
124
+ card_number = params["card"]
125
+ result = setup_ephemeral_env_for_card(card_number)
126
+ if result[:status] == "ok"
127
+ result.to_json
128
+ else
129
+ halt 422, result.to_json
130
+ end
131
+ end
132
+
119
133
  # Deployment API routes (if deployments are configured)
120
134
  return unless defined?(DEPLOYMENTS_CONFIG)
121
135
 
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.29
4
+ version: 0.0.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis