brainiac 0.0.3 → 0.0.4

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: 1ecf3d562c59eaeb76f9c1e4ceb87f3ed8c1cabb4cc6c3ddc6837e7c38fe4e8d
4
- data.tar.gz: 60abd844fa6877850aaf37f603229beae693d3aa8b8d82194ac378844009e766
3
+ metadata.gz: 3753442d24d4e39a70b7fd537ebb1e62495a826a42d2a52d16311bf300c1fc9c
4
+ data.tar.gz: 4e44dd38c7d78a51a8b2c73884353e5df911b8a6d28550328d6b906e432f0f5d
5
5
  SHA512:
6
- metadata.gz: ab7cd6b237850d08abfb1586a45cbed1e6252196be96a1927e14b1908dab5dd6b992aaeb34a0bfed693fde8c6e296efad10b7ea2974d4daf4fc17aaaea063f5a
7
- data.tar.gz: 06f90d59ed0584c9c1d94a3feac2b5ed3430c39dcc8579d4f1e18100114a8ac5feb7f3d0d1da74a128a6506da735a5b626bb072cc4457a67aa68dfe7cb196cb4
6
+ metadata.gz: 5dda943f8c6f67ff425ab6850d11e0b131c190441a5f52f1415b39cc42947a00756f19e6416b503a0b6c3f9229eb0dc4ac1cd4a987b0758d373e0be220ab5969
7
+ data.tar.gz: b95eae03330676be88800817be77af1c40b79edf4ab9ac574cfabeba7e0c82b8cd57318905fd150041cc3396f81d6817c4285f8188da266a43724571660f20ee
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- brainiac (0.0.3)
4
+ brainiac (0.0.4)
5
5
  puma (~> 7.2)
6
6
  rackup (~> 2.3)
7
7
  sinatra (~> 4.1)
@@ -90,7 +90,7 @@ DEPENDENCIES
90
90
  CHECKSUMS
91
91
  ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
92
92
  base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
93
- brainiac (0.0.3)
93
+ brainiac (0.0.4)
94
94
  event_emitter (0.2.6) sha256=c72697bd5cce9d36594be1972c17f1c9a573236f44303a4d1d548080364e1391
95
95
  json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a
96
96
  language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Brainiac
2
2
 
3
- A webhook receiver that listens for [Fizzy](https://fizzy.do), GitHub, Discord, and Zoho Mail events, then dispatches work to AI agent CLIs. Each agent has its own persona, brain, and voice they collaborate on the same projects through @mentions.
3
+ Brainiac is a multi-agent orchestration layer for developer workflows. It connects your tools (Fizzy, GitHub, Discord, Zoho) to a team of autonomous AI agents. By managing personas, shared knowledge, and collaborative workflows via @mentions, Brainiac allows you to deploy and manage a unified fleet of AI experts directly from your CLI.
4
4
 
5
5
  ## How It Works
6
6
 
7
- Webhook events trigger the receiver to spawn an AI agent CLI with a natural language prompt. The receiver can dispatch multiple agents each with a unique personality and kiro-cli config. Agents are discovered from `~/.kiro/agents/`, and projects registered in `~/.brainiac/projects.json`. Config reloads dynamically, no restart needed.
7
+ Brainiac listens for incoming events and automatically spawns the appropriate AI agent CLI to handle the request. Because each agent maintains its own unique persona and configuration, you can deploy a specialized team—all managed through ~/.kiro/agents/. Project tracking is handled via ~/.brainiac/projects.json, and because the system reloads configurations dynamically, you can iterate on your agent workflows in real-time without ever needing a restart.
8
8
 
9
9
  ### Events
10
10
 
data/brainiac.gemspec CHANGED
@@ -10,10 +10,6 @@ Gem::Specification.new do |s|
10
10
  s.license = "MIT"
11
11
  s.required_ruby_version = ">= 3.4"
12
12
 
13
- s.cert_chain = ["certs/stowzilla.pem"]
14
- signing_key_path = File.expand_path("~/.ssh/gem-private_key.pem")
15
- s.signing_key = signing_key_path if File.exist?(signing_key_path)
16
-
17
13
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.start_with?("test/", "tmp/", ".") }
18
14
  s.executables = ["brainiac"]
19
15
 
@@ -742,6 +742,14 @@ def handle_discord_message(message, agent_key, bot_token, bot_user_id)
742
742
  # Strip CLI provider tag (e.g. [cli:grok]) from prompt content
743
743
  clean_content_for_prompt = clean_content_for_prompt.sub(/\[cli:\w+\]/i, "").strip
744
744
 
745
+ # Detect chat mode tag: [chat], [question], [?] — skips worktree, uses tmp dir instead
746
+ chat_mode = clean_content.match?(/\[(chat|question|\?)\]/i)
747
+ if chat_mode
748
+ clean_content = clean_content.sub(/\[(chat|question|\?)\]/i, "").strip
749
+ clean_content_for_prompt = clean_content_for_prompt.sub(/\[(chat|question|\?)\]/i, "").strip
750
+ LOG.info "[Discord:#{agent_name}] Chat mode detected — will skip worktree creation"
751
+ end
752
+
745
753
  # Find project: inline override > channel mapping > default_project
746
754
  if inline_project_key && PROJECTS.key?(inline_project_key)
747
755
  project_key = inline_project_key
@@ -927,7 +935,21 @@ def handle_discord_message(message, agent_key, bot_token, bot_user_id)
927
935
  thread_map = DISCORD_THREAD_MAP_MUTEX.synchronize { load_discord_thread_map }
928
936
  existing = thread_map[thread_map_key]
929
937
 
930
- if existing && existing["worktree"] && File.directory?(existing["worktree"])
938
+ if existing && existing["chat_mode"]
939
+ # Thread was started in chat mode — reuse the tmp dir, don't create a worktree
940
+ thread_worktree_path = existing["worktree"]
941
+ thread_cli_provider = existing["cli_provider"]
942
+ thread_model = existing["model"]
943
+ thread_effort = existing["effort"]
944
+ chat_mode = true
945
+ effective_provider = detect_cli_provider(text: clean_content) || thread_cli_provider
946
+ resolved_for_resume = resolve_project_cli_config(project_config, cli_provider_override: effective_provider, agent_name: agent_name)
947
+ should_resume = resolved_for_resume["resume_flag"] ? true : false
948
+ LOG.info "[Discord:#{agent_name}] Reusing chat mode tmp dir at #{thread_worktree_path} (resume: #{should_resume})"
949
+ elsif chat_mode
950
+ # New chat mode session — skip worktree, tmp dir will be created below
951
+ LOG.info "[Discord:#{agent_name}] Chat mode — skipping worktree creation"
952
+ elsif existing && existing["worktree"] && File.directory?(existing["worktree"])
931
953
  # Existing worktree — resume session. Inherit tags from the thread's first dispatch.
932
954
  thread_worktree_path = existing["worktree"]
933
955
  thread_cli_provider = existing["cli_provider"]
@@ -989,6 +1011,31 @@ def handle_discord_message(message, agent_key, bot_token, bot_user_id)
989
1011
  end
990
1012
  end
991
1013
 
1014
+ # Chat mode: create a tmp directory instead of a worktree for lightweight conversational sessions
1015
+ if chat_mode && !thread_worktree_path && thread_map_key
1016
+ chat_tmp_dir = File.join(BRAINIAC_DIR, "tmp", "chat", "#{agent_key}-#{effective_thread_id}")
1017
+ FileUtils.mkdir_p(chat_tmp_dir)
1018
+ thread_worktree_path = chat_tmp_dir
1019
+
1020
+ first_cli_provider = detect_cli_provider(text: clean_content)
1021
+ first_model = project_config ? detect_model(project_config, text: clean_content) : nil
1022
+ first_effort = project_config ? detect_effort(project_config, text: clean_content) : nil
1023
+ thread_cli_provider = first_cli_provider
1024
+ thread_model = first_model
1025
+ thread_effort = first_effort
1026
+
1027
+ DISCORD_THREAD_MAP_MUTEX.synchronize do
1028
+ map = load_discord_thread_map
1029
+ map[thread_map_key] = { "worktree" => chat_tmp_dir, "chat_mode" => true,
1030
+ "project" => PROJECTS.find { |_k, v| v == project_config }&.first,
1031
+ "channel_id" => effective_thread_id, "cli_provider" => first_cli_provider,
1032
+ "model" => first_model, "effort" => first_effort,
1033
+ "created_at" => Time.now.iso8601 }
1034
+ save_discord_thread_map(map)
1035
+ end
1036
+ LOG.info "[Discord:#{agent_name}] Created chat mode tmp dir at #{chat_tmp_dir}"
1037
+ end
1038
+
992
1039
  if should_resume && thread_worktree_path
993
1040
  # Lean resume prompt — prior session has full context
994
1041
  prompt = render_discord_resume_prompt(
@@ -1038,6 +1085,15 @@ def handle_discord_message(message, agent_key, bot_token, bot_user_id)
1038
1085
  channel: :discord)
1039
1086
  end
1040
1087
 
1088
+ # Chat mode fallback: if no thread_map_key was available (no thread created, e.g. DM or no project),
1089
+ # still use a tmp dir so we don't fall back to the project repo_path.
1090
+ if chat_mode && !thread_worktree_path
1091
+ chat_tmp_dir = File.join(BRAINIAC_DIR, "tmp", "chat", "#{agent_key}-#{message_id}")
1092
+ FileUtils.mkdir_p(chat_tmp_dir)
1093
+ thread_worktree_path = chat_tmp_dir
1094
+ LOG.info "[Discord:#{agent_name}] Chat mode fallback tmp dir at #{chat_tmp_dir}"
1095
+ end
1096
+
1041
1097
  work_dir = thread_worktree_path || (project_config ? project_config["repo_path"] : Dir.pwd)
1042
1098
 
1043
1099
  prompt_file = File.join(response_dir, "discord-prompt-#{timestamp}-#{agent_key}-#{message_id}.md")
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Brainiac
4
4
  # @return [String] the current gem version
5
- VERSION = "0.0.3"
5
+ VERSION = "0.0.4"
6
6
  end
metadata CHANGED
@@ -1,39 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainiac
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis
8
8
  bindir: bin
9
- cert_chain:
10
- - |
11
- -----BEGIN CERTIFICATE-----
12
- MIIEdDCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADBAMQ4wDAYDVQQDDAVhZ2Vu
13
- dDEZMBcGCgmSJomT8ixkARkWCXN0b3d6aWxsYTETMBEGCgmSJomT8ixkARkWA2Nv
14
- bTAeFw0yNjA2MDgxOTExNTlaFw0yNzA2MDgxOTExNTlaMEAxDjAMBgNVBAMMBWFn
15
- ZW50MRkwFwYKCZImiZPyLGQBGRYJc3Rvd3ppbGxhMRMwEQYKCZImiZPyLGQBGRYD
16
- Y29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAupBquKI/4WvXOgND
17
- pXyqH2GllZs1wG4TWWdn/DoMg45UoCwD+AWEuGrIdInBCpPN8vEJNJWPoM/RrU+b
18
- xRBZT4uUk00bnZRW2SYh5GJSqBoBR+rWc2DGkXyGfdRU2sQvkB0+is6ChgQ61WMM
19
- 33LE9+loBlVsZ6EVtrc18Uh2OW0mJpe0hN2nmBrxZqqOZigxC4DKRMFHvpRkxSb6
20
- mD4kit1AcwX9NEWJsXxrPaetL/SB/VbXaEZX93XAvp6USaXvCWt4slkDS2mIvqtn
21
- 9DtGC43LFC7SDGbnsG9PVenQgVCi8UWFPUAab0PqZSlmi3Qlbhw8qTGPp5Cbv4vz
22
- qjC2UGPOQigA/7lbbGRhCohMrjOVHMAQwkcgiIqtolUoYlnvPMIy+m3pdvgDv/PH
23
- bsZGvXQ7i0458xsmp1vaKthZocVAR+GboHbuIiYPUnO45ccXUQ00x6365tTe7mZi
24
- NvmUYdAGbQmVvFqyxF7IYA6sF74L2Lstu0knSfss557bAe1HAgMBAAGjeTB3MAkG
25
- A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSnxTL/lNBCeLqpeVIX6AUY
26
- kel4zjAeBgNVHREEFzAVgRNhZ2VudEBzdG93emlsbGEuY29tMB4GA1UdEgQXMBWB
27
- E2FnZW50QHN0b3d6aWxsYS5jb20wDQYJKoZIhvcNAQELBQADggGBACm9Fjit/UCv
28
- FxlKqeiCTIG94cIx+QrWAOJSx9knKydwUec1u04D/DbfZjTn3C2Bj227QgxeUn+6
29
- if3e2v7zAk1896hLmGYzML0+nxQPb0vmtdLR7HETUlSKTVabcv1fbwLyjsuGrBvk
30
- y51vOEzUEZ508a9yepLYqrQu1kOju4d57c9oA5l3H0mMKWz7av9tFj0B+STvuaWk
31
- HRYDWc5HgOEVTyV+w0uFt2Kw4OCb8C42uSvC5RfYYtw78MSP+5Ru+LXJ7XOtmuN0
32
- E6GVmofQ17ig9O3rgfFbMendSInrRmvPIGswvM1yivq9NOllFbdck2OJKPx6FCJF
33
- 7SJIkXQfc9P4B5iASIV1d1FsE0YX+g3jHXPJK/4mGL5bAyBKzpMfQB/mg6vQBzkh
34
- aOKPwcreFj7TznBl89R5tNS9wZQfPVR98zgPyocddWhK18eQNMSBUnv4eeJ8PPbk
35
- DovL+G8ajHDZ9fjH/+GVYHEMuiVdLarXrKJpHC1VfGTTUAp4NSEpUQ==
36
- -----END CERTIFICATE-----
9
+ cert_chain: []
37
10
  date: 1980-01-02 00:00:00.000000000 Z
38
11
  dependencies:
39
12
  - !ruby/object:Gem::Dependency
@@ -163,7 +136,6 @@ files:
163
136
  - bin/brainiac
164
137
  - bin/brainiac-completion.bash
165
138
  - brainiac.gemspec
166
- - certs/stowzilla.pem
167
139
  - docs/waybar-config.md
168
140
  - lib/brainiac.rb
169
141
  - lib/brainiac/agents.rb
checksums.yaml.gz.sig DELETED
Binary file
data/certs/stowzilla.pem DELETED
@@ -1,26 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIEdDCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADBAMQ4wDAYDVQQDDAVhZ2Vu
3
- dDEZMBcGCgmSJomT8ixkARkWCXN0b3d6aWxsYTETMBEGCgmSJomT8ixkARkWA2Nv
4
- bTAeFw0yNjA2MDgxOTExNTlaFw0yNzA2MDgxOTExNTlaMEAxDjAMBgNVBAMMBWFn
5
- ZW50MRkwFwYKCZImiZPyLGQBGRYJc3Rvd3ppbGxhMRMwEQYKCZImiZPyLGQBGRYD
6
- Y29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAupBquKI/4WvXOgND
7
- pXyqH2GllZs1wG4TWWdn/DoMg45UoCwD+AWEuGrIdInBCpPN8vEJNJWPoM/RrU+b
8
- xRBZT4uUk00bnZRW2SYh5GJSqBoBR+rWc2DGkXyGfdRU2sQvkB0+is6ChgQ61WMM
9
- 33LE9+loBlVsZ6EVtrc18Uh2OW0mJpe0hN2nmBrxZqqOZigxC4DKRMFHvpRkxSb6
10
- mD4kit1AcwX9NEWJsXxrPaetL/SB/VbXaEZX93XAvp6USaXvCWt4slkDS2mIvqtn
11
- 9DtGC43LFC7SDGbnsG9PVenQgVCi8UWFPUAab0PqZSlmi3Qlbhw8qTGPp5Cbv4vz
12
- qjC2UGPOQigA/7lbbGRhCohMrjOVHMAQwkcgiIqtolUoYlnvPMIy+m3pdvgDv/PH
13
- bsZGvXQ7i0458xsmp1vaKthZocVAR+GboHbuIiYPUnO45ccXUQ00x6365tTe7mZi
14
- NvmUYdAGbQmVvFqyxF7IYA6sF74L2Lstu0knSfss557bAe1HAgMBAAGjeTB3MAkG
15
- A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSnxTL/lNBCeLqpeVIX6AUY
16
- kel4zjAeBgNVHREEFzAVgRNhZ2VudEBzdG93emlsbGEuY29tMB4GA1UdEgQXMBWB
17
- E2FnZW50QHN0b3d6aWxsYS5jb20wDQYJKoZIhvcNAQELBQADggGBACm9Fjit/UCv
18
- FxlKqeiCTIG94cIx+QrWAOJSx9knKydwUec1u04D/DbfZjTn3C2Bj227QgxeUn+6
19
- if3e2v7zAk1896hLmGYzML0+nxQPb0vmtdLR7HETUlSKTVabcv1fbwLyjsuGrBvk
20
- y51vOEzUEZ508a9yepLYqrQu1kOju4d57c9oA5l3H0mMKWz7av9tFj0B+STvuaWk
21
- HRYDWc5HgOEVTyV+w0uFt2Kw4OCb8C42uSvC5RfYYtw78MSP+5Ru+LXJ7XOtmuN0
22
- E6GVmofQ17ig9O3rgfFbMendSInrRmvPIGswvM1yivq9NOllFbdck2OJKPx6FCJF
23
- 7SJIkXQfc9P4B5iASIV1d1FsE0YX+g3jHXPJK/4mGL5bAyBKzpMfQB/mg6vQBzkh
24
- aOKPwcreFj7TznBl89R5tNS9wZQfPVR98zgPyocddWhK18eQNMSBUnv4eeJ8PPbk
25
- DovL+G8ajHDZ9fjH/+GVYHEMuiVdLarXrKJpHC1VfGTTUAp4NSEpUQ==
26
- -----END CERTIFICATE-----
data.tar.gz.sig DELETED
@@ -1 +0,0 @@
1
- U�>�ª뭌��\�~Vt�z�<!ݳ�f0���&�-֏P�K���*�Xj(����sba�"[C��_�rA��r�*�x��HR�]�[ck���ʙ�.�H�Va�&q8�xѪc�f� Y�k��O���ݨ�g�^��tkk�F�x�������B��7�K��,�Ę#���+�AA-�Nj�4�٫�b�� 3of_7Z(1��^�G��wWZ�z�x�w�Lv.��e.���+5��r�F=��yEC��T�Z�a{'6Z����EDa��z��T��aKQ��d�(e%JL�8{��q���1�R����,8��r�QbE��j�Bd���n��ϫ 5�[)�c��P���;o~i��ц�6� �^J�V�+A�I��@��+�
metadata.gz.sig DELETED
Binary file