brainiac-discord 0.0.11 → 0.0.14

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: f90a4cf177bc62d55f5773e21f3b5e05aaefbdbff94bae975fcbcb21ae3dbb64
4
+ data.tar.gz: a9dc84c5ab058a8173c96a6bda909a5ea8959a36fe61065d316b0b408ab2eb54
5
5
  SHA512:
6
- metadata.gz: 8af3d015077e894932bf05ae2940b8bc9d69895874b88ed548e51c01469a2257bc2bda5dd162a601c775c4745567c257a16c0091b52f5ae4854f4ebb42fecfd3
7
- data.tar.gz: bbda431894c7453f4e6a8f9b8c6747884cc9cf39c01a0b812dd7f9a812a5afff63fbbc0f2171ccee88c7deabfd3eeac7216910efbb01b24def1d4d3270ad4db0
6
+ metadata.gz: c7df8598d6a702644e25c18c76c49aa8f406fa3c0806b2ba9a4eccf0859615fffc027e056d66d2ac42b4d737fdb7b7c00f62e2c2b629a4ee4e4e1adfa9844030
7
+ data.tar.gz: f7e4ddc91b9d0b819f82000e276f9490fa4fdc8454fd475ef49d09de5d58b917e988be95df2ec8577a4d55cca4ec186cc4cc1d486022912840e49767a41371ee
@@ -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
  )
@@ -816,6 +826,13 @@ module Brainiac
816
826
  debounced_repo_fetch(repo_path)
817
827
  worktree_path = create_or_reuse_worktree(repo_path: repo_path, branch: branch)
818
828
 
829
+ # Register a work item so brainiac-github can route PR comments/reviews back
830
+ # to the agent that actually owns this Discord thread's worktree. Without this,
831
+ # PRs created from a conversational session have no work item and comments
832
+ # fall back to the project's default agent.
833
+ project_key = PROJECTS.find { |_k, v| v == project_config }&.first
834
+ register_work_item(branch: branch, worktree: worktree_path, project: project_key, agent: agent_name)
835
+
819
836
  cli, model, effort = detect_thread_overrides(
820
837
  project_config, clean_content,
821
838
  fallback_cli: existing&.dig("cli_provider"),
@@ -886,17 +903,15 @@ module Brainiac
886
903
 
887
904
  def spawn_agent(agent_key:, agent_name:, bot_token:, channel_id:, message_id:, discord_user:,
888
905
  work_dir:, prompt_file:, response_file:, meta_file:, model:, effort:,
889
- should_resume:, cli_provider_override:, project_config:,
906
+ actual_resume:, resolved:, project_config:,
890
907
  session_key:, supersede_key:, attachment_paths:, timestamp:, response_dir:)
891
908
  agent_config_name = agent_key.downcase.gsub(/[^a-z0-9-]/, "-")
892
909
  log_file = File.join(response_dir, "discord-agent-#{timestamp}-#{agent_key}-#{message_id}.log")
893
910
 
894
- resolved = resolve_project_cli_config(project_config || DEFAULT_PROJECT,
895
- cli_provider_override: cli_provider_override, agent_name: agent_name)
896
911
  cmd = build_agent_cmd(resolved, agent_config_name: agent_config_name, model: model, effort: effort,
897
- prompt_file: prompt_file, resume: should_resume)
912
+ prompt_file: prompt_file, resume: actual_resume)
898
913
 
899
- resume_note = should_resume ? ", resuming" : ""
914
+ resume_note = actual_resume ? ", resuming" : ""
900
915
  if defined?(LOG)
901
916
  LOG.info "[Discord:#{agent_name}] Dispatching for #{discord_user} " \
902
917
  "(model: #{model || "default"}, effort: #{effort || "default"}, cli: #{resolved["agent_cli"]}#{resume_note}), tail -f #{log_file}"
@@ -910,6 +925,17 @@ module Brainiac
910
925
  LOG.info "[Discord:#{agent_name}] Injecting #{agent_env.size} env var(s): #{agent_env.keys.join(", ")}" if defined?(LOG)
911
926
  end
912
927
 
928
+ # Inject a GitHub App token so `gh`/`git` run as the agent's own bot
929
+ # identity (e.g. galen[bot]) instead of the host machine's personal
930
+ # `gh auth`. Without this, `gh pr create` in the prompt would open PRs
931
+ # under whoever is logged in on the box. No-op if the github plugin
932
+ # isn't loaded or the agent has no app configured.
933
+ gh_env = github_agent_token_env(agent_name, project_config)
934
+ unless gh_env.empty?
935
+ spawn_env.merge!(gh_env)
936
+ LOG.info "[Discord:#{agent_name}] Injecting GitHub App token (GH_TOKEN) for bot identity" if defined?(LOG)
937
+ end
938
+
913
939
  head_before, status_before = capture_brainiac_state(project_config, work_dir)
914
940
  prompt_mode = resolved["prompt_mode"] || "stdin"
915
941
 
@@ -936,6 +962,41 @@ module Brainiac
936
962
  )
937
963
  end
938
964
 
965
+ # Build a { "GH_TOKEN" => ... } env hash so the spawned agent's `gh`
966
+ # and `git` invocations authenticate as the agent's own GitHub App bot
967
+ # rather than the host's personal `gh auth`. This is what makes the
968
+ # prompt's `gh pr create` open PRs under e.g. galen[bot].
969
+ #
970
+ # Reuses the brainiac-github plugin's AppClient. The github plugin is
971
+ # optional, so everything is guarded: if it isn't loaded, or no app is
972
+ # configured for the agent (or the shared "brainiac" app), we return an
973
+ # empty hash and `gh` falls back to whatever's authenticated on the box.
974
+ def github_agent_token_env(agent_name, project_config)
975
+ return {} unless agent_name && project_config
976
+
977
+ repo = project_config["github_repo"]
978
+ return {} unless repo && !repo.to_s.empty?
979
+
980
+ return {} unless defined?(Brainiac::Plugins::Github::AppClient)
981
+
982
+ client = Brainiac::Plugins::Github::AppClient
983
+ effective_agent = if client.configured?(agent_name)
984
+ agent_name
985
+ elsif client.configured?("brainiac")
986
+ "brainiac"
987
+ end
988
+ return {} unless effective_agent
989
+
990
+ repo_owner = repo.to_s.split("/").first
991
+ token = client.installation_token_for(effective_agent, repo_owner: repo_owner)
992
+ return {} unless token && !token.empty?
993
+
994
+ { "GH_TOKEN" => token }
995
+ rescue StandardError => e
996
+ LOG.warn "[Discord:#{agent_name}] Could not mint GitHub App token: #{e.message}" if defined?(LOG)
997
+ {}
998
+ end
999
+
939
1000
  def capture_brainiac_state(project_config, work_dir)
940
1001
  return [nil, nil] unless project_config
941
1002
 
@@ -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.14"
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.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis