brainiac-basecamp 0.0.25 → 0.0.27
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/basecamp/cli.rb +106 -5
- data/lib/brainiac/plugins/basecamp/version.rb +1 -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: cbdbf3cd360b0186167aaf722ffcb20bda8ce915648d1e931bf3da379a2340c7
|
|
4
|
+
data.tar.gz: f0ebcc122d90912c4616e7169852fa4e26ba63919ab9ec85f5b1a50e3269161f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 608ea1521a63273ced78835879fd2477422110a749d161ee3a89d5d83949316ac90ab2484b36cd9ede69d683c8298be28c54e0dce30dd78a3f951c7ce6ac8aa2
|
|
7
|
+
data.tar.gz: 4e0680e96bec2fbc7891938b806b55b2fd8c02ed5c82b788cf3908960217fbe710afa604f18002edfa4b37d15b541e471c5a96f866d8fc0397cb922256ad4aa0
|
|
@@ -839,6 +839,8 @@ module Brainiac
|
|
|
839
839
|
set fizzy-account-id <id> Set Fizzy account ID (for card URLs)
|
|
840
840
|
set review-gate <mode> Set review gate (on_complete or on_pr_merge)
|
|
841
841
|
set epic-prefix <prefix> Set epic todolist prefix (default: "Epic:")
|
|
842
|
+
set ephemeral-deploys <on|off> Enable/disable ephemeral Belt env auto-creation
|
|
843
|
+
set parent-env <project> <env> Set parent env for ephemeral Belt deploys
|
|
842
844
|
reset task <card-number> [--to <status>] Reset a task to a given status (default: pending)
|
|
843
845
|
reset epic <todolist-id> [--to <status>] Reset entire epic or all tasks within it
|
|
844
846
|
reset gates <card-number> Clear gate approvals and re-dispatch gates
|
|
@@ -859,6 +861,18 @@ module Brainiac
|
|
|
859
861
|
4. deploy.project_envs.<project> in config (per-project default)
|
|
860
862
|
5. deploy.default_env in config (global default)
|
|
861
863
|
|
|
864
|
+
Ephemeral Belt Environments:
|
|
865
|
+
When a Fizzy card with 'deploy' tag is assigned to an agent on a Belt app:
|
|
866
|
+
1. Creates ephemeral env: belt g environment fizzy-<card> <parent-env>
|
|
867
|
+
2. Deploys to it: belt deploy fizzy-<card>
|
|
868
|
+
3. Redeploys on PR push: belt deploy fizzy-<card> [frontend]
|
|
869
|
+
4. Destroys on PR merge: belt destroy environment fizzy-<card> --full
|
|
870
|
+
|
|
871
|
+
Configure with:
|
|
872
|
+
brainiac basecamp set ephemeral-deploys on
|
|
873
|
+
brainiac basecamp set parent-env stowzilla dev02
|
|
874
|
+
brainiac basecamp set parent-env feature-parity dev
|
|
875
|
+
|
|
862
876
|
Task statuses (for reset --to):
|
|
863
877
|
pending — Not yet started, waiting for dependencies
|
|
864
878
|
in_flight — Agent is actively working on it
|
|
@@ -872,13 +886,15 @@ module Brainiac
|
|
|
872
886
|
key = args.shift
|
|
873
887
|
value = args.shift
|
|
874
888
|
|
|
875
|
-
unless key
|
|
889
|
+
unless key
|
|
876
890
|
puts "Usage: brainiac basecamp set <key> <value>"
|
|
877
891
|
puts ""
|
|
878
892
|
puts "Keys:"
|
|
879
|
-
puts " fizzy-account-id <id>
|
|
880
|
-
puts " review-gate <mode>
|
|
881
|
-
puts " epic-prefix <prefix>
|
|
893
|
+
puts " fizzy-account-id <id> Fizzy account ID (for card URLs)"
|
|
894
|
+
puts " review-gate <mode> on_complete, on_pr_merge, or epic_branch"
|
|
895
|
+
puts " epic-prefix <prefix> Todolist prefix for epic detection"
|
|
896
|
+
puts " ephemeral-deploys <on|off> Enable/disable ephemeral Belt env deploys"
|
|
897
|
+
puts " parent-env <project> <env> Set parent env for ephemeral deploys"
|
|
882
898
|
return
|
|
883
899
|
end
|
|
884
900
|
|
|
@@ -886,11 +902,19 @@ module Brainiac
|
|
|
886
902
|
|
|
887
903
|
case key
|
|
888
904
|
when "fizzy-account-id"
|
|
905
|
+
unless value
|
|
906
|
+
puts "Usage: brainiac basecamp set fizzy-account-id <id>"
|
|
907
|
+
return
|
|
908
|
+
end
|
|
889
909
|
config["fizzy_account_id"] = value
|
|
890
910
|
save_config(config)
|
|
891
911
|
puts "✓ Set fizzy_account_id = #{value}"
|
|
892
912
|
puts " Card URLs will be: https://app.fizzy.do/#{value}/cards/NNNN"
|
|
893
913
|
when "review-gate"
|
|
914
|
+
unless value
|
|
915
|
+
puts "Usage: brainiac basecamp set review-gate <mode>"
|
|
916
|
+
return
|
|
917
|
+
end
|
|
894
918
|
unless %w[on_complete on_pr_merge epic_branch].include?(value)
|
|
895
919
|
puts "Error: review-gate must be 'on_complete', 'on_pr_merge', or 'epic_branch'"
|
|
896
920
|
return
|
|
@@ -908,18 +932,64 @@ module Brainiac
|
|
|
908
932
|
puts " Epic tasks advance immediately when agent completes"
|
|
909
933
|
end
|
|
910
934
|
when "epic-prefix"
|
|
935
|
+
unless value
|
|
936
|
+
puts "Usage: brainiac basecamp set epic-prefix <prefix>"
|
|
937
|
+
return
|
|
938
|
+
end
|
|
911
939
|
config["epic_prefix"] = value
|
|
912
940
|
save_config(config)
|
|
913
941
|
puts "✓ Set epic_prefix = #{value}"
|
|
914
942
|
when "profile"
|
|
943
|
+
unless value
|
|
944
|
+
puts "Usage: brainiac basecamp set profile <name>"
|
|
945
|
+
return
|
|
946
|
+
end
|
|
915
947
|
config["basecamp_profile"] = value
|
|
916
948
|
save_config(config)
|
|
917
949
|
puts "✓ Set basecamp_profile = #{value}"
|
|
918
950
|
puts " All basecamp CLI commands will use --profile #{value}"
|
|
919
951
|
puts " Set up the profile: basecamp profile create #{value} && basecamp auth login --profile #{value}"
|
|
952
|
+
when "ephemeral-deploys"
|
|
953
|
+
unless value
|
|
954
|
+
puts "Usage: brainiac basecamp set ephemeral-deploys <on|off>"
|
|
955
|
+
return
|
|
956
|
+
end
|
|
957
|
+
enabled = %w[on yes true 1].include?(value.downcase)
|
|
958
|
+
config["deploy"] ||= {}
|
|
959
|
+
config["deploy"]["ephemeral_enabled"] = enabled
|
|
960
|
+
save_config(config)
|
|
961
|
+
puts "✓ Set ephemeral_enabled = #{enabled}"
|
|
962
|
+
if enabled
|
|
963
|
+
puts " Ephemeral Belt environments will be created for cards with 'deploy' tag"
|
|
964
|
+
puts " Make sure parent envs are configured: brainiac basecamp set parent-env <project> <env>"
|
|
965
|
+
else
|
|
966
|
+
puts " Ephemeral Belt environment creation is disabled"
|
|
967
|
+
end
|
|
968
|
+
when "parent-env"
|
|
969
|
+
# Special case: takes two values (project and env)
|
|
970
|
+
project_key = value
|
|
971
|
+
parent_env = args.shift
|
|
972
|
+
unless project_key && parent_env
|
|
973
|
+
puts "Usage: brainiac basecamp set parent-env <project-key> <parent-env>"
|
|
974
|
+
puts ""
|
|
975
|
+
puts "Example:"
|
|
976
|
+
puts " brainiac basecamp set parent-env stowzilla dev02"
|
|
977
|
+
puts " brainiac basecamp set parent-env feature-parity dev"
|
|
978
|
+
puts ""
|
|
979
|
+
puts "This sets the parent environment for ephemeral Belt deploys."
|
|
980
|
+
puts "When a card with 'deploy' tag is assigned, an ephemeral environment"
|
|
981
|
+
puts "is created using: belt g environment fizzy-<card> <parent-env>"
|
|
982
|
+
return
|
|
983
|
+
end
|
|
984
|
+
config["deploy"] ||= {}
|
|
985
|
+
config["deploy"]["project_envs"] ||= {}
|
|
986
|
+
config["deploy"]["project_envs"][project_key] = parent_env
|
|
987
|
+
save_config(config)
|
|
988
|
+
puts "✓ Set parent env for '#{project_key}' = #{parent_env}"
|
|
989
|
+
puts " Cards with 'deploy' tag will create: fizzy-<card> from #{parent_env}"
|
|
920
990
|
else
|
|
921
991
|
puts "Unknown key: #{key}"
|
|
922
|
-
puts "Valid keys: fizzy-account-id, review-gate, epic-prefix, profile"
|
|
992
|
+
puts "Valid keys: fizzy-account-id, review-gate, epic-prefix, profile, ephemeral-deploys, parent-env"
|
|
923
993
|
end
|
|
924
994
|
end
|
|
925
995
|
|
|
@@ -986,9 +1056,15 @@ module Brainiac
|
|
|
986
1056
|
# Reset the task
|
|
987
1057
|
reset_task_to(task, target_status)
|
|
988
1058
|
|
|
1059
|
+
# If completing this task leaves every task in the epic complete,
|
|
1060
|
+
# seal the epic in the same atomic write so the reconcile loop never
|
|
1061
|
+
# re-fires the completion notification.
|
|
1062
|
+
finalized = finalize_epic_if_all_complete!(epic)
|
|
1063
|
+
|
|
989
1064
|
save_epics(epics)
|
|
990
1065
|
puts "✓ Reset card ##{card_number} from '#{old_status}' → '#{target_status}'"
|
|
991
1066
|
puts " Epic: #{epic['title']}"
|
|
1067
|
+
puts "✓ All tasks complete — epic finalized (status=complete, notification suppressed)" if finalized
|
|
992
1068
|
|
|
993
1069
|
return unless target_status == "pending"
|
|
994
1070
|
|
|
@@ -1096,8 +1172,11 @@ module Brainiac
|
|
|
1096
1172
|
tasks_to_reset.each { |t| reset_task_to(t, target_status) }
|
|
1097
1173
|
epic["updated_at"] = Time.now.iso8601
|
|
1098
1174
|
|
|
1175
|
+
finalized = finalize_epic_if_all_complete!(epic)
|
|
1176
|
+
|
|
1099
1177
|
save_epics(epics)
|
|
1100
1178
|
puts "✓ Reset #{tasks_to_reset.size} task(s) → '#{target_status}' in epic '#{epic['title']}'"
|
|
1179
|
+
puts "✓ All tasks complete — epic finalized (status=complete, notification suppressed)" if finalized
|
|
1101
1180
|
puts ""
|
|
1102
1181
|
epic["tasks"].each do |t|
|
|
1103
1182
|
icon = case t["status"]
|
|
@@ -1169,9 +1248,31 @@ module Brainiac
|
|
|
1169
1248
|
task["awaiting_final_decision"] = true
|
|
1170
1249
|
when "complete"
|
|
1171
1250
|
task["completed_at"] ||= Time.now.iso8601
|
|
1251
|
+
# A completed task is no longer awaiting a final decision. Leaving
|
|
1252
|
+
# this true lets reconcile_final_decision_task treat the task as
|
|
1253
|
+
# unsettled and re-dispatch/re-complete it on the next sweep.
|
|
1254
|
+
task["awaiting_final_decision"] = false
|
|
1172
1255
|
end
|
|
1173
1256
|
end
|
|
1174
1257
|
|
|
1258
|
+
# Seal an epic when a reset leaves every task complete. Without this, an
|
|
1259
|
+
# epic can sit status="active" with all tasks done — exactly the
|
|
1260
|
+
# thrash-prone state where the 90s reconcile loop re-detects "all
|
|
1261
|
+
# complete", re-runs complete_epic, and re-posts the "🎉 Epic completed"
|
|
1262
|
+
# notification on every sweep. Setting completion_notified suppresses a
|
|
1263
|
+
# notification for this manual, operator-driven completion. Returns true
|
|
1264
|
+
# if the epic was finalized.
|
|
1265
|
+
def finalize_epic_if_all_complete!(epic)
|
|
1266
|
+
return false unless epic["tasks"]&.any?
|
|
1267
|
+
return false unless epic["tasks"].all? { |t| t["status"] == "complete" }
|
|
1268
|
+
return false if epic["status"] == "complete"
|
|
1269
|
+
|
|
1270
|
+
epic["status"] = "complete"
|
|
1271
|
+
epic["completed_at"] ||= Time.now.iso8601
|
|
1272
|
+
epic["completion_notified"] = true
|
|
1273
|
+
true
|
|
1274
|
+
end
|
|
1275
|
+
|
|
1175
1276
|
def load_epics
|
|
1176
1277
|
epics_file = File.join(BRAINIAC_DIR, "basecamp_epics.json")
|
|
1177
1278
|
return [] unless File.exist?(epics_file)
|