Story 33: Copy-paste diff commands for agent worktrees

- Add base_branch detection to WorktreeInfo (from project root HEAD)
- Expose base_branch in AgentInfo API response
- Add {{base_branch}} template variable to agent config rendering
- Show git difftool command with copy-to-clipboard in AgentPanel UI
- Add diff command instruction to coder agent prompts
- Add AgentPanel tests for diff command rendering and clipboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dave
2026-02-20 12:48:50 +00:00
parent 1cd1d318d3
commit 39b67ff754
7 changed files with 297 additions and 7 deletions

View File

@@ -175,6 +175,7 @@ impl ProjectConfig {
worktree_path: &str,
story_id: &str,
agent_name: Option<&str>,
base_branch: Option<&str>,
) -> Result<(String, Vec<String>, String), String> {
let agent = match agent_name {
Some(name) => self
@@ -185,9 +186,11 @@ impl ProjectConfig {
.ok_or_else(|| "No agents configured".to_string())?,
};
let bb = base_branch.unwrap_or("master");
let render = |s: &str| {
s.replace("{{worktree_path}}", worktree_path)
.replace("{{story_id}}", story_id)
.replace("{{base_branch}}", bb)
};
let command = render(&agent.command);
@@ -378,7 +381,7 @@ max_turns = 0
fn render_agent_args_default() {
let config = ProjectConfig::default();
let (cmd, args, prompt) = config
.render_agent_args("/tmp/wt", "42_foo", None)
.render_agent_args("/tmp/wt", "42_foo", None, None)
.unwrap();
assert_eq!(cmd, "claude");
assert!(args.is_empty());
@@ -404,7 +407,7 @@ max_turns = 30
let config = ProjectConfig::parse(toml_str).unwrap();
let (cmd, args, prompt) = config
.render_agent_args("/tmp/wt", "42_foo", Some("supervisor"))
.render_agent_args("/tmp/wt", "42_foo", Some("supervisor"), Some("master"))
.unwrap();
assert_eq!(cmd, "claude");
assert!(args.contains(&"--model".to_string()));
@@ -422,7 +425,7 @@ max_turns = 30
// Render for coder
let (_, coder_args, _) = config
.render_agent_args("/tmp/wt", "42_foo", Some("coder"))
.render_agent_args("/tmp/wt", "42_foo", Some("coder"), Some("master"))
.unwrap();
assert!(coder_args.contains(&"sonnet".to_string()));
assert!(coder_args.contains(&"30".to_string()));
@@ -433,7 +436,7 @@ max_turns = 30
#[test]
fn render_agent_args_not_found() {
let config = ProjectConfig::default();
let result = config.render_agent_args("/tmp/wt", "42_foo", Some("nonexistent"));
let result = config.render_agent_args("/tmp/wt", "42_foo", Some("nonexistent"), None);
assert!(result.is_err());
assert!(result.unwrap_err().contains("No agent named 'nonexistent'"));
}