mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
fix: move goosehints/AGENTS.md handling to goose, and out of developer extension (#5575)
This commit is contained in:
Generated
+5
-4
@@ -2597,9 +2597,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.16"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
|
||||
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
@@ -2632,6 +2632,7 @@ dependencies = [
|
||||
"etcetera",
|
||||
"fs2",
|
||||
"futures",
|
||||
"ignore",
|
||||
"include_dir",
|
||||
"indexmap 2.12.0",
|
||||
"indoc",
|
||||
@@ -3415,9 +3416,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.23"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
|
||||
checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
mod import_files;
|
||||
pub mod load_hints;
|
||||
@@ -1,6 +1,5 @@
|
||||
pub mod analyze;
|
||||
mod editor_models;
|
||||
mod goose_hints;
|
||||
mod lang;
|
||||
mod shell;
|
||||
mod text_editor;
|
||||
|
||||
@@ -33,7 +33,6 @@ use tokio_util::sync::CancellationToken;
|
||||
|
||||
use super::analyze::{types::AnalyzeParams, CodeAnalyzer};
|
||||
use super::editor_models::{create_editor_model, EditorModel};
|
||||
use super::goose_hints::load_hints::{load_hint_files, GOOSE_HINTS_FILENAME};
|
||||
use super::shell::{
|
||||
configure_shell_command, expand_path, get_shell_config, is_absolute_path, kill_process_group,
|
||||
};
|
||||
@@ -246,17 +245,6 @@ impl ServerHandler for DeveloperServer {
|
||||
}
|
||||
};
|
||||
|
||||
let hints_filenames: Vec<String> = std::env::var("CONTEXT_FILE_NAMES")
|
||||
.ok()
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.unwrap_or_else(|| vec!["AGENTS.md".to_string(), GOOSE_HINTS_FILENAME.to_string()]);
|
||||
|
||||
// Build ignore patterns for file reference processing
|
||||
let ignore_patterns = Self::build_ignore_patterns(&cwd);
|
||||
|
||||
// Load hints using the centralized function
|
||||
let hints = load_hint_files(&cwd, &hints_filenames, &ignore_patterns);
|
||||
|
||||
// Check if editor model exists and augment with custom llm editor tool description
|
||||
let editor_description = if let Some(ref editor) = self.editor_model {
|
||||
formatdoc! {r#"
|
||||
@@ -373,12 +361,7 @@ impl ServerHandler for DeveloperServer {
|
||||
_ => format!("{}{}", common_shell_instructions, unix_specific),
|
||||
};
|
||||
|
||||
// Return base instructions directly when no hints are found
|
||||
let instructions = if hints.is_empty() {
|
||||
format!("{base_instructions}{editor_description}\n{shell_tool_desc}")
|
||||
} else {
|
||||
format!("{base_instructions}\n{editor_description}\n{shell_tool_desc}\n{hints}")
|
||||
};
|
||||
let instructions = format!("{base_instructions}{editor_description}\n{shell_tool_desc}");
|
||||
|
||||
ServerInfo {
|
||||
server_info: Implementation {
|
||||
@@ -3397,161 +3380,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_global_goosehints() {
|
||||
// Note: This test checks if ~/.config/goose/.goosehints exists and includes it in instructions
|
||||
// Since RMCP version uses get_info() instead of instructions(), we test that method
|
||||
let global_hints_path =
|
||||
PathBuf::from(shellexpand::tilde("~/.config/goose/.goosehints").to_string());
|
||||
let global_hints_bak_path =
|
||||
PathBuf::from(shellexpand::tilde("~/.config/goose/.goosehints.bak").to_string());
|
||||
let mut globalhints_existed = false;
|
||||
|
||||
if global_hints_path.is_file() {
|
||||
globalhints_existed = true;
|
||||
fs::copy(&global_hints_path, &global_hints_bak_path).unwrap();
|
||||
}
|
||||
|
||||
fs::write(&global_hints_path, "These are my global goose hints.").unwrap();
|
||||
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
let server = create_test_server();
|
||||
let server_info = server.get_info();
|
||||
|
||||
assert!(server_info.instructions.is_some());
|
||||
let instructions = server_info.instructions.unwrap();
|
||||
assert!(instructions.contains("my global goose hints."));
|
||||
|
||||
// restore backup if globalhints previously existed
|
||||
if globalhints_existed {
|
||||
fs::copy(&global_hints_bak_path, &global_hints_path).unwrap();
|
||||
fs::remove_file(&global_hints_bak_path).unwrap();
|
||||
} else {
|
||||
fs::remove_file(&global_hints_path).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_goosehints_with_file_references() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
std::env::set_current_dir(&temp_dir).unwrap();
|
||||
|
||||
// Create referenced files
|
||||
let readme_path = temp_dir.path().join("README.md");
|
||||
std::fs::write(
|
||||
&readme_path,
|
||||
"# Project README\n\nThis is the project documentation.",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let guide_path = temp_dir.path().join("guide.md");
|
||||
std::fs::write(&guide_path, "# Development Guide\n\nFollow these steps...").unwrap();
|
||||
|
||||
// Create .goosehints with references
|
||||
let hints_content = r#"# Project Information
|
||||
|
||||
Please refer to:
|
||||
@README.md
|
||||
@guide.md
|
||||
|
||||
Additional instructions here.
|
||||
"#;
|
||||
let hints_path = temp_dir.path().join(".goosehints");
|
||||
std::fs::write(&hints_path, hints_content).unwrap();
|
||||
|
||||
// Create server and check instructions
|
||||
let server = create_test_server();
|
||||
let server_info = server.get_info();
|
||||
|
||||
assert!(server_info.instructions.is_some());
|
||||
let instructions = server_info.instructions.unwrap();
|
||||
|
||||
// Should contain the .goosehints content
|
||||
assert!(instructions.contains("Project Information"));
|
||||
assert!(instructions.contains("Additional instructions here"));
|
||||
|
||||
// Should contain the referenced files' content
|
||||
assert!(instructions.contains("# Project README"));
|
||||
assert!(instructions.contains("This is the project documentation"));
|
||||
assert!(instructions.contains("# Development Guide"));
|
||||
assert!(instructions.contains("Follow these steps"));
|
||||
|
||||
// Should have attribution markers
|
||||
assert!(instructions.contains("--- Content from"));
|
||||
assert!(instructions.contains("--- End of"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_goosehints_when_present() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
fs::write(".goosehints", "Test hint content").unwrap();
|
||||
let server = create_test_server();
|
||||
let server_info = server.get_info();
|
||||
|
||||
assert!(server_info.instructions.is_some());
|
||||
let instructions = server_info.instructions.unwrap();
|
||||
assert!(instructions.contains("Test hint content"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_goosehints_when_missing() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
let server = create_test_server();
|
||||
let server_info = server.get_info();
|
||||
|
||||
assert!(server_info.instructions.is_some());
|
||||
let instructions = server_info.instructions.unwrap();
|
||||
// When no hints are present, instructions should not contain hint content
|
||||
assert!(!instructions.contains("AGENTS.md:") && !instructions.contains(".goosehints:"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_goosehints_multiple_filenames() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
std::env::set_var("CONTEXT_FILE_NAMES", r#"["CLAUDE.md", ".goosehints"]"#);
|
||||
|
||||
fs::write("CLAUDE.md", "Custom hints file content from CLAUDE.md").unwrap();
|
||||
fs::write(".goosehints", "Custom hints file content from .goosehints").unwrap();
|
||||
let server = create_test_server();
|
||||
let server_info = server.get_info();
|
||||
|
||||
assert!(server_info.instructions.is_some());
|
||||
let instructions = server_info.instructions.unwrap();
|
||||
assert!(instructions.contains("Custom hints file content from CLAUDE.md"));
|
||||
assert!(instructions.contains("Custom hints file content from .goosehints"));
|
||||
std::env::remove_var("CONTEXT_FILE_NAMES");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_goosehints_configurable_filename() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
std::env::set_var("CONTEXT_FILE_NAMES", r#"["CLAUDE.md"]"#);
|
||||
|
||||
fs::write("CLAUDE.md", "Custom hints file content").unwrap();
|
||||
let server = create_test_server();
|
||||
let server_info = server.get_info();
|
||||
|
||||
assert!(server_info.instructions.is_some());
|
||||
let instructions = server_info.instructions.unwrap();
|
||||
assert!(instructions.contains("Custom hints file content"));
|
||||
assert!(!instructions.contains(".goosehints")); // Make sure it's not loading the default
|
||||
std::env::remove_var("CONTEXT_FILE_NAMES");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_resolve_path_absolute() {
|
||||
|
||||
@@ -109,6 +109,7 @@ insta = "1.43.2"
|
||||
paste = "1.0.0"
|
||||
shellexpand = "3.1.1"
|
||||
indexmap = "2.12.0"
|
||||
ignore = "0.4.25"
|
||||
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
|
||||
@@ -245,6 +245,7 @@ impl Agent {
|
||||
async fn prepare_reply_context(
|
||||
&self,
|
||||
unfixed_conversation: Conversation,
|
||||
working_dir: &std::path::Path,
|
||||
) -> Result<ReplyContext> {
|
||||
let unfixed_messages = unfixed_conversation.messages().clone();
|
||||
let (conversation, issues) = fix_conversation(unfixed_conversation.clone());
|
||||
@@ -261,7 +262,8 @@ impl Agent {
|
||||
let initial_messages = conversation.messages().clone();
|
||||
let config = Config::global();
|
||||
|
||||
let (tools, toolshim_tools, system_prompt) = self.prepare_tools_and_prompt().await?;
|
||||
let (tools, toolshim_tools, system_prompt) =
|
||||
self.prepare_tools_and_prompt(working_dir).await?;
|
||||
let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);
|
||||
|
||||
self.tool_inspection_manager
|
||||
@@ -830,7 +832,9 @@ impl Agent {
|
||||
session: Session,
|
||||
cancel_token: Option<CancellationToken>,
|
||||
) -> Result<BoxStream<'_, Result<AgentEvent>>> {
|
||||
let context = self.prepare_reply_context(conversation).await?;
|
||||
let context = self
|
||||
.prepare_reply_context(conversation, &session.working_dir)
|
||||
.await?;
|
||||
let ReplyContext {
|
||||
mut conversation,
|
||||
mut tools,
|
||||
@@ -844,6 +848,7 @@ impl Agent {
|
||||
|
||||
let provider = self.provider().await?;
|
||||
let session_id = session_config.id.clone();
|
||||
let working_dir = session.working_dir.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = SessionManager::maybe_update_name(&session_id, provider).await {
|
||||
warn!("Failed to generate session description: {}", e);
|
||||
@@ -1137,7 +1142,8 @@ impl Agent {
|
||||
}
|
||||
}
|
||||
if tools_updated {
|
||||
(tools, toolshim_tools, system_prompt) = self.prepare_tools_and_prompt().await?;
|
||||
(tools, toolshim_tools, system_prompt) =
|
||||
self.prepare_tools_and_prompt(&working_dir).await?;
|
||||
}
|
||||
let mut exit_chat = false;
|
||||
if no_tools_called {
|
||||
@@ -1307,6 +1313,7 @@ impl Agent {
|
||||
.with_extensions(extensions_info.into_iter())
|
||||
.with_frontend_instructions(self.frontend_instructions.lock().await.clone())
|
||||
.with_extension_and_tool_counts(extension_count, tool_count)
|
||||
.with_hints(&std::env::current_dir()?)
|
||||
.build();
|
||||
|
||||
let recipe_prompt = prompt_manager.get_recipe_prompt().await;
|
||||
|
||||
@@ -8,11 +8,13 @@ use std::collections::HashMap;
|
||||
use crate::agents::extension::ExtensionInfo;
|
||||
use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents;
|
||||
use crate::agents::router_tools::llm_search_tool_prompt;
|
||||
use crate::hints::load_hints::{load_hint_files, AGENTS_MD_FILENAME, GOOSE_HINTS_FILENAME};
|
||||
use crate::{
|
||||
config::{Config, GooseMode},
|
||||
prompt_template,
|
||||
utils::sanitize_unicode_tags,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
const MAX_EXTENSIONS: usize = 5;
|
||||
const MAX_TOOLS: usize = 50;
|
||||
@@ -52,6 +54,7 @@ pub struct SystemPromptBuilder<'a, M> {
|
||||
frontend_instructions: Option<String>,
|
||||
extension_tool_count: Option<(usize, usize)>,
|
||||
router_enabled: bool,
|
||||
hints: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> SystemPromptBuilder<'a, PromptManager> {
|
||||
@@ -86,6 +89,33 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_hints(mut self, working_dir: &Path) -> Self {
|
||||
let config = Config::global();
|
||||
let hints_filenames = config
|
||||
.get_param::<Vec<String>>("CONTEXT_FILE_NAMES")
|
||||
.unwrap_or_else(|_| {
|
||||
vec![
|
||||
GOOSE_HINTS_FILENAME.to_string(),
|
||||
AGENTS_MD_FILENAME.to_string(),
|
||||
]
|
||||
});
|
||||
let ignore_patterns = {
|
||||
let builder = ignore::gitignore::GitignoreBuilder::new(working_dir);
|
||||
builder.build().unwrap_or_else(|_| {
|
||||
ignore::gitignore::GitignoreBuilder::new(working_dir)
|
||||
.build()
|
||||
.expect("Failed to build default gitignore")
|
||||
})
|
||||
};
|
||||
|
||||
let hints = load_hint_files(working_dir, &hints_filenames, &ignore_patterns);
|
||||
|
||||
if !hints.is_empty() {
|
||||
self.hints = Some(hints);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> String {
|
||||
let mut extensions_info = self.extensions_info;
|
||||
|
||||
@@ -138,6 +168,12 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
|
||||
});
|
||||
|
||||
let mut system_prompt_extras = self.manager.system_prompt_extras.clone();
|
||||
|
||||
// Add hints if provided
|
||||
if let Some(hints) = self.hints {
|
||||
system_prompt_extras.push(hints);
|
||||
}
|
||||
|
||||
if goose_mode == GooseMode::Chat {
|
||||
system_prompt_extras.push(
|
||||
"Right now you are in the chat only mode, no access to any tool use and system."
|
||||
@@ -201,6 +237,7 @@ impl PromptManager {
|
||||
frontend_instructions: None,
|
||||
extension_tool_count: None,
|
||||
router_enabled: false,
|
||||
hints: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,10 @@ async fn toolshim_postprocess(
|
||||
}
|
||||
|
||||
impl Agent {
|
||||
pub async fn prepare_tools_and_prompt(&self) -> Result<(Vec<Tool>, Vec<Tool>, String)> {
|
||||
pub async fn prepare_tools_and_prompt(
|
||||
&self,
|
||||
working_dir: &std::path::Path,
|
||||
) -> Result<(Vec<Tool>, Vec<Tool>, String)> {
|
||||
// Get router enabled status
|
||||
let router_enabled = self.tool_route_manager.is_router_enabled().await;
|
||||
|
||||
@@ -156,6 +159,7 @@ impl Agent {
|
||||
.with_frontend_instructions(self.frontend_instructions.lock().await.clone())
|
||||
.with_extension_and_tool_counts(extension_count, tool_count)
|
||||
.with_router_enabled(router_enabled)
|
||||
.with_hints(working_dir)
|
||||
.build();
|
||||
|
||||
// Handle toolshim if enabled
|
||||
@@ -468,7 +472,9 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let (tools, _toolshim_tools, _system_prompt) = agent.prepare_tools_and_prompt().await?;
|
||||
let working_dir = std::env::current_dir()?;
|
||||
let (tools, _toolshim_tools, _system_prompt) =
|
||||
agent.prepare_tools_and_prompt(&working_dir).await?;
|
||||
|
||||
// Ensure both platform and frontend tools are present
|
||||
let names: Vec<String> = tools.iter().map(|t| t.name.clone().into_owned()).collect();
|
||||
|
||||
+9
-76
@@ -1,13 +1,14 @@
|
||||
use etcetera::{choose_app_strategy, AppStrategy};
|
||||
use ignore::gitignore::Gitignore;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::developer::goose_hints::import_files::read_referenced_files;
|
||||
use crate::config::paths::Paths;
|
||||
use crate::hints::import_files::read_referenced_files;
|
||||
|
||||
pub const GOOSE_HINTS_FILENAME: &str = ".goosehints";
|
||||
pub const AGENTS_MD_FILENAME: &str = "AGENTS.md";
|
||||
|
||||
fn find_git_root(start_dir: &Path) -> Option<&Path> {
|
||||
let mut check_dir = start_dir;
|
||||
@@ -59,22 +60,7 @@ pub fn load_hint_files(
|
||||
let mut local_hints_contents = Vec::with_capacity(hints_filenames.len());
|
||||
|
||||
for hints_filename in hints_filenames {
|
||||
// Global hints
|
||||
// choose_app_strategy().config_dir()
|
||||
// - macOS/Linux: ~/.config/goose/
|
||||
// - Windows: ~\AppData\Roaming\Block\goose\config\
|
||||
// keep previous behavior of expanding ~/.config in case this fails
|
||||
let global_hints_path = choose_app_strategy(crate::APP_STRATEGY.clone())
|
||||
.map(|strategy| strategy.in_config_dir(hints_filename))
|
||||
.unwrap_or_else(|_| {
|
||||
let path_str = format!("~/.config/goose/{}", hints_filename);
|
||||
PathBuf::from(shellexpand::tilde(&path_str).to_string())
|
||||
});
|
||||
|
||||
if let Some(parent) = global_hints_path.parent() {
|
||||
let _ = std::fs::create_dir_all(parent);
|
||||
}
|
||||
|
||||
let global_hints_path = Paths::in_config_dir(hints_filename);
|
||||
if global_hints_path.is_file() {
|
||||
let mut visited = HashSet::new();
|
||||
let hints_dir = global_hints_path.parent().unwrap();
|
||||
@@ -116,7 +102,7 @@ pub fn load_hint_files(
|
||||
|
||||
let mut hints = String::new();
|
||||
if !global_hints_contents.is_empty() {
|
||||
hints.push_str("\n### Global Hints\nThe developer extension includes some global hints that apply to all projects & directories.\n");
|
||||
hints.push_str("\n### Global Hints\nThese are my global goose hints.\n");
|
||||
hints.push_str(&global_hints_contents.join("\n"));
|
||||
}
|
||||
|
||||
@@ -124,7 +110,9 @@ pub fn load_hint_files(
|
||||
if !hints.is_empty() {
|
||||
hints.push_str("\n\n");
|
||||
}
|
||||
hints.push_str("### Project Hints\nThe developer extension includes some hints for working on the project in this directory.\n");
|
||||
hints.push_str(
|
||||
"### Project Hints\nThese are hints for working on the project in this directory.\n",
|
||||
);
|
||||
hints.push_str(&local_hints_contents.join("\n"));
|
||||
}
|
||||
|
||||
@@ -135,7 +123,6 @@ pub fn load_hint_files(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ignore::gitignore::GitignoreBuilder;
|
||||
use serial_test::serial;
|
||||
use std::fs::{self};
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -146,51 +133,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_global_goosehints() {
|
||||
// if ~/.config/goose/.goosehints exists, it should be included in the instructions
|
||||
// copy the existing global hints file to a .bak file
|
||||
let global_hints_path = PathBuf::from(
|
||||
shellexpand::tilde(format!("~/.config/goose/{}", GOOSE_HINTS_FILENAME).as_str())
|
||||
.to_string(),
|
||||
);
|
||||
let global_hints_bak_path = PathBuf::from(
|
||||
shellexpand::tilde(format!("~/.config/goose/{}.bak", GOOSE_HINTS_FILENAME).as_str())
|
||||
.to_string(),
|
||||
);
|
||||
let mut globalhints_existed = false;
|
||||
|
||||
if global_hints_path.is_file() {
|
||||
globalhints_existed = true;
|
||||
fs::copy(&global_hints_path, &global_hints_bak_path).unwrap();
|
||||
}
|
||||
|
||||
fs::write(&global_hints_path, "These are my global goose hints.").unwrap();
|
||||
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
let gitignore = create_dummy_gitignore();
|
||||
let hints = load_hint_files(dir.path(), &[GOOSE_HINTS_FILENAME.to_string()], &gitignore);
|
||||
|
||||
assert!(hints.contains("### Global Hints"));
|
||||
assert!(hints.contains("my global goose hints."));
|
||||
|
||||
// restore backup if globalhints previously existed
|
||||
if globalhints_existed {
|
||||
fs::copy(&global_hints_bak_path, &global_hints_path).unwrap();
|
||||
fs::remove_file(&global_hints_bak_path).unwrap();
|
||||
} else {
|
||||
// Clean up the test file we created
|
||||
let _ = fs::remove_file(&global_hints_path);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_goosehints_when_present() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
fs::write(dir.path().join(GOOSE_HINTS_FILENAME), "Test hint content").unwrap();
|
||||
let gitignore = create_dummy_gitignore();
|
||||
@@ -200,10 +144,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_goosehints_when_missing() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
let gitignore = create_dummy_gitignore();
|
||||
let hints = load_hint_files(dir.path(), &[GOOSE_HINTS_FILENAME.to_string()], &gitignore);
|
||||
@@ -212,10 +154,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_goosehints_multiple_filenames() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
fs::write(
|
||||
dir.path().join("CLAUDE.md"),
|
||||
@@ -240,10 +180,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_goosehints_configurable_filename() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::env::set_current_dir(dir.path()).unwrap();
|
||||
|
||||
fs::write(dir.path().join("CLAUDE.md"), "Custom hints file content").unwrap();
|
||||
let gitignore = create_dummy_gitignore();
|
||||
@@ -357,11 +295,7 @@ mod tests {
|
||||
|
||||
fs::create_dir(project_root.join(".git")).unwrap();
|
||||
|
||||
fs::write(
|
||||
project_root.join("README.md"),
|
||||
"# Project README\nProject overview content",
|
||||
)
|
||||
.unwrap();
|
||||
fs::write(project_root.join("README.md"), "# Project README").unwrap();
|
||||
fs::write(project_root.join("config.md"), "Configuration details").unwrap();
|
||||
|
||||
let hints_content = r#"Project hints content
|
||||
@@ -382,7 +316,6 @@ Additional instructions here."#;
|
||||
|
||||
assert!(hints.contains("--- Content from README.md ---"));
|
||||
assert!(hints.contains("# Project README"));
|
||||
assert!(hints.contains("Project overview content"));
|
||||
assert!(hints.contains("--- End of README.md ---"));
|
||||
|
||||
assert!(hints.contains("--- Content from config.md ---"));
|
||||
@@ -0,0 +1,4 @@
|
||||
mod import_files;
|
||||
pub mod load_hints;
|
||||
|
||||
pub use load_hints::{load_hint_files, AGENTS_MD_FILENAME, GOOSE_HINTS_FILENAME};
|
||||
@@ -3,6 +3,7 @@ pub mod config;
|
||||
pub mod context_mgmt;
|
||||
pub mod conversation;
|
||||
pub mod execution;
|
||||
pub mod hints;
|
||||
pub mod logging;
|
||||
pub mod mcp_utils;
|
||||
pub mod model;
|
||||
|
||||
Reference in New Issue
Block a user