brainiac-discord 0.0.11 → 0.0.13

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: e8d2bbbf0efaa83da8904137abf18a256f79e5073fe5896390c0afa1f880856f
4
- data.tar.gz: 9b9a19c746dd57d13b232a6864918b99acf9a54128213dac2ff1c0328b90e242
3
+ metadata.gz: 1f2f87e89db33072e4ceb141ec472b71ce09f22d3a383da595f195f3f441b9ee
4
+ data.tar.gz: 69aeb6d7e6f945f0fb517c8bfd37a6d91e749137d634d5578596a462579044b2
5
5
  SHA512:
6
- metadata.gz: 8af3d015077e894932bf05ae2940b8bc9d69895874b88ed548e51c01469a2257bc2bda5dd162a601c775c4745567c257a16c0091b52f5ae4854f4ebb42fecfd3
7
- data.tar.gz: bbda431894c7453f4e6a8f9b8c6747884cc9cf39c01a0b812dd7f9a812a5afff63fbbc0f2171ccee88c7deabfd3eeac7216910efbb01b24def1d4d3270ad4db0
6
+ metadata.gz: 2eab7e192cfe422009193273e88bbf8aab1b8ccecdf3d33d7643847b4799a55f44bb5c3d5f18c56eea753982491c73426942e420a1d99c418867829c9bb65fdf
7
+ data.tar.gz: 6f66c81ea46ac32423fb10a542730c3e2c71d6d7db71b959ef188b93effa68a12932f4e8e52cc1d203473882355d78339058320dbba9eb61eb8e88d62a479700
@@ -558,8 +558,24 @@ module Brainiac
558
558
  )
559
559
  end
560
560
 
561
+ # Resolve CLI overrides and work_dir BEFORE building the prompt so we can determine
562
+ # whether resume will actually work. This prevents sending a lean prompt when
563
+ # the CLI won't actually have session state.
564
+ work_dir = chat_mode_fallback(agent_key, agent_name, message_id, chat_mode, thread_worktree_path) ||
565
+ (project_config ? project_config["repo_path"] : Dir.pwd)
566
+ model, effort, cli_provider_override = resolve_overrides(
567
+ clean_content, project_config, thread_model, thread_effort, thread_cli_provider
568
+ )
569
+ resolved = resolve_project_cli_config(project_config || DEFAULT_PROJECT,
570
+ cli_provider_override: cli_provider_override, agent_name: agent_name)
571
+
572
+ # Convert should_resume to the actual flag/symbol. If resolve_resume returns false,
573
+ # we know the CLI won't actually resume, so we shouldn't send a lean prompt.
574
+ actual_resume = should_resume ? resolve_resume(true, resolved, work_dir) : false
575
+ use_lean_prompt = actual_resume && thread_worktree_path
576
+
561
577
  prompt = build_prompt(
562
- should_resume: should_resume, thread_worktree_path: thread_worktree_path,
578
+ should_resume: use_lean_prompt, thread_worktree_path: thread_worktree_path,
563
579
  clean_content_for_prompt: clean_content_for_prompt,
564
580
  discord_user: discord_user, channel_name: channel_info&.dig("name") || channel_id, reply_context: reply_context,
565
581
  channel_history: channel_history, thread_root_context: thread_root_context,
@@ -567,15 +583,9 @@ module Brainiac
567
583
  brain_context: brain_context, agent_name: agent_name, supersede_key: supersede_key
568
584
  )
569
585
 
570
- work_dir = chat_mode_fallback(agent_key, agent_name, message_id, chat_mode, thread_worktree_path) ||
571
- (project_config ? project_config["repo_path"] : Dir.pwd)
572
586
  prompt_file = File.join(response_dir, "discord-prompt-#{timestamp}-#{agent_key}-#{message_id}.md")
573
587
  File.write(prompt_file, prompt)
574
588
 
575
- model, effort, cli_provider_override = resolve_overrides(
576
- clean_content, project_config, thread_model, thread_effort, thread_cli_provider
577
- )
578
-
579
589
  persist_overrides(thread_map_key, clean_content, project_config,
580
590
  cli_provider: cli_provider_override, model: model, effort: effort,
581
591
  prev_cli_provider: thread_cli_provider, prev_model: thread_model, prev_effort: thread_effort)
@@ -592,8 +602,8 @@ module Brainiac
592
602
  agent_key: agent_key, agent_name: agent_name, bot_token: bot_token,
593
603
  channel_id: channel_id, message_id: message_id, discord_user: discord_user,
594
604
  work_dir: work_dir, prompt_file: prompt_file, response_file: response_file,
595
- meta_file: meta_file, model: model, effort: effort, should_resume: should_resume,
596
- cli_provider_override: cli_provider_override, project_config: project_config,
605
+ meta_file: meta_file, model: model, effort: effort, actual_resume: actual_resume,
606
+ resolved: resolved, project_config: project_config,
597
607
  session_key: session_key, supersede_key: supersede_key,
598
608
  attachment_paths: attachment_paths, timestamp: timestamp, response_dir: response_dir
599
609
  )
@@ -886,17 +896,15 @@ module Brainiac
886
896
 
887
897
  def spawn_agent(agent_key:, agent_name:, bot_token:, channel_id:, message_id:, discord_user:,
888
898
  work_dir:, prompt_file:, response_file:, meta_file:, model:, effort:,
889
- should_resume:, cli_provider_override:, project_config:,
899
+ actual_resume:, resolved:, project_config:,
890
900
  session_key:, supersede_key:, attachment_paths:, timestamp:, response_dir:)
891
901
  agent_config_name = agent_key.downcase.gsub(/[^a-z0-9-]/, "-")
892
902
  log_file = File.join(response_dir, "discord-agent-#{timestamp}-#{agent_key}-#{message_id}.log")
893
903
 
894
- resolved = resolve_project_cli_config(project_config || DEFAULT_PROJECT,
895
- cli_provider_override: cli_provider_override, agent_name: agent_name)
896
904
  cmd = build_agent_cmd(resolved, agent_config_name: agent_config_name, model: model, effort: effort,
897
- prompt_file: prompt_file, resume: should_resume)
905
+ prompt_file: prompt_file, resume: actual_resume)
898
906
 
899
- resume_note = should_resume ? ", resuming" : ""
907
+ resume_note = actual_resume ? ", resuming" : ""
900
908
  if defined?(LOG)
901
909
  LOG.info "[Discord:#{agent_name}] Dispatching for #{discord_user} " \
902
910
  "(model: #{model || "default"}, effort: #{effort || "default"}, cli: #{resolved["agent_cli"]}#{resume_note}), tail -f #{log_file}"
@@ -910,6 +918,17 @@ module Brainiac
910
918
  LOG.info "[Discord:#{agent_name}] Injecting #{agent_env.size} env var(s): #{agent_env.keys.join(", ")}" if defined?(LOG)
911
919
  end
912
920
 
921
+ # Inject a GitHub App token so `gh`/`git` run as the agent's own bot
922
+ # identity (e.g. galen[bot]) instead of the host machine's personal
923
+ # `gh auth`. Without this, `gh pr create` in the prompt would open PRs
924
+ # under whoever is logged in on the box. No-op if the github plugin
925
+ # isn't loaded or the agent has no app configured.
926
+ gh_env = github_agent_token_env(agent_name, project_config)
927
+ unless gh_env.empty?
928
+ spawn_env.merge!(gh_env)
929
+ LOG.info "[Discord:#{agent_name}] Injecting GitHub App token (GH_TOKEN) for bot identity" if defined?(LOG)
930
+ end
931
+
913
932
  head_before, status_before = capture_brainiac_state(project_config, work_dir)
914
933
  prompt_mode = resolved["prompt_mode"] || "stdin"
915
934
 
@@ -936,6 +955,41 @@ module Brainiac
936
955
  )
937
956
  end
938
957
 
958
+ # Build a { "GH_TOKEN" => ... } env hash so the spawned agent's `gh`
959
+ # and `git` invocations authenticate as the agent's own GitHub App bot
960
+ # rather than the host's personal `gh auth`. This is what makes the
961
+ # prompt's `gh pr create` open PRs under e.g. galen[bot].
962
+ #
963
+ # Reuses the brainiac-github plugin's AppClient. The github plugin is
964
+ # optional, so everything is guarded: if it isn't loaded, or no app is
965
+ # configured for the agent (or the shared "brainiac" app), we return an
966
+ # empty hash and `gh` falls back to whatever's authenticated on the box.
967
+ def github_agent_token_env(agent_name, project_config)
968
+ return {} unless agent_name && project_config
969
+
970
+ repo = project_config["github_repo"]
971
+ return {} unless repo && !repo.to_s.empty?
972
+
973
+ return {} unless defined?(Brainiac::Plugins::Github::AppClient)
974
+
975
+ client = Brainiac::Plugins::Github::AppClient
976
+ effective_agent = if client.configured?(agent_name)
977
+ agent_name
978
+ elsif client.configured?("brainiac")
979
+ "brainiac"
980
+ end
981
+ return {} unless effective_agent
982
+
983
+ repo_owner = repo.to_s.split("/").first
984
+ token = client.installation_token_for(effective_agent, repo_owner: repo_owner)
985
+ return {} unless token && !token.empty?
986
+
987
+ { "GH_TOKEN" => token }
988
+ rescue StandardError => e
989
+ LOG.warn "[Discord:#{agent_name}] Could not mint GitHub App token: #{e.message}" if defined?(LOG)
990
+ {}
991
+ end
992
+
939
993
  def capture_brainiac_state(project_config, work_dir)
940
994
  return [nil, nil] unless project_config
941
995
 
@@ -48,8 +48,8 @@ module Brainiac
48
48
  3. Make the changes, test if applicable
49
49
  4. Commit with a clear message
50
50
  5. Push the branch
51
- 6. Summarize what you did in your response file
52
- 7. If it's substantial or needs review, mention opening a PR (but don't create it unless asked)
51
+ 6. Open a PR with `gh pr create --fill` (or with a descriptive body)
52
+ 7. Summarize what you did in your response file, including a link to the PR
53
53
 
54
54
  **When responding conversationally:**
55
55
  - Answer questions about the codebase, architecture, conventions
@@ -3,7 +3,7 @@
3
3
  module Brainiac
4
4
  module Plugins
5
5
  module Discord
6
- VERSION = "0.0.11"
6
+ VERSION = "0.0.13"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainiac-discord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis