Skip to content

Commit dc64487

Browse files
committed
Path fall back .amazonq to .kiro migration functionality
- Support workspace and global path migration - Maintain backward compatibility with existing .amazonq configs - Follow proper precedence rules (amazonq > kiro when both exist) - Add comprehensive unit tests covering all migration scenarios -
1 parent e3cf013 commit dc64487

File tree

6 files changed

+336
-44
lines changed

6 files changed

+336
-44
lines changed

crates/agent/src/agent/agent_config/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ use tracing::{
3434
use super::util::directories::{
3535
global_agents_path,
3636
legacy_global_mcp_config_path,
37-
};
38-
use crate::agent::util::directories::{
3937
legacy_workspace_mcp_config_path,
4038
local_agents_path,
4139
};

crates/agent/src/agent/util/directories.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use super::error::{
1414
use crate::agent::util::consts::env_var::CLI_DATA_DIR;
1515

1616
const DATA_DIR_NAME: &str = "amazon-q";
17-
const AWS_DIR_NAME: &str = "amazonq";
1817

1918
type Result<T, E = UtilError> = std::result::Result<T, E>;
2019

@@ -57,28 +56,51 @@ pub fn settings_schema_path(base: impl AsRef<Path>) -> PathBuf {
5756
base.as_ref().join("settings_schema.json")
5857
}
5958

59+
fn resolve_migrated_path(is_global: bool, subpath: &str) -> Result<PathBuf> {
60+
let (kiro_base, amazonq_base) = if is_global {
61+
let home = home_dir()?;
62+
(home.join(".aws/kiro"), home.join(".aws/amazonq"))
63+
} else {
64+
let cwd = env::current_dir()
65+
.context("unable to get the current directory")?;
66+
(cwd.join(".kiro"), cwd.join(".amazonq"))
67+
};
68+
69+
let scope = if is_global { "global" } else { "workspace" };
70+
71+
match (kiro_base.exists(), amazonq_base.exists()) {
72+
(true, false) => {
73+
warn!("Using .kiro {} configuration", scope);
74+
Ok(kiro_base.join(subpath))
75+
},
76+
(false, true) => {
77+
warn!("Migration notice: Using .amazonq {} configs", scope);
78+
Ok(amazonq_base.join(subpath))
79+
},
80+
(true, true) => {
81+
warn!("Both .amazonq and .kiro {} configs exist, using .amazonq", scope);
82+
Ok(amazonq_base.join(subpath))
83+
},
84+
(false, false) => Ok(kiro_base.join(subpath)), // Default to kiro
85+
}
86+
}
87+
6088
/// Path to the directory containing local agent configs.
6189
pub fn local_agents_path() -> Result<PathBuf> {
62-
Ok(env::current_dir()
63-
.context("unable to get the current directory")?
64-
.join(format!(".{}", AWS_DIR_NAME))
65-
.join("cli-agents"))
90+
resolve_migrated_path(false, "cli-agents")
6691
}
6792

6893
/// Path to the directory containing global agent configs.
6994
pub fn global_agents_path() -> Result<PathBuf> {
70-
Ok(home_dir()?.join(".aws").join(AWS_DIR_NAME).join("cli-agents"))
95+
resolve_migrated_path(true, "cli-agents")
7196
}
7297

7398
/// Legacy workspace MCP server config path
7499
pub fn legacy_workspace_mcp_config_path() -> Result<PathBuf> {
75-
Ok(env::current_dir()
76-
.context("unable to get the current directory")?
77-
.join(format!(".{}", AWS_DIR_NAME))
78-
.join("mcp.json"))
100+
resolve_migrated_path(false, "mcp.json")
79101
}
80102

81103
/// Legacy global MCP server config path
82104
pub fn legacy_global_mcp_config_path() -> Result<PathBuf> {
83-
Ok(home_dir()?.join(".aws").join(AWS_DIR_NAME).join("mcp.json"))
105+
resolve_migrated_path(true, "mcp.json")
84106
}

crates/chat-cli/src/cli/agent/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ impl Default for Agent {
197197
resources: {
198198
let mut resources = Vec::new();
199199
resources.extend(paths::workspace::DEFAULT_AGENT_RESOURCES.iter().map(|&s| s.into()));
200-
resources.push(format!("file://{}", paths::workspace::RULES_PATTERN).into());
200+
// Default fallback pattern - will be updated dynamically in load() function
201+
resources.push("file://.amazonq/rules/**/*.md".into());
201202
resources
202203
},
203204
hooks: Default::default(),
@@ -742,6 +743,16 @@ impl Agents {
742743

743744
all_agents.push({
744745
let mut agent = Agent::default();
746+
747+
// Update rules pattern to use dynamic path resolution
748+
if let Ok(rules_dir) = resolver.workspace().rules_dir() {
749+
let rules_pattern = format!("{}/**/*.md", rules_dir.display());
750+
// Replace the hardcoded rules pattern with the dynamic one
751+
if let Some(pos) = agent.resources.iter().position(|r| r.as_str().contains(".amazonq/rules/")) {
752+
agent.resources[pos] = format!("file://{}", rules_pattern).into();
753+
}
754+
}
755+
745756
if mcp_enabled {
746757
'load_legacy_mcp_json: {
747758
if global_mcp_config.is_none() {

crates/chat-cli/src/cli/agent/root_command_args.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use super::{
2525
use crate::database::settings::Setting;
2626
use crate::os::Os;
2727
use crate::theme::StyledText;
28-
use crate::util::paths;
2928
use crate::util::paths::PathResolver;
3029

3130
#[derive(Clone, Debug, Subcommand, PartialEq, Eq)]
@@ -337,7 +336,7 @@ pub async fn create_agent(
337336
bail!("Path must be a directory");
338337
}
339338

340-
path.join(paths::workspace::AGENTS_DIR)
339+
PathResolver::new(os).workspace().agents_dir()?
341340
} else {
342341
PathResolver::new(os).global().agents_dir()?
343342
};

crates/chat-cli/src/cli/chat/cli/prompts.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -733,10 +733,13 @@ impl PromptsArgs {
733733
}
734734

735735
if !global_prompts.is_empty() {
736+
let global_dir = PathResolver::new(os).global().prompts_dir()
737+
.map(|p| p.display().to_string())
738+
.unwrap_or_else(|_| "global prompts".to_string());
736739
queue!(
737740
session.stderr,
738741
style::SetAttribute(Attribute::Bold),
739-
style::Print(&format!("Global ({}):", crate::util::paths::global::PROMPTS_DIR)),
742+
style::Print(&format!("Global ({}):", global_dir)),
740743
StyledText::reset_attributes(),
741744
style::Print("\n"),
742745
)?;
@@ -750,10 +753,13 @@ impl PromptsArgs {
750753
if !global_prompts.is_empty() {
751754
queue!(session.stderr, style::Print("\n"))?;
752755
}
756+
let local_dir = PathResolver::new(os).workspace().prompts_dir()
757+
.map(|p| p.display().to_string())
758+
.unwrap_or_else(|_| "local prompts".to_string());
753759
queue!(
754760
session.stderr,
755761
style::SetAttribute(Attribute::Bold),
756-
style::Print(&format!("Local ({}):", crate::util::paths::workspace::PROMPTS_DIR)),
762+
style::Print(&format!("Local ({}):", local_dir)),
757763
StyledText::reset_attributes(),
758764
style::Print("\n"),
759765
)?;
@@ -2069,8 +2075,8 @@ mod tests {
20692075
let temp_dir = TempDir::new().unwrap();
20702076

20712077
// Create test prompts in temp directory structure
2072-
let global_dir = temp_dir.path().join(crate::util::paths::global::PROMPTS_DIR);
2073-
let local_dir = temp_dir.path().join(crate::util::paths::workspace::PROMPTS_DIR);
2078+
let global_dir = temp_dir.path().join(".aws/amazonq/prompts");
2079+
let local_dir = temp_dir.path().join(".amazonq/prompts");
20742080

20752081
create_prompt_file(&global_dir, "global_only", "Global content");
20762082
create_prompt_file(&global_dir, "shared", "Global shared");
@@ -2090,8 +2096,8 @@ mod tests {
20902096
let temp_dir = TempDir::new().unwrap();
20912097

20922098
// Create global and local directories
2093-
let global_dir = temp_dir.path().join(crate::util::paths::global::PROMPTS_DIR);
2094-
let local_dir = temp_dir.path().join(crate::util::paths::workspace::PROMPTS_DIR);
2099+
let global_dir = temp_dir.path().join(".aws/amazonq/prompts");
2100+
let local_dir = temp_dir.path().join(".amazonq/prompts");
20952101

20962102
// Create prompts: one with same name in both directories, one unique to each
20972103
create_prompt_file(&global_dir, "shared", "Global version");

0 commit comments

Comments
 (0)