diff --git a/.gitignore b/.gitignore index 8e9330d0ea..27a2ddd3d9 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,7 @@ book/ .env* run-build.sh + +# Test artifacts +.kiro +e2etests/reports \ No newline at end of file diff --git a/e2etests/.gitignore b/e2etests/.gitignore index e2644ec46e..f9344cfd40 100644 --- a/e2etests/.gitignore +++ b/e2etests/.gitignore @@ -1,2 +1,4 @@ qcli_test_summary*.json -qcli_test_summary*.html \ No newline at end of file +qcli_test_summary*.html +report-analysis/ +.amazonq/ \ No newline at end of file diff --git a/e2etests/Cargo.lock b/e2etests/Cargo.lock index 6a810dc65e..7548339d7d 100644 --- a/e2etests/Cargo.lock +++ b/e2etests/Cargo.lock @@ -23,6 +23,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + [[package]] name = "cfg-if" version = "1.0.1" @@ -38,6 +44,16 @@ dependencies = [ "windows", ] +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "expectrl" version = "0.7.1" @@ -50,12 +66,104 @@ dependencies = [ "regex", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "libc" version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + [[package]] name = "memchr" version = "2.7.5" @@ -77,19 +185,63 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset", "pin-utils", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + [[package]] name = "ptyprocess" version = "0.4.1" @@ -103,7 +255,28 @@ dependencies = [ name = "q-cli-e2e-tests" version = "0.1.0" dependencies = [ + "ctor", "expectrl", + "regex", + "serial_test", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", ] [[package]] @@ -135,6 +308,81 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + +[[package]] +name = "serial_test" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + [[package]] name = "windows" version = "0.44.0" @@ -144,6 +392,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-targets" version = "0.42.2" diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index 3ab4239a45..3388fa52b1 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -8,13 +8,18 @@ edition = "2021" [dependencies] expectrl = "0.7" regex = "1.0" +serial_test = "3.0" +ctor = "0.2" + [features] -core_session = ["help", "quit", "clear", "changelog"] # Core Session Commands (/help, /quit, /clear, /changelog) +core_session = ["help","tangent", "quit", "clear", "changelog","introspect"] # Core Session Commands (/help,/tangent, /quit, /clear, /changelog,introspect) help = [] # Help Command (/help) +tangent = [] # Tangent Command (/tangent) quit = [] # Quit Command (/quit) clear = [] # Clear Command (/clear) changelog = [] # Changelog Command (/changelog) +introspect = [] # Introspect Command (introspect) tools = [] # Tools Command (/tools) agent = [] # Agent Commands (/agent list, /agent create, etc.) @@ -35,10 +40,18 @@ issue_reporting = [] # Issue Reporting Commands mcp = [] # MCP Commands (/mcp, /mcp --help) ai_prompts = [] # AI Prompts ("What is AWS?", "Hello") -q_subcommand = [] # Q SubCommand (q chat, q doctor, q translate) +kiro_cli_subcommand = [] # Kiro-cli SubCommand (q chat, q doctor, q translate) todos = [] # todos command experiment=[] # experiment command regression = [] # Regression Tests sanity = [] # Sanity Tests - Quick smoke tests for basic functionality +deprecated = [] # Deprecated Tests +kiro_steering = [] # Kiro Steering Tests +sub_integrations = [] # Kiro-Cli integrations subcommand +setup_subcommands = [] # KIRO-CLI setup subcommand +diagnostics = [] # KIRO-CLI diagnostics subcommand +init_subcommand = [] # KIRO-CLI init subcommand +theme_subcommand = [] # KIRO-CLI thenme subcomnmand +issue_subcommand = [] # KIRO-CLI issue subcommand diff --git a/e2etests/analysis_report_template.html b/e2etests/analysis_report_template.html new file mode 100644 index 0000000000..a21c6fd7e3 --- /dev/null +++ b/e2etests/analysis_report_template.html @@ -0,0 +1,857 @@ + + +
+ + +Generated on:
+ ++ Critical performance metrics across all test executions, providing executive-level insights and benchmarks for comparison. +
++ Historical view of test execution duration and test count over time, helping identify performance trends and test suite growth. +
++ Individual feature performance tracking over time. Select a feature to view its execution duration and test count history. +
++ This histogram compares the latest execution time of each feature against its average of the last 3 executions. + Green bars indicate features performing at or better than their recent average, while red bars show features + taking longer than their recent average performance. +
++ This chart shows multiple performance metrics for each feature side by side. Latest execution uses red/green logic + (red if > last 3 avg, green otherwise), while other metrics use consistent colors for easy comparison. +
++ Chronological summary of all test executions with duration comparisons against historical averages. Recent executions shown first. +
+| Date | +Total Tests | +Total Failed | +Duration (minutes) | +Duration (hours) | +vs Average | +
|---|
+ Detailed performance metrics for each feature including latest execution time with color-coded performance indicators. +
+| Feature ↕ | +Latest Time (min) ↕ | +Avg Duration (min) ↕ | +Avg Last 3 (min) ↕ | +Avg Last 5 (min) ↕ | +Best w/ Same Tests ↕ | +
|---|
+ Comprehensive analysis of execution time changes with comparisons against multiple baselines and feature-level breakdowns. +
+ ++ Pass/fail status matrix showing feature reliability over time. Green indicates pass, red indicates failure, gray indicates not tested. +
+| Feature | +
|---|
+ Statistical analysis of feature failure rates, helping identify the most problematic features requiring attention. +
+| Feature ↕ | +Failure Rate (%) ↕ | +Total Runs ↕ | +Failed Runs ↕ | +
|---|
Platform: {platform}
-Q Binary: {q_binary_info}
+Binary: {q_binary_info}
/agent command without subcommands to display help information. Verifies agent management description, usage, available subcommands, and options");
-
- let session = get_chat_session();
+
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent")?;
-
+
+ let response = chat.execute_command_with_timeout("/agent",Some(1000))?;
+
println!("📝 Agent response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- assert!(response.contains("Manage agents"), "Missing 'Manage agents' description");
- assert!(response.contains("Usage:"), "Missing usage information");
- assert!(response.contains("/agent"), "Missing agent command");
- assert!(response.contains(" /agent create command to create a new agent with specified name. Verifies agent creation process, file system operations, and cleanup");
-
+
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let agent_name = format!("test_demo_agent_{}", timestamp);
-
- let session = get_chat_session();
+
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let create_response = chat.execute_command(&format!("/agent create --name {}", agent_name))?;
-
+
+ let create_response = chat.execute_command_with_timeout(&format!("/agent create --name {}", agent_name),Some(1000))?;
+
println!("📝 Agent create response: {} bytes", create_response.len());
println!("📝 CREATE RESPONSE:");
println!("{}", create_response);
println!("📝 END CREATE RESPONSE");
-
+
let save_response = chat.execute_command(":wq")?;
-
+
println!("📝 Save response: {} bytes", save_response.len());
println!("📝 SAVE RESPONSE:");
println!("{}", save_response);
println!("📝 END SAVE RESPONSE");
-
- assert!(save_response.contains("Agent") && save_response.contains(&agent_name) && save_response.contains("has been created successfully"), "Missing agent creation success message");
- println!("✅ Found agent creation success message");
-
- let whoami_response = chat.execute_command("!whoami")?;
-
- println!("📝 Whoami response: {} bytes", whoami_response.len());
- println!("📝 WHOAMI RESPONSE:");
- println!("{}", whoami_response);
- println!("📝 END WHOAMI RESPONSE");
-
+
+ assert!(save_response.contains("Agent") && save_response.contains(&agent_name) && save_response.contains("has been created successfully"), "Expected output 'Agent has been created successfully' is missing in response");
+
+ let whoami_response = chat.execute_command_with_timeout("!whoami",Some(1000))?;
+
let lines: Vec<&str> = whoami_response.lines().collect();
let username = lines.iter()
.find(|line| !line.starts_with("!") && !line.starts_with(">") && !line.trim().is_empty())
- .expect("Failed to get username from whoami command")
+ .expect("Expected output 'username' is missing in whoami response")
.trim();
- println!("✅ Current username: {}", username);
-
- let agent_path = format!("/Users/{}/.aws/amazonq/cli-agents/{}.json", username, agent_name);
- println!("✅ Agent path: {}", agent_path);
-
+
+ let home_dir = std::env::var("HOME").unwrap_or_else(|_| format!("/home/{}", username));
+ let agent_path = format!("{}/.kiro/agents/{}.json", home_dir, agent_name);
+
if std::path::Path::new(&agent_path).exists() {
std::fs::remove_file(&agent_path)?;
- println!("✅ Agent file deleted: {}", agent_path);
} else {
println!("⚠️ Agent file not found at: {}", agent_path);
}
-
- assert!(!std::path::Path::new(&agent_path).exists(), "Agent file should be deleted");
- println!("✅ Agent deletion verified");
-
+
+ assert!(!std::path::Path::new(&agent_path).exists(), "Expected output 'agent file deletion' is missing");
+
+ println!("✅ Agent create command executed successfully");
+
// Release the lock before cleanup
drop(chat);
-
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
+
Ok(())
}
+/// Tests the /agent edit command to edit a existing agent with specified name
+/// Verifies agent edit process, file system operations, and cleanup
+#[test]
+#[cfg(all(feature = "agent", feature = "sanity"))]
+fn test_agent_edit_command() -> Result<(), Box /agent edit command to edit a existing agent. Verifies agent edit process, file system operations, and cleanup");
+
+ let timestamp = std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .unwrap()
+ .as_secs();
+ let agent_name = format!("test_demo_agent_{}", timestamp);
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ chat.execute_command_with_timeout(&format!("/agent create --name {}", agent_name),Some(1000))?;
+
+ let save_response = chat.execute_command(":wq")?;
+
+ assert!(save_response.contains("Agent") && save_response.contains(&agent_name) && save_response.contains("has been created successfully"), "Expected output 'Agent has been created successfully' is missing in response");
+
+ // Edit the agent description
+ let edit_response = chat.execute_command_with_timeout(&format!("/agent edit --name {}", agent_name),Some(2000))?;
+
+ println!("📝 Agent edit response: {} bytes", edit_response.len());
+ println!("📝 EDIT RESPONSE:");
+ println!("{}", edit_response);
+ println!("📝 END EDIT RESPONSE");
+
+
+ // Use line-based editing
+ chat.execute_command("/description")?; // Search for description line
+ chat.execute_command("S")?; // Delete line and enter insert mode
+ chat.execute_command(" \"description\": \"Updated agent description for testing\",")?;
+ chat.execute_command("\u{1b}")?; // ESC
+
+ let save_edit = chat.execute_command(":wq")?;
+
+ println!("📝 Edit save response: {} bytes", save_edit.len());
+ println!("📝 EDIT SAVE RESPONSE:");
+ println!("{}", save_edit);
+ println!("📝 END EDIT SAVE RESPONSE");
+
+ assert!(save_edit.contains("Agent") && save_edit.contains(&agent_name) && save_edit.contains("has been edited successfully"), "Expected output 'has been edited successfully' is missing in response");
+ println!("✅ /agent edit executed successfully with expected response.");
+ let whoami_response = chat.execute_command_with_timeout("!whoami",Some(500))?;
+
+ let lines: Vec<&str> = whoami_response.lines().collect();
+ let username = lines.iter()
+ .find(|line| !line.starts_with("!") && !line.starts_with(">") && !line.trim().is_empty())
+ .expect("Expected output 'username' is missing in whoami response")
+ .trim();
+
+ let home_dir = std::env::var("HOME").unwrap_or_else(|_| format!("/home/{}", username));
+ let agent_path = format!("{}/.kiro/agents/{}.json", home_dir, agent_name);
+
+ if std::path::Path::new(&agent_path).exists() {
+ std::fs::remove_file(&agent_path)?;
+ } else {
+ println!("⚠️ Agent file not found at: {}", agent_path);
+ }
+
+ assert!(!std::path::Path::new(&agent_path).exists(), "Agent file should be deleted");
+ //Release the lock before cleanup
+ drop(chat);
+
+ Ok(())
+}
/// Tests the /agent create command without required arguments to verify error handling
/// Verifies proper error messages, usage information, and help suggestions
#[test]
#[cfg(all(feature = "agent", feature = "sanity"))]
fn test_agent_create_missing_args() -> Result<(), Box /agent create command without required arguments to verify error handling. Verifies proper error messages, usage information, and help suggestions");
-
- let session = get_chat_session();
+
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent create")?;
-
+
+ let response = chat.execute_command_with_timeout("/agent create",Some(2000))?;
+
println!("📝 Agent create missing args response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- assert!(response.contains("error:"), "Missing error message part 1a");
- assert!(response.contains("the following required arguments"), "Missing error message part 1b");
- assert!(response.contains("were not provided:"), "Missing error message part 2");
- assert!(response.contains("--name"), "Missing required name argument part 1");
- assert!(response.contains(" /agent help command to display comprehensive agent help information. Verifies agent descriptions, usage notes, launch instructions, and configuration paths");
-
- let session = get_chat_session();
+
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent help")?;
-
+
+ let response = chat.execute_command_with_timeout("/agent help",Some(1000))?;
+
println!("📝 Agent help command response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- assert!(response.contains("~/.aws/amazonq/cli-agents/"), "Missing global path");
- assert!(response.contains("cwd/.amazonq/cli-agents"), "Missing workspace path");
- assert!(response.contains("Usage:"), "Missing usage label");
- assert!(response.contains("/agent"), "Missing agent command");
- assert!(response.contains(" /agent command with invalid subcommand to verify error handling. Verifies that invalid commands display help information with available commands and options");
-
- let session = get_chat_session();
+
+ let session =q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent invalidcommand")?;
-
+
+ let response = chat.execute_command_with_timeout("/agent invalidcommand",Some(1000))?;
+
println!("📝 Agent invalid command response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- assert!(response.contains("Commands:"), "Missing commands section");
- assert!(response.contains("list"), "Missing list command");
- assert!(response.contains("create"), "Missing create command");
- assert!(response.contains("schema"), "Missing schema command");
- assert!(response.contains("set-default"), "Missing set-default command");
- assert!(response.contains("help"), "Missing help command");
- println!("✅ Found all expected commands in help output");
-
- assert!(response.contains("Options:"), "Missing options section");
- println!("✅ Found options section");
-
- println!("✅ /agent invalidcommand executed successfully with expected error");
-
+
+ assert!(response.contains("Commands"), "Expected output 'Commands' is missing in response");
+ assert!(response.contains("list"), "Expected output 'list' is missing in response");
+ assert!(response.contains("create"), "Expected output 'create' is missing in response");
+ assert!(response.contains("schema"), "Expected output 'schema' is missing in response");
+ assert!(response.contains("set-default"), "Expected output 'set-default' is missing in response");
+ assert!(response.contains("help"), "Expected output 'help' is missing in response");
+ assert!(response.contains("Options"), "Expected output 'Options' is missing in response");
+
+ println!("✅ /agent invalid command executed successfully with expected error");
+
// Release the lock before cleanup
drop(chat);
-
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
+
Ok(())
}
@@ -316,113 +299,88 @@ fn test_agent_invalid_command() -> Result<(), Box /agent list command to display all available agents. Verifies agent listing format and presence of default agent");
-
- let session = get_chat_session();
+
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent list")?;
-
+
+ let response = chat.execute_command_with_timeout("/agent list",Some(1000))?;
+
println!("📝 Agent list response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- assert!(response.contains("q_cli_default"), "Missing q_cli_default agent");
- println!("✅ Found q_cli_default agent in list");
-
- assert!(response.contains("* q_cli_default"), "Missing bullet point format for q_cli_default");
- println!("✅ Verified bullet point format for agent list");
-
+
+ assert!(response.contains("kiro_default"), "Expected output 'kiro_default' is missing in response");
+
+ assert!(response.contains("* kiro_default"), "Expected output '* kiro_default' is missing in response");
+
println!("✅ /agent list command executed successfully");
-
+
// Release the lock before cleanup
drop(chat);
-
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
+
Ok(())
}
-/// Tests the /agent schema command to display agent configuration schema
-/// Verifies JSON schema structure with required keys and properties
-// #[test]
-// #[cfg(feature = "agent")]
-// fn test_agent_schema_command() -> Result<(), Box /agent set-default command with valid arguments to set default agent. Verifies success messages and confirmation of default agent configuration");
-
- let session = get_chat_session();
+
+ let session =q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent set-default -n q_cli_default")?;
-
+ let _ = chat.execute_command("clear");
+ let _ = chat.execute_command("\x0C");
+
+ let response = chat.execute_command_with_timeout("/agent set-default -n kiro_default",Some(1000))?;
+
println!("📝 Agent set-default command response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- let mut failures = Vec::new();
-
- if !response.contains("✓") { failures.push("Missing success checkmark"); }
- if !response.contains("Default agent set to") { failures.push("Missing success message"); }
- if !response.contains("q_cli_default") { failures.push("Missing agent name"); }
- if !response.contains("This will take effect") { failures.push("Missing effect message"); }
- if !response.contains("next time q chat is launched") { failures.push("Missing launch message"); }
-
- if !failures.is_empty() {
- panic!("Test failures: {}", failures.join(", "));
- }
-
- println!("✅ All expected success messages found");
+
+ assert!(response.contains("✓"), "Expected output '✓' is missing in response");
+ assert!(response.contains("Default agent set to"), "Expected output 'Default agent set to' is missing in response");
+ assert!(response.contains("kiro_default"), "Expected output 'kiro_default' is missing in response");
+ assert!(response.contains("This will take effect"), "Expected output 'This will take effect' is missing in response");
+ assert!(response.contains("next time kiro-cli chat is launched"), "Expected output 'next time kiro-cli chat is launched' is missing in response");
+
println!("✅ /agent set-default executed successfully with valid arguments");
-
+
// Release the lock before cleanup
drop(chat);
-
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
+
+
+ Ok(())
+}
+// Tests the /agent schema command to display agent configuration schema
+// Verifies JSON schema structure with required keys and properties
+#[test]
+#[cfg(all(feature = "agent", feature = "sanity"))]
+fn test_agent_schema_command() -> Result<(), Box /agent schema command to display agent configuration schema. Verifies JSON schema structure with required keys and properties");
+
+ let session = q_chat_helper::get_new_chat_session()?;
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+ let schema_response = chat.execute_command_with_timeout("/agent schema",Some(1000))?;
+
+ println!("📝 Agent schema response: {} bytes", schema_response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", schema_response);
+ println!("📝 END OUTPUT");
+
+ assert!(schema_response.contains("$schema"), "Expected output '$schema' is missing in response");
+ assert!(schema_response.contains("title"), "Expected output 'title' is missing in response");
+ assert!(schema_response.contains("description"), "Expected output 'description' is missing in response");
+ assert!(schema_response.contains("type"), "Expected output 'type' is missing in response");
+ assert!(schema_response.contains("properties"), "Expected output 'properties' is missing in response");
+ assert!(schema_response.contains("name"), "Expected output 'name' is missing in response");
+
+ println!("✅ /agent schema executed successfully with valid JSON schema");
+
+ drop(chat);
Ok(())
}
@@ -432,46 +390,125 @@ fn test_agent_set_default_command() -> Result<(), Box /agent set-default command without required arguments to verify error handling. Verifies error messages, usage information, and available options display");
-
- let session = get_chat_session();
+
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
-
- let response = chat.execute_command("/agent set-default")?;
-
+ let response = chat.execute_command_with_timeout("/agent set-default",Some(2000))?;
+
println!("📝 Agent set-default missing args response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
- let mut failures = Vec::new();
-
- if !response.contains("error") { failures.push("Missing error message"); }
- if !response.contains("the following required arguments were not provided:") { failures.push("Missing error message2"); }
- if !response.contains("--name /agent generatecommand with vi editor interaction");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+ // Clear any previous session output to prevent contamination
+ let _ = chat.execute_command("clear");
+ // Start the command and wait for name prompt
+ let response = chat.execute_command_with_timeout("/agent generate", Some(20000))?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ // Wait longer for the prompt to fully appear
+ std::thread::sleep(std::time::Duration::from_secs(5));
+
+ // Enter agent name
+ chat.send_key_input("test-agent\r")?;
+ std::thread::sleep(std::time::Duration::from_secs(2));
+ println!("{}", response);
+
+ // Enter description
+ chat.send_key_input("Test agent description\r")?;
+ std::thread::sleep(std::time::Duration::from_secs(2));
+ println!("{}", response);
+
+ // Select scope (Enter for default)
+ chat.send_key_input("\r")?;
+ std::thread::sleep(std::time::Duration::from_secs(2));
+ println!("{}", response);
+
+ // Wait for MCP menu, then confirm (Enter)
+ let _final_response = chat.send_key_input("\r")?;
+
+ // Handle vi editor opening - enter insert mode and add content
+ chat.send_key_input("i")?; // Enter insert mode
+ // chat.send_key_input("Test system instructions for the agent")?;
+ chat.send_key_input("\u{1b}")?; // ESC to exit insert mode
+
+ std::thread::sleep(std::time::Duration::from_secs(3));
+
+ // Get final response
+ let final_response = chat.execute_command(":wq")?;
+ println!("📝 Final response: {}", final_response);
+
+ assert!(
+ final_response.contains("has been created and saved successfully") ||
+ final_response.contains("Generating agent config") ||
+ final_response.contains("Agent 'test-agent'"),
+ "Expected output 'agent creation confirmation' is missing in response"
+ );
+ println!("✅ /agent generate executed successfully with expected response");
+ drop(chat);
+ Ok(())
+
+}
+
+// Tests the /agent swap command to swap the agents
+// Verifies agent swap process and response validation
+#[test]
+#[cfg(all(feature = "agent", feature = "sanity"))]
+fn test_agent_swap_command() -> Result<(), Box /agent swapcommand.");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+ // Clear any previous session output to prevent contamination
+ let _ = chat.execute_command("clear");
+ // Start the command and wait for name prompt
+ let _response1 = chat.execute_command_with_timeout("/agent swap",Some(2000))?;
+ println!("📝 Agent swap response: {} bytes", _response1.len());
+ println!("📝 Full output: {}", _response1);
+ println!("📝 End output");
+ let _response2 = chat.execute_command_with_timeout("1",Some(1000))?;
+ println!("📝 Agent swap response Full output : {}", _response2);
+
+ assert!(
+ _response2.contains("✓") || _response2.contains("Choose one of the following agents"),
+ "Expected output 'agent swap confirmation' is missing in response"
+ );
+ println!("✅ /agent swap executed successfully with expected response");
+ drop(chat);
Ok(())
}
\ No newline at end of file
diff --git a/e2etests/tests/ai_prompts/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs
index 0891e33b9a..e17842a2ae 100644
--- a/e2etests/tests/ai_prompts/test_ai_prompt.rs
+++ b/e2etests/tests/ai_prompts/test_ai_prompt.rs
@@ -1,106 +1,38 @@
#[allow(unused_imports)]
use q_cli_e2e_tests::q_chat_helper;
-use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}};
-#[allow(dead_code)]
-static INIT: Once = Once::new();
-#[allow(dead_code)]
-static mut CHAT_SESSION: OptionAI prompt functionality by sending 'What is AWS?' and verifying the response contains relevant AWS information and technical terms");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap();
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("What is AWS?")?;
+ let response = chat.execute_command_with_timeout("What is AWS?",Some(1000))?;
println!("📝 AI response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
- // Check if we got an actual AI response
- if response.contains("Amazon Web Services") ||
- response.contains("cloud") ||
- response.contains("AWS") ||
- response.len() > 100 {
- println!("✅ Got substantial AI response ({} bytes)!", response.len());
-
- // Additional checks for quality response
- if response.contains("Amazon Web Services") {
- println!("✅ Response correctly identifies 'Amazon Web Services'");
- }
- if response.contains("cloud") {
- println!("✅ Response mentions cloud computing concepts");
- }
- if response.contains("AWS") {
- println!("✅ Response uses AWS acronym appropriately");
- }
-
- // Check for technical depth
- let technical_terms = ["service", "platform", "infrastructure", "compute", "storage"];
- let found_terms: Vec<&str> = technical_terms.iter()
- .filter(|&&term| response.to_lowercase().contains(term))
- .copied()
- .collect();
- if !found_terms.is_empty() {
- println!("✅ Response includes technical terms: {:?}", found_terms);
- }
- } else {
- println!("⚠️ Response seems limited or just echoed input");
- println!("⚠️ Expected AWS explanation but got: {} bytes", response.len());
- }
+ // Assert we got a meaningful AWS response
+ let has_aws_content = response.contains("Amazon Web Services") ||
+ response.contains("cloud") ||
+ response.contains("AWS");
+ assert!(has_aws_content || response.len() > 100, "Response should contain AWS-related content or be substantial (got {} bytes)", response.len());
+
+ // Verify technical depth
+ let technical_terms = ["service", "platform", "infrastructure", "compute", "storage"];
+ let has_technical_terms = technical_terms.iter().any(|&term| response.to_lowercase().contains(term));
+ assert!(has_technical_terms || has_aws_content, "Response should include technical terms or AWS-specific content");
- println!("✅ Test completed successfully");
+ println!("✅ AI prompt test completed successfully");
// Release the lock before cleanup
drop(chat);
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
Ok(())
}
@@ -109,40 +41,31 @@ fn test_what_is_aws_prompt() -> Result<(), Box /prompts command to display available prompts with usage instructions and argument requirements");
-
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
-
- let response = chat.execute_command("/prompts")?;
-
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts",Some(2000))?;
+
println!("📝 Prompts command response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
+
// Verify usage instruction
- assert!(response.contains("Usage:") && response.contains("@") && response.contains(" /prompts --help command to display comprehensive help information about prompts functionality and MCP server integration");
-
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
-
- let response = chat.execute_command("/prompts --help")?;
-
- println!("📝 Prompts help response: {} bytes", response.len());
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts --help",Some(3000))?;
+
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
+
// Verify description
assert!(response.contains("Prompts are reusable templates that help you quickly access common workflows and tasks"), "Missing prompts description");
assert!(response.contains("These templates are provided by the mcp servers you have installed and configured"), "Missing MCP servers description");
- println!("✅ Found prompts description");
-
- // Verify usage examples
- assert!(response.contains("@") && response.contains(" /prompts list command to display all available prompts with their arguments and usage information");
-
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
-
- let response = chat.execute_command("/prompts list")?;
-
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts list",Some(2000))?;
+
println!("📝 Prompts list response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
+
// Verify usage instruction
- assert!(response.contains("Usage:") && response.contains("@") && response.contains(" /prompts get prompt_name command to display all available prompts with their arguments and usage information");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ // Setup - create a test prompt file
+ let prompts_dir = PathBuf::from(".kiro/prompts");
+ let test_prompt_path = prompts_dir.join("test-e2e-prompt.md");
+ fs::create_dir_all(&prompts_dir)?;
+ let prompt_content = r#"---
+ name: test-e2e-prompt
+ ---
+ What is AWS? Explain in 10 words.
+ "#;
+ fs::write(&test_prompt_path, prompt_content)?;
+ let prompt_name = "test-e2e-prompt";
+
+ let get_response = chat.execute_command_with_timeout(&format!("/prompts get {}", prompt_name),Some(2000))?;
+ println!("📝 Get response: {}", get_response);
+
+ assert!(!get_response.is_empty(), "Prompt get command should return content");
+ assert!(get_response.contains("What is AWS? Explain in 10 words."), "Expected prompt content not found in get response");
+ println!("✅ /prompt get command functionality verified!");
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
+ drop(chat);
+
+ // Cleanup - remove the test prompt file
+ fs::remove_file(&test_prompt_path)?;
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "ai_prompts", feature = "sanity"))]
+fn test_create_prompt_command() -> Result<(), Box /prompts create --name promptname command create a new local prompt");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts create --name testprompt",Some(2000))?;
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ // it will open vi editor so we need to add some prmppt then close it using :wp
+ // Enter insert mode
+ chat.send_key_input("i")?;
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // Press enter to go to new line
+ chat.send_key_input("\r")?;
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // Add prompt content
+ chat.send_key_input("This is a test prompt for e2e testing.")?;
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // Exit insert mode
+ chat.send_key_input("\x1B")?;
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // Save and exit vi editor
+ let response = chat.send_key_input(":wq\r")?;
+ std::thread::sleep(std::time::Duration::from_secs(2));
+
+ println!("📝 Prompts list response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Created local prompt"), "Missing Created local prompt");
+ assert!(response.contains("testprompt"), "Missing testprompt");
+ assert!(response.contains("testprompt.md"), "Missing testprompt.md");
+
+ println!("✅ /prompts create command functionality verified!");
+
+ // Release the lock before cleanup
+ drop(chat);
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "ai_prompts", feature = "sanity"))]
+fn test_prompts_details_command() -> Result<(), Box /prompts details command to display detailed information about a specific prompt");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts details testprompt",Some(2000))?;
+
+ println!("📝 Prompts list response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Prompt Details"), "Missing Prompt Details");
+ assert!(response.contains("Name"), "Missing Name");
+ assert!(response.contains("Source"), "Missing Source");
+ assert!(response.contains("Usage"), "Missing Usage");
+ assert!(response.contains("Content Preview"), "Missing Content Preview");
+ assert!(response.contains("testprompt"), "Missing testprompt");
+ assert!(response.contains("This is a test prompt for e2e testing."), "Missing prompt content");
+
+ println!("✅ /prompts details command functionality verified!");
+
+ // Release the lock before cleanup
+ drop(chat);
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "ai_prompts", feature = "sanity"))]
+fn test_prompts_remove_command() -> Result<(), Box /prompts remove command remove an existing local prompt");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts remove testprompt",Some(2000))?;
+
+ println!("📝 Prompts list response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Warning"), "Missing Warning");
+ assert!(response.contains("This will permanently remove the"), "Missing This will permanently remove the message");
+ assert!(response.contains("testprompt"), "Missing testprompt");
+
+ let response = chat.send_key_input("y\r")?;
+ std::thread::sleep(std::time::Duration::from_secs(2));
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Removed local prompt"), "Missing Removed local prompt message");
+ assert!(response.contains("successfully"), "Missing successfully message");
+ assert!(response.contains("testprompt"), "Missing testprompt");
+
+ println!("✅ All prompts remove command functionality verified!");
+
+ // Release the lock before cleanup
+ drop(chat);
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "ai_prompts", feature = "sanity"))]
+fn test_create_prompt_with_content_command() -> Result<(), Box /prompts create --name promptname --content prompt-content command create a new local prompt with prompt content.");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts create --name promptlocaltest --content 'What is java'",Some(2000))?;
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Created local prompt"), "Expected 'Created local prompt' in response.");
+ assert!(response.contains("✓"), "Expected '✓' in response.");
+
+ //delete created prompt
+ let remove_response = chat.execute_command_with_timeout("/prompts remove promptlocaltest",Some(2000))?;
+ println!("Remove Response: {}", remove_response);
+ if remove_response.contains("Are you sure you want to remove this prompt? (y/n):") {
+ chat.send_key_input("y")?;
+ println!("Now removing the created prompt");
+ let enter_response = chat.send_key_input("\r")?;
+ if enter_response.contains("Removed") || enter_response.contains("successfully") {
+ println!("📝 Created prompt removed successfully!");
+ } else {
+ println!("📝 Unable to remove the created prompt.");
+ }
+ }
+ println!("✅ /prompts create --name --content command functionality verified!");
+ // Release the lock before cleanup
+ drop(chat);
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "ai_prompts", feature = "sanity"))]
+fn test_create_prompt_with_content_global_command() -> Result<(), Box /prompts create --name promptname --content prompt-content --global command create a new global prompt with prompt content.");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ let response = chat.execute_command_with_timeout("/prompts create --name promptglobaltest --content 'What is java' --global",Some(2000))?;
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Created global prompt"), "Expected 'Created global prompt' in response.");
+ assert!(response.contains("✓"), "Expected '✓' in response.");
+
+ //delete created prompt
+ let remove_response = chat.execute_command_with_timeout("/prompts remove promptglobaltest --global",Some(2000))?;
+ println!("Remove Response: {}", remove_response);
+ if remove_response.contains("Are you sure you want to remove this prompt? (y/n):") {
+ chat.send_key_input("y")?;
+ println!("Now removing the created prompt");
+ let enter_response = chat.send_key_input("\r")?;
+ if enter_response.contains("Removed") || enter_response.contains("successfully") {
+ println!("📝 Created prompt removed successfully!");
+ } else {
+ println!("📝 Unable to remove the created prompt.");
+ }
+ }
+ println!("✅ /prompts create --name --content --global command functionality verified!");
+ // Release the lock before cleanup
+ drop(chat);
+
Ok(())
}
\ No newline at end of file
diff --git a/e2etests/tests/all_tests.rs b/e2etests/tests/all_tests.rs
index 1a51ea765b..9466ac1992 100644
--- a/e2etests/tests/all_tests.rs
+++ b/e2etests/tests/all_tests.rs
@@ -6,9 +6,23 @@ mod core_session;
mod integration;
mod mcp;
mod model;
-mod q_subcommand;
+mod kiro_cli_subcommand;
mod save_load;
mod session_mgmt;
mod tools;
mod todos;
mod experiment;
+mod kiro_steering;
+mod sub_integrations;
+mod setup_subcommands;
+mod diagnostics;
+mod init_subcommand;
+mod theme_subcommand;
+mod issue_subcommand;
+
+use q_cli_e2e_tests::q_chat_helper;
+
+#[ctor::dtor]
+fn cleanup_session() {
+ let _ = q_chat_helper::close_session();
+}
\ No newline at end of file
diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs
index 6c142744ef..e85bb72544 100644
--- a/e2etests/tests/context/test_context_command.rs
+++ b/e2etests/tests/context/test_context_command.rs
@@ -1,67 +1,15 @@
#[allow(unused_imports)]
use q_cli_e2e_tests::q_chat_helper;
-use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}};
-#[allow(dead_code)]
-static INIT: Once = Once::new();
-#[allow(dead_code)]
-static mut CHAT_SESSION: Option /context show command to display current context information including agent configuration and context files");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/context show")?;
+ let response = chat.execute_command_with_timeout("/context show",Some(500))?;
println!("📝 Context show response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -70,20 +18,15 @@ fn test_context_show_command() -> Result<(), Box /context help command to display comprehensive help information for context management including usage, commands, and options");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/context help")?;
+ let response = chat.execute_command_with_timeout("/context help",Some(500))?;
println!("📝 Context help response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -104,8 +47,8 @@ fn test_context_help_command() -> Result<(), Box /context command without subcommands to verify it displays help information with usage and available commands");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/context")?;
+ let response = chat.execute_command_with_timeout("/context",Some(500))?;
println!("📝 Context response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
- assert!(response.contains("Usage"), "Missing Usage section");
- assert!(response.contains("/context") && response.contains(" /context test command with invalid subcommand to verify proper error handling and help display");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/context test")?;
+ let response = chat.execute_command_with_timeout("/context test",Some(500))?;
println!("📝 Context invalid response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -183,17 +115,14 @@ fn test_context_invalid_command() -> Result<(), Box /context remove command with non-existing file to verify proper error handling");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/context remove non_existent_file.txt")?;
+ let response = chat.execute_command_with_timeout("/context remove non_existent_file.txt",Some(1000))?;
println!("📝 Context remove response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -244,15 +171,13 @@ fn test_context_remove_command_of_non_existent_file() -> Result<(), Box /context add command to add a file to context and /context remove command to remove a file from context");
- let test_file_path = "/tmp/test_context_file_.py";
+ let test_file_path = "/tmp/test_context_unique_file.py";
// Create a test file
std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?;
- println!("✅ Created test file at {}", test_file_path);
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+ // Clear context first to avoid interference from previous tests
+ let _ = chat.execute_command_with_timeout("/context clear", Some(1000));
+
// Add file to context
- let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?;
+ let add_response = chat.execute_command_with_timeout(&format!("/context add {}", test_file_path),Some(1000))?;
println!("📝 Context add response: {} bytes", add_response.len());
println!("📝 ADD RESPONSE:");
@@ -278,11 +205,11 @@ fn test_add_remove_file_context() -> Result<(), Box /changelog command to display version history and updates");
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/changelog")?;
+ let response = chat.execute_command_with_timeout("/changelog",Some(1000))?;
println!("📝 Changelog response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -65,31 +22,24 @@ fn test_changelog_command() -> Result<(), Box /changelog -h command to display help information");
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/changelog -h")?;
+ let response = chat.execute_command_with_timeout("/changelog -h",Some(1000))?;
println!("📝 Help response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -111,18 +61,17 @@ fn test_changelog_help_command() -> Result<(), Box /clear command to clear conversation history and verify that previous context is no longer remembered by the AI");
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
// Send initial message
println!("\n🔍 Sending prompt: 'My name is TestUser'");
- let _initial_response = chat.execute_command("My name is TestUser")?;
+ let _initial_response = chat.execute_command_with_timeout("My name is TestUser",Some(1000))?;
println!("📝 Initial response: {} bytes", _initial_response.len());
println!("📝 INITIAL RESPONSE OUTPUT:");
println!("{}", _initial_response);
@@ -64,13 +21,14 @@ fn test_clear_command() -> Result<(), Box introspect command.");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ println!("✅ Kiro-cli Chat session started");
+
+ let response = chat.execute_command_with_timeout("introspect", Some(3000))?;
+
+ println!("📝 Response: {} bytes", response);
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ if response.contains("I'm Kiro") {
+ assert!(response.contains("I'm Kiro"),"Missing Kiro message");
+ } else if response.contains("Core Capabilities") {
+ assert!(response.contains("Core Capabilities"),"Missing Core Capabilities");
+ } else if response.contains("Available Commands") {
+ assert!(response.contains("Available Commands"),"Missing Available Commands.");
+ } else if response.contains("Experimental Features") {
+ assert!(response.contains("Experimental Features"),"Missing Experimental Features.");
+ }
+
+ println!("✅ Introspect command executed successfully");
+
+ // Release the lock
+ drop(chat);
+
+ Ok(())
+}
\ No newline at end of file
diff --git a/e2etests/tests/core_session/test_command_tangent.rs b/e2etests/tests/core_session/test_command_tangent.rs
new file mode 100644
index 0000000000..cec645f2b2
--- /dev/null
+++ b/e2etests/tests/core_session/test_command_tangent.rs
@@ -0,0 +1,43 @@
+#[allow(unused_imports)]
+use q_cli_e2e_tests::q_chat_helper;
+
+// Test the tangent command.
+#[test]
+#[cfg(all(feature = "core_session", feature = "sanity"))]
+fn test_tangent_command() -> Result<(), Box /tangent command.");
+ let session =q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ // Enable tangent mode first
+ let _enable_result = q_chat_helper::execute_q_subcommand("kiro-cli", &["settings", "chat.enableTangentMode", "true"])?;
+ println!("Enable result: {} ",_enable_result);
+ println!("enable result end.");
+
+ // Wait for settings to take effect
+ std::thread::sleep(std::time::Duration::from_secs(10));
+
+ // Execute the tangent command
+ let response = chat.execute_command("/tangent")?;
+
+ println!("📝 transform response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(!response.is_empty(), "Expected non-empty response");
+
+ // Check if tangent mode is enabled
+ if !response.contains("Tangent mode is disabled") {
+ // Tangent mode is enabled - check for expected content
+ assert!(response.contains("checkpoint") || response.contains("tangent"), "Expected checkpoint or tangent-related message");
+ println!("✅ Tangent command executed with tangent mode enabled");
+ } else {
+ println!("⚠️ Tangent mode still disabled after timeout");
+ }
+
+ println!("Tangent command executed successfully.");
+ drop(chat);
+ Ok(())
+}
\ No newline at end of file
diff --git a/e2etests/tests/core_session/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs
index 3b7f66269a..9732135553 100644
--- a/e2etests/tests/core_session/test_help_command.rs
+++ b/e2etests/tests/core_session/test_help_command.rs
@@ -1,94 +1,171 @@
#[allow(unused_imports)]
use q_cli_e2e_tests::q_chat_helper;
-use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}};
-#[allow(dead_code)]
-static INIT: Once = Once::new();
-#[allow(dead_code)]
-static mut CHAT_SESSION: Option /help command to display all available commands and verify core functionality like quit, clear, tools, and help commands are present");
-
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
- println!("✅ Q Chat session started");
-
- let response = chat.execute_command("/help")?;
-
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ println!("✅ Kiro-cli Chat session started");
+
+ let response = chat.execute_command_with_timeout("/help",Some(100))?;
+
println!("📝 Help response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
println!("{}", response);
println!("📝 END OUTPUT");
-
+
// Verify help content
- assert!(response.contains("Commands:"), "Missing Commands section");
- println!("✅ Found Commands section with all available commands");
-
+ assert!(response.contains("Commands"), "Missing Commands section");
+
assert!(response.contains("quit"), "Missing quit command");
assert!(response.contains("clear"), "Missing clear command");
assert!(response.contains("tools"), "Missing tools command");
assert!(response.contains("help"), "Missing help command");
- println!("✅ Verified core commands: quit, clear, tools, help");
-
+
// Verify specific useful commands
- if response.contains("context") {
- println!("✅ Found context management command");
- }
- if response.contains("agent") {
- println!("✅ Found agent management command");
- }
- if response.contains("model") {
- println!("✅ Found model selection command");
- }
-
+ assert!(response.contains("context"), "Missing context management command");
+ assert!(response.contains("agent"), "Missing agent management command");
+ assert!(response.contains("model"), "Missing model selection command");
+
println!("✅ All help content verified!");
-
- // Release the lock before cleanup
+
+ // Release the lock
drop(chat);
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "help", feature = "sanity"))]
+fn test_multiline_command() -> Result<(), Boxctrl+J multiline command input with embedded newlines");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ println!("✅ Kiro-cli Chat session started");
+
+ // Ctrl+J produces ASCII Line Feed (0x0A)
+ let ctrl_j = "\x0A";
+ let multiline_input = format!("what is aws explain in 100 words.{}what is AI explain in 100 words", ctrl_j);
+ let response = chat.execute_command_with_timeout(&multiline_input,Some(1000))?;
+
+ println!("📝 Response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("AWS"), "Response should contain 'AWS'");
+ assert!(response.contains("AI"), "Response should contain 'AI'");
+ assert!(!response.is_empty(), "Response should not be empty");
+ println!("✅ Multiline input processed successfully");
+
+ drop(chat);
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "help", feature = "sanity"))]
+fn test_whoami_command() -> Result<(), Box !whoami command to display the current user");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ println!("✅ Kiro Chat session started");
+
+ let response = chat.execute_command_with_timeout("!whoami",Some(100))?;
+
+ println!("📝 Help response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ // Verify whoami content
+ assert!(!response.is_empty(), "Empty response from whoami command");
+
+ // Verify response contains user information
+ assert!(response.len() > 0, "Response should contain user information");
+
+ println!("✅ All whoami command functionality verified!");
+
+ // Release the lock
+ drop(chat);
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "help", feature = "sanity"))]
+fn test_ctrls_command() -> Result<(), Boxctrl+s command to display available commands in an interactive menu and verify core commands are accessible");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ println!("✅ Kiro-cli Chat session started");
+
+ // Ctrl+J produces ASCII Line Feed (0x0A)
+ let ctrl_j = "\x13";
+ let response = chat.execute_command_with_timeout(ctrl_j,Some(2000))?;
- // Cleanup only if this is the last test
- cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?;
-
+ let cleaned_response = clean_terminal_output(&response);
+
+ println!("📝 Response: {} bytes", cleaned_response.len());
+ println!("📝 FULL OUTPUT:");
+ println!("{}", cleaned_response);
+ println!("📝 END OUTPUT");
+
+ assert!(cleaned_response.contains("agent"),"Response should contain /agent");
+ assert!(cleaned_response.contains("clear"),"Response should contain /clear");
+ // assert!(cleaned_response.contains("context"),"Response should contain /context");
+ // assert!(cleaned_response.contains("code"),"Response should contain /code");
+ assert!(cleaned_response.contains("changelog"),"Response should contain /changelog");
+
+ //pressing esc button to close ctrl+s window
+ let _esc = chat.execute_command("\x1B")?;
+
+ println!("✅ Ctrl+s input processed successfully");
+
+ drop(chat);
Ok(())
}
+
+#[test]
+#[cfg(all(feature = "help", feature = "sanity"))]
+fn test_multiline_with_alt_enter_command() -> Result<(), BoxAlt(⌥) + Enter(⏎) for multiline input");
+
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+
+ println!("✅ Kiro-cli Chat session started");
+
+ let alt_enter = "\x1B\x0A";
+ let aws_prompt = "what is AWS explain in 100 words ";
+ let ai_rompt = "what is AI explain in 100 words";
+
+ let combined = format!("{}{}{}", aws_prompt, alt_enter,ai_rompt);
+ let response = chat.execute_command_with_timeout(&combined,Some(1000))?;
+
+ println!("📝 Response: {} bytes", response.len());
+ println!("📝 FULL OUTPUT: {}",response);
+ println!("📝 END");
+
+ assert!(response.contains("AWS"), "Response should contain 'AWS'");
+ assert!(response.contains("AI"), "Response should contain 'AI'");
+ assert!(!response.is_empty(), "Response should not be empty");
+
+ println!("✅ Alt+Enter multiline input processed successfully");
+
+ drop(chat);
+ Ok(())
+}
\ No newline at end of file
diff --git a/e2etests/tests/core_session/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs
index e253f5b191..6ced1b045c 100644
--- a/e2etests/tests/core_session/test_quit_command.rs
+++ b/e2etests/tests/core_session/test_quit_command.rs
@@ -1,48 +1,18 @@
#[allow(unused_imports)]
use q_cli_e2e_tests::q_chat_helper;
-use std::sync::{Mutex, Once, atomic::{AtomicUsize}};
-#[allow(dead_code)]
-static INIT: Once = Once::new();
-#[allow(dead_code)]
-static mut CHAT_SESSION: Option /quit command to properly terminate the Q Chat session and exit cleanly");
- let session = get_chat_session();
- let mut chat = session.lock().unwrap();
-
- println!("✅ Q Chat session started");
+ let session = q_chat_helper::get_chat_session();
+ let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
+ println!("✅ Kiro-cli Chat session started");
- chat.execute_command("/quit")?;
+ chat.execute_command_with_timeout("/quit",Some(1000))?;
println!("✅ /quit command executed successfully");
- println!("✅ Test completed successfully");
Ok(())
}
diff --git a/e2etests/tests/diagnostics/mod.rs b/e2etests/tests/diagnostics/mod.rs
new file mode 100644
index 0000000000..ae7ac4a5b9
--- /dev/null
+++ b/e2etests/tests/diagnostics/mod.rs
@@ -0,0 +1 @@
+pub mod test_kiro_cli_diagnostic;
\ No newline at end of file
diff --git a/e2etests/tests/diagnostics/test_kiro_cli_diagnostic.rs b/e2etests/tests/diagnostics/test_kiro_cli_diagnostic.rs
new file mode 100644
index 0000000000..c5d7e87b64
--- /dev/null
+++ b/e2etests/tests/diagnostics/test_kiro_cli_diagnostic.rs
@@ -0,0 +1,192 @@
+#[allow(unused_imports)]
+use q_cli_e2e_tests::q_chat_helper;
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_help_subommand() -> Result<(), Box kiro-cli diagnostics --help subcommand to verify help options.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics --help' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","--help"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Options:"), "Expected 'Options:' in the output");
+ assert!(response.contains("-f"), "Expected '-f' in the output");
+ assert!(response.contains("--format"), "Expected '--format' in the output");
+ assert!(response.contains(" kiro-cli diagnostics --format plain subcommand to verify plain format.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics --format plain' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","--format", "plain"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("system-info"), "Expected 'system-info' in the output");
+ assert!(response.contains("environment"), "Expected 'environment' in the output");
+ assert!(response.contains("env-vars"), "Expected 'env-vars' in the output");
+
+ println!("✅ Kiro Cli diagnostics --format plain subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_json_subommand() -> Result<(), Box kiro-cli diagnostics --format json subcommand to verify json format.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics --format json' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","--format", "json"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("{"), "Expected `{{` in the output");
+ assert!(response.contains("}"), "Expected `}}`in the output");
+ assert!(response.contains("env-vars"), "Expected 'env-vars' in the output");
+ assert!(response.contains("system-info"), "Expected 'system-info' in the output");
+
+ println!("✅ Kiro Cli diagnostics --format json subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_json_pretty_subommand() -> Result<(), Box kiro-cli diagnostics --format json-pretty subcommand to verify json format.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics --format json-pretty' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","--format", "json-pretty"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("{"), "Expected `{{` in the output");
+ assert!(response.contains("}"), "Expected `}}`in the output");
+ assert!(response.contains("env-vars"), "Expected 'env-vars' in the output");
+ assert!(response.contains("system-info"), "Expected 'system-info' in the output");
+
+ println!("✅ Kiro Cli diagnostics --format json-pretty subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_verbose_subommand() -> Result<(), Box kiro-cli diagnostics --verbose subcommand to verify verbose command output.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics --format --verbose' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","--verbose"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("system-info"), "Expected 'system-info' in the output");
+ assert!(response.contains("environment"), "Expected 'environment' in the output");
+ assert!(response.contains("env-vars"), "Expected 'env-vars' in the output");
+
+ println!("✅ Kiro Cli diagnostics --verbose subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_force_subommand() -> Result<(), Box kiro-cli diagnostics --force subcommand to verify force command output.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics --format force' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","--force"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("system-info"), "Expected 'system-info' in the output");
+ assert!(response.contains("environment"), "Expected 'environment' in the output");
+ assert!(response.contains("env-vars"), "Expected 'env-vars' in the output");
+
+ println!("✅ Kiro Cli diagnostics --force subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_verbose_shorthand_subommand() -> Result<(), Box kiro-cli diagnostics -v subcommand to verify -v command output.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics -v' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","-v"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("system-info"), "Expected 'system-info' in the output");
+ assert!(response.contains("environment"), "Expected 'environment' in the output");
+ assert!(response.contains("env-vars"), "Expected 'env-vars' in the output");
+
+ println!("✅ Kiro Cli diagnostics -v subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "diagnostics", feature = "sanity"))]
+fn test_kiro_cli_diagnostics_help_shorthand_subommand() -> Result<(), Box kiro-cli diagnostics -h subcommand to verify -h command output.");
+
+ println!("\n🔍 Executing 'kiro-cli diagnostics -h' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["diagnostics","-h"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Options:"), "Expected 'Options:' in the output");
+ assert!(response.contains("-f"), "Expected '-f' in the output");
+ assert!(response.contains("--format"), "Expected '--format' in the output");
+ assert!(response.contains(" /experiment command to toggle Knowledge experimental features");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/experiment")?;
+ let response = chat.execute_command_with_timeout("/experiment",Some(500))?;
println!("📝 Experiment response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -67,9 +19,8 @@ fn test_knowledge_command() -> Result<(), Box /experiment command to toggle thinking experimental features");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/experiment")?;
+ let response = chat.execute_command_with_timeout("/experiment",Some(500))?;
println!("📝 Experiment response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -187,36 +131,34 @@ fn test_thinking_command() -> Result<(), Box /experiment --help command to display help information");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/experiment --help")?;
+ let response = chat.execute_command_with_timeout("/experiment --help",Some(500))?;
println!("📝 Help response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -307,19 +242,17 @@ fn test_experiment_help_command() -> Result<(), Box /experiment command to toggle Tangent Mode experimental feature");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/experiment")?;
+ let response = chat.execute_command_with_timeout("/experiment",Some(500))?;
println!("📝 Experiment response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -341,36 +274,34 @@ fn test_tangent_mode_experiment() -> Result<(), Box /experiment command to toggle Todo Lists experimental feature");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- println!("✅ Q Chat session started");
+ println!("✅ Kiro-cli Chat session started");
- let response = chat.execute_command("/experiment")?;
+ let response = chat.execute_command_with_timeout("/experiment",Some(500))?;
println!("📝 Experiment response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -461,36 +384,34 @@ fn test_todo_lists_experiment() -> Result<(), Box kiro-cli init --help subcommand to verify help options.");
+
+ println!("\n🔍 Executing 'kiro-cli init --help' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--help"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Options:"), "Expected 'Options:' in the output");
+ assert!(response.contains("Arguments"), "Expected 'Arguments' in the output");
+ assert!(response.contains("SHELL"), "Expected 'SHELL' in the output");
+
+ assert!(response.contains("bash"), "Expected 'bash' in the output");
+ assert!(response.contains("zsh"), "Expected 'zsh' in the output");
+ assert!(response.contains("fish"), "Expected 'fish' in the output");
+
+ assert!(response.contains("nu"), "Expected 'nu' in the output");
+ assert!(response.contains("WHEN"), "Expected 'WHEN' in the output");
+ assert!(response.contains("RCFILE"), "Expected 'RCFILE' in the output");
+
+ assert!(response.contains("rcfile"), "Expected 'rcfile' in the output");
+
+ assert!(response.contains("-v"), "Expected '-v' in the output");
+ assert!(response.contains("--verbose"), "Expected '--verbose' in the output");
+
+ assert!(response.contains("-h"), "Expected '-h' in the output");
+ assert!(response.contains("--help"), "Expected '--help' in the output");
+
+ println!("✅ Kiro Cli init --help subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_bash_pre_subommand() -> Result<(), Box kiro-cli init bash pre subcommand to verify bash pre init subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init bash pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","bash","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("function __fig_source_bash_preexec"), "Expected 'function __fig_source_bash_preexec' in the output");
+ assert!(response.contains("bash-preexec.sh"), "Expected 'bash-preexec.sh' in the output");
+
+ assert!(response.contains("General Usage:"), "Expected 'General Usage:' in the output");
+ assert!(response.contains("#!/usr/bin/env bash"), "Expected '#!/usr/bin/env bash' in the output");
+ assert!(response.contains("https://github.com/rcaloras/bash-preexec"), "Expected 'https://github.com/rcaloras/bash-preexec' in the output");
+
+ assert!(response.contains("#"), "Expected '#' in the output");
+
+ println!("✅ Kiro Cli init bash pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_bash_post_subommand() -> Result<(), Box kiro-cli init bash post subcommand to verify kiro-cli init bash post subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init bash post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","bash","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SHELL"), "Expected 'Q_SHELL' in the output");
+ assert!(response.contains("bash-preexec.sh"), "Expected 'bash-preexec.sh' in the output");
+
+ assert!(response.contains("General Usage:"), "Expected 'General Usage:' in the output");
+ assert!(response.contains("https://github.com/rcaloras/bash-preexec"), "Expected 'https://github.com/rcaloras/bash-preexec' in the output");
+
+ assert!(response.contains("#"), "Expected '#' in the output");
+
+ println!("✅ Kiro Cli init bash post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_zsh_pre_subommand() -> Result<(), Box kiro-cli init zsh pre subcommand to verify kiro-cli init zsh pre subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init zsh pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","zsh","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SHELL"), "Expected 'Q_SHELL' in the output");
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("#!/usr/bin/env bash"), "Expected shebang in the output");
+ assert!(response.contains("mkdir -p"), "Expected 'mkdir -p' in the output");
+ assert!(response.contains("~/.local/bin"), "Expected '~/.local/bin' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("kiro-cli-term"), "Expected 'kiro-cli-term' in the output");
+ assert!(response.contains("Q_IS_LOGIN_SHELL"), "Expected 'Q_IS_LOGIN_SHELL' in the output");
+
+ println!("✅ Kiro Cli init zsh pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_zsh_post_subommand() -> Result<(), Box kiro-cli init zsh post subcommand to verify kiro-cli init zsh pre subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init zsh post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","zsh","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SHELL"), "Expected 'Q_SHELL' in the output");
+ assert!(response.contains("Global Configuration Variables"), "Expected 'Global Configuration Variables' in the output");
+
+ assert!(response.contains("Utility Functions"), "Expected 'Utility Functions' in the output");
+ assert!(response.contains("Widget Helpers"), "Expected 'Widget Helpers' in the output");
+
+ assert!(response.contains("Highlighting"), "Expected 'Highlighting' in the output");
+ assert!(response.contains("Autosuggest Widget Implementations"), "Expected 'Autosuggest Widget Implementations' in the output");
+ assert!(response.contains("InlineShell Suggestion Strategy"), "Expected 'InlineShell Suggestion Strategy' in the output");
+
+ println!("✅ Kiro Cli init zsh post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_fish_pre_subommand() -> Result<(), Box kiro-cli init fish pre subcommand to verify kiro-cli init fish pre subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init fish pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","fish","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("command mkdir"), "Expected 'command mkdir' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+
+ assert!(response.contains("Load parent"), "Expected 'Load parent' in the output");
+
+ println!("✅ Kiro Cli init fist pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_fish_post_subommand() -> Result<(), Box kiro-cli init fish post subcommand to verify kiro-cli init fish post subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init fish post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","fish","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("set --query"), "Expected 'set --query' in the output");
+ assert!(response.contains("TTY"), "Expected 'TTY' in the output");
+
+ assert!(response.contains("fig_wrap_prompt"), "Expected 'fig_wrap_prompt' in the output");
+
+ println!("✅ Kiro Cli init fist post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_nu_pre_subommand() -> Result<(), Box kiro-cli init nu pre subcommand to verify kiro-cli init nu pre subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init nu pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","nu","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("should_launch"), "Expected 'should_launch' in the output");
+
+ assert!(response.contains("with-env"), "Expected 'with-env' in the output");
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ println!("✅ Kiro Cli init nu pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_nu_post_subommand() -> Result<(), Box kiro-cli init nu post subcommand to verify kiro-cli init nu post subcommand.");
+
+ println!("\n🔍 Executing 'kiro-cli init nu post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","nu","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("fig_reset_hooks"), "Expected 'fig_reset_hooks' in the output");
+ assert!(response.contains("let hooks ="), "Expected 'let hooks =' in the output");
+
+ assert!(response.contains("fig_pre_execution_hook"), "Expected 'fig_pre_execution_hook' in the output");
+ assert!(response.contains("fig_set_prompt"), "Expected 'fig_set_prompt' in the output");
+ assert!(response.contains("StartPrompt"), "Expected 'StartPrompt' in the output");
+
+ println!("✅ Kiro Cli init nu post subcommand executed successfully!");
+
+ Ok(())
+}
+
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_help_shorthand_subommand() -> Result<(), Box kiro-cli init -h subcommand to verify help options.");
+
+ println!("\n🔍 Executing 'kiro-cli init -h' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-h"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Usage"), "Expected 'Usage' in the output");
+ assert!(response.contains("[OPTIONS]"), "Expected '[OPTIONS]' in the output");
+
+ assert!(response.contains("Options:"), "Expected 'Options:' in the output");
+ assert!(response.contains("Arguments"), "Expected 'Arguments' in the output");
+ assert!(response.contains("SHELL"), "Expected 'SHELL' in the output");
+
+ assert!(response.contains("bash"), "Expected 'bash' in the output");
+ assert!(response.contains("zsh"), "Expected 'zsh' in the output");
+ assert!(response.contains("fish"), "Expected 'fish' in the output");
+
+ assert!(response.contains("nu"), "Expected 'nu' in the output");
+ assert!(response.contains("WHEN"), "Expected 'WHEN' in the output");
+ assert!(response.contains("RCFILE"), "Expected 'RCFILE' in the output");
+
+ assert!(response.contains("rcfile"), "Expected 'rcfile' in the output");
+
+ assert!(response.contains("-v"), "Expected '-v' in the output");
+ assert!(response.contains("--verbose"), "Expected '--verbose' in the output");
+
+ assert!(response.contains("-h"), "Expected '-h' in the output");
+ assert!(response.contains("--help"), "Expected '--help' in the output");
+
+ println!("✅ Kiro Cli init -h subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_bash_verbose_bash_pre_subommand() -> Result<(), Box kiro-cli init --verbose bash pre subcommand to verify verbose bash pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -verbose bash pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","bash","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("mkdir -p"), "Expected 'mkdir -p' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("kiro-cli-term"), "Expected 'kiro-cli-term' in the output");
+ assert!(response.contains("Q_EXECUTION_STRING"), "Expected 'Q_EXECUTION_STRING' in the output");
+
+ assert!(response.contains("exec -a"), "Expected 'exec -a' in the output");
+ assert!(!response.contains("SHOULD_QTERM_LAUNCH") || response.contains("bash pre"), "bash post should not contain SHOULD_QTERM_LAUNCH");
+
+ println!("✅ Kiro Cli init --verbose bash pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_bash_verbose_bash_post_subommand() -> Result<(), Box kiro-cli init --verbose bash post subcommand to verify verbose bash post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -verbose bash post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","bash","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("__fig_preexec"), "Expected '__fig_preexec' in the output");
+ assert!(response.contains("__fig_pre_prompt"), "Expected '__fig_pre_prompt' in the output");
+ assert!(response.contains("PROMPT_COMMAND"), "Expected 'PROMPT_COMMAND' in the output");
+
+ assert!(response.contains("precmd_functions"), "Expected 'precmd_functions' in the output");
+ assert!(response.contains("preexec_functions"), "Expected 'preexec_functions' in the output");
+ assert!(response.contains("fig_osc"), "Expected 'fig_osc' in the output");
+
+ assert!(response.contains("StartPrompt"), "Expected 'StartPrompt' in the output");
+ assert!(response.contains("EndPrompt"), "Expected 'EndPrompt' in the output");
+ assert!(!response.contains("__fig_preexec") || response.contains("bash post"), "bash pre should not focus on __fig_preexec");
+
+ println!("✅ Kiro Cli init --verbose bash post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_verbose_zsh_pre_subommand() -> Result<(), Box kiro-cli init --verbose zsh pre subcommand to verify verbose zsh pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -verbose zsh pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","zsh","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("mkdir -p"), "Expected 'mkdir -p' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("kiro-cli-term"), "Expected 'kiro-cli-term' in the output");
+ assert!(response.contains("Q_EXECUTION_STRING"), "Expected 'Q_EXECUTION_STRING' in the output");
+
+ assert!(response.contains("exec -a"), "Expected 'exec -a' in the output");
+ assert!(response.contains("Q_IS_LOGIN_SHELL"), "Expected 'Q_IS_LOGIN_SHELL' in the output");
+ assert!(!response.contains("Q_DOTFILES_SOURCED") || response.contains("zsh post"), "zsh pre should not contain autosuggestions");
+
+ println!("✅ Kiro Cli init --verbose zsh pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_verbose_zsh_post_subommand() -> Result<(), Box kiro-cli init --verbose zsh post subcommand to verify verbose zsh post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -verbose zsh post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","zsh","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_DOTFILES_SOURCED"), "Expected 'Q_DOTFILES_SOURCED' in the output");
+ assert!(response.contains("KIRO_CLI_AUTOSUGGEST"), "Expected 'KIRO_CLI_AUTOSUGGEST' in the output");
+ assert!(response.contains("_kiro_cli_autosuggest"), "Expected '_kiro_cli_autosuggest' in the output");
+
+ assert!(response.contains("fig_preexec"), "Expected 'fig_preexec' in the output");
+ assert!(response.contains("fig_precmd"), "Expected 'fig_precmd' in the output");
+ assert!(response.contains("precmd_functions"), "Expected 'precmd_functions' in the output");
+
+ assert!(response.contains("preexec_functions"), "Expected 'preexec_functions' in the output");
+ assert!(response.contains("Q_USER_PS1"), "Expected 'Q_USER_PS1' in the output");
+ assert!(response.contains("inline_shell_completion"), "Expected 'inline_shell_completion' in the output");
+
+ assert!(!response.contains("SHOULD_QTERM_LAUNCH") || response.contains("zsh pre"), "zsh post should not contain terminal launch logic");
+
+ println!("✅ Kiro Cli init --verbose zsh post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_verbose_fish_pre_subommand() -> Result<(), Box kiro-cli init --verbose fish pre subcommand to verify verbose fish pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init --verbose fish pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","fish","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("command mkdir -p"), "Expected 'command mkdir -p' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+
+ assert!(response.contains("Q_PARENT"), "Expected 'Q_PARENT' in the output");
+ assert!(response.contains("kiro-cli-term"), "Expected 'kiro-cli-term' in the output");
+ assert!(response.contains("Q_SHELL"), "Expected 'Q_SHELL' in the output");
+
+ assert!(response.contains("exec bash -c"), "Expected 'exec bash -c' in the output");
+ assert!(response.contains("Q_IS_LOGIN_SHELL"), "Expected 'Q_IS_LOGIN_SHELL' in the output");
+ assert!(!response.contains("fig_preexec"), "fish pre should not contain fig_preexec hooks");
+
+ println!("✅ Kiro Cli init --verbose fish pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_verbose_fish_post_subommand() -> Result<(), Box kiro-cli init --verbose fish post subcommand to verify verbose fish post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init --verbose fish post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","fish","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("fig_preexec"), "Expected 'fig_preexec' in the output");
+ assert!(response.contains("fig_precmd"), "Expected 'fig_precmd' in the output");
+ assert!(response.contains("fig_wrap_prompt"), "Expected 'fig_wrap_prompt' in the output");
+
+ assert!(response.contains("fig_copy_fn"), "Expected 'fig_copy_fn' in the output");
+ assert!(response.contains("StartPrompt"), "Expected 'StartPrompt' in the output");
+ assert!(response.contains("EndPrompt"), "Expected 'EndPrompt' in the output");
+
+ assert!(response.contains("fish_prompt"), "Expected 'fish_prompt' in the output");
+ assert!(response.contains("QTERM_SESSION_ID"), "Expected 'QTERM_SESSION_ID' in the output");
+ assert!(!response.contains("SHOULD_QTERM_LAUNCH"), "fish post should not contain terminal launch logic");
+
+ println!("✅ Kiro Cli init --verbose fish post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_bash_pre_subommand() -> Result<(), Box kiro-cli init -v bash pre subcommand to verify verbose bash pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v bash pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","bash","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SHELL="));
+ assert!(response.contains("SHOULD_QTERM_LAUNCH="));
+ assert!(response.contains("__fig_source_bash_preexec"));
+ assert!(!response.contains("__fig_pre_prompt"));
+ println!("✅ Kiro Cli init -v bash pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_bash_post_subommand() -> Result<(), Box kiro-cli init -v bash post subcommand to verify verbose bash post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v bash post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","bash","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("__fig_pre_prompt"));
+ assert!(response.contains("__fig_post_prompt"));
+ assert!(response.contains("fig_osc"));
+ assert!(response.contains("kiro-cli _ pre-cmd"));
+ println!("✅ Kiro Cli init -v bash post subcommand executed successfully!");
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_verbose_nu_pre_subommand() -> Result<(), Box kiro-cli init --verbose nu pre subcommand to verify verbose nu pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init --verbose nu pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","nu","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("mkdir ~/.local/bin"), "Expected 'mkdir ~/.local/bin' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("should-figterm-launch"), "Expected 'should-figterm-launch' in the output");
+ assert!(response.contains("figterm_path"), "Expected 'figterm_path' in the output");
+
+ assert!(response.contains("exec $figterm_path"), "Expected 'exec $figterm_path' in the output");
+ assert!(response.contains("pathadd"), "Expected 'pathadd' function in the output");
+ assert!(!response.contains("fig_pre_execution_hook"), "nu pre should not contain execution hooks");
+
+ println!("✅ Kiro Cli init --verbose nu pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_verbose_nu_post_subommand() -> Result<(), Box kiro-cli init --verbose nu post subcommand to verify verbose nu post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init --verbose nu post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","--verbose","nu","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("fig_pre_execution_hook"), "Expected 'fig_pre_execution_hook' in the output");
+ assert!(response.contains("fig_pre_prompt_hook"), "Expected 'fig_pre_prompt_hook' in the output");
+ assert!(response.contains("fig_set_prompt"), "Expected 'fig_set_prompt' in the output");
+
+ assert!(response.contains("fig_reset_hooks"), "Expected 'fig_reset_hooks' in the output");
+ assert!(response.contains("print_fig_osc"), "Expected 'print_fig_osc' in the output");
+ assert!(response.contains("StartPrompt"), "Expected 'StartPrompt' in the output");
+
+ assert!(response.contains("EndPrompt"), "Expected 'EndPrompt' in the output");
+ assert!(response.contains("DoneSourcing"), "Expected 'DoneSourcing' in the output");
+ assert!(!response.contains("should_launch"), "nu post should not contain terminal launch logic");
+
+ println!("✅ Kiro Cli init --verbose nu post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_zsh_post_subommand() -> Result<(), Box kiro-cli init -v zsh post subcommand to verify verbose zsh -v post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v zsh post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","zsh","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SHELL"), "Expected 'Q_SHELL' in the output");
+ assert!(response.contains("Q_DOTFILES_SOURCED"), "Expected 'Q_DOTFILES_SOURCED' in the output");
+ assert!(response.contains("KIRO_CLI_AUTOSUGGEST"), "Expected 'KIRO_CLI_AUTOSUGGEST' in the output");
+ assert!(response.contains("_zsh_autosuggest_accept"), "Expected '_zsh_autosuggest_accept' in the output");
+ assert!(response.contains("fig_preexec"), "Expected 'fig_preexec' in the output");
+ assert!(response.contains("fig_precmd"), "Expected 'fig_precmd' in the output");
+ assert!(response.contains("fig_osc"), "Expected 'fig_osc' in the output");
+ assert!(response.contains("QTERM_SESSION_ID"), "Expected 'QTERM_SESSION_ID' in the output");
+ assert!(response.contains("inline-shell-completion"), "Expected 'inline-shell-completion' in the output");
+ assert!(!response.contains("mkdir -p"), "zsh post should not contain directory creation");
+
+ println!("✅ Kiro Cli init -v zsh post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_zsh_pre_subommand() -> Result<(), Box kiro-cli init -v zsh pre subcommand to verify verbose zsh -v pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v zsh pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","zsh","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("Q_SHELL"), "Expected 'Q_SHELL' in the output");
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("#!/usr/bin/env bash"), "Expected shebang in the output");
+ assert!(response.contains("mkdir -p"), "Expected 'mkdir -p' in the output");
+ assert!(response.contains("~/.local/bin"), "Expected '~/.local/bin' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("kiro-cli-term"), "Expected 'kiro-cli-term' in the output");
+ assert!(response.contains("Q_IS_LOGIN_SHELL"), "Expected 'Q_IS_LOGIN_SHELL' in the output");
+ assert!(!response.contains("Q_DOTFILES_SOURCED"), "zsh pre should not contain dotfiles sourced check");
+
+ println!("✅ Kiro Cli init -v zsh pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_fish_pre_subommand() -> Result<(), Box kiro-cli init -v fish pre subcommand to verify verbose fish -v pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v fish pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","fish","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("set -g Q_SHELL"), "Expected 'set -g Q_SHELL' in the output");
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("command mkdir -p"), "Expected 'command mkdir -p' in the output");
+ assert!(response.contains("builtin contains"), "Expected 'builtin contains' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+ assert!(response.contains("Q_PARENT"), "Expected 'Q_PARENT' in the output");
+ assert!(response.contains("kiro-cli-term"), "Expected 'kiro-cli-term' in the output");
+ assert!(response.contains("Q_IS_LOGIN_SHELL"), "Expected 'Q_IS_LOGIN_SHELL' in the output");
+ assert!(response.contains("exec bash -c"), "Expected 'exec bash -c' in the output");
+ assert!(!response.contains("fig_preexec"), "fish pre should not contain fig_preexec hooks");
+
+ println!("✅ Kiro Cli init -v fish pre subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_fish_post_subommand() -> Result<(), Box kiro-cli init -v fish post subcommand to verify verbose fish -v post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v fish post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","fish","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("set -g Q_SHELL"), "Expected 'set -g Q_SHELL' in the output");
+ assert!(response.contains("function fig_osc"), "Expected 'function fig_osc' in the output");
+ assert!(response.contains("function fig_copy_fn"), "Expected 'function fig_copy_fn' in the output");
+ assert!(response.contains("function fig_wrap_prompt"), "Expected 'function fig_wrap_prompt' in the output");
+ assert!(response.contains("function fig_preexec"), "Expected 'function fig_preexec' in the output");
+ assert!(response.contains("function fig_precmd"), "Expected 'function fig_precmd' in the output");
+ assert!(response.contains("--on-event fish_preexec"), "Expected '--on-event fish_preexec' in the output");
+ assert!(response.contains("--on-event fish_prompt"), "Expected '--on-event fish_prompt' in the output");
+ assert!(response.contains("QTERM_SESSION_ID"), "Expected 'QTERM_SESSION_ID' in the output");
+ assert!(!response.contains("SHOULD_QTERM_LAUNCH"), "fish post should not contain terminal launch logic");
+
+ println!("✅ Kiro Cli init -v fish post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_nu_post_subommand() -> Result<(), Box kiro-cli init -v nu post subcommand to verify verbose nu -v post response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v nu post' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","nu","post"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("let-env Q_SHELL"), "Expected 'let-env Q_SHELL' in the output");
+ assert!(response.contains("def-env fig_osc"), "Expected 'def-env fig_osc' in the output");
+ assert!(response.contains("def-env print_fig_osc"), "Expected 'def-env print_fig_osc' in the output");
+ assert!(response.contains("def-env fig_reset_hooks"), "Expected 'def-env fig_reset_hooks' in the output");
+ assert!(response.contains("def-env fig_pre_execution_hook"), "Expected 'def-env fig_pre_execution_hook' in the output");
+ assert!(response.contains("def-env fig_pre_prompt_hook"), "Expected 'def-env fig_pre_prompt_hook' in the output");
+ assert!(response.contains("def-env fig_set_prompt"), "Expected 'def-env fig_set_prompt' in the output");
+ assert!(response.contains("StartPrompt"), "Expected 'StartPrompt' in the output");
+ assert!(response.contains("EndPrompt"), "Expected 'EndPrompt' in the output");
+ assert!(response.contains("DoneSourcing"), "Expected 'DoneSourcing' in the output");
+ assert!(!response.contains("should_launch"), "nu post should not contain terminal launch logic");
+
+ println!("✅ Kiro Cli init -v nu post subcommand executed successfully!");
+
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "init_subcommand", feature = "sanity"))]
+fn test_kiro_cli_init_v_nu_pre_subommand() -> Result<(), Box kiro-cli init -v nu pre subcommand to verify verbose nu -v pre response.");
+
+ println!("\n🔍 Executing 'kiro-cli init -v nu pre' subcommand...");
+ let response = q_chat_helper::execute_q_subcommand("kiro-cli", &["init","-v","nu","pre"])?;
+
+ println!("📝 FULL OUTPUT:");
+ println!("{}", response);
+ println!("📝 END OUTPUT");
+
+ assert!(response.contains("let-env Q_SHELL"), "Expected 'let-env Q_SHELL' in the output");
+ assert!(response.contains("SHOULD_QTERM_LAUNCH"), "Expected 'SHOULD_QTERM_LAUNCH' in the output");
+ assert!(response.contains("mkdir ~/.local/bin"), "Expected 'mkdir ~/.local/bin' in the output");
+ assert!(response.contains("def pathadd"), "Expected 'def pathadd' in the output");
+ assert!(response.contains("Q_NEW_SESSION"), "Expected 'Q_NEW_SESSION' in the output");
+ assert!(response.contains("Q_SET_PARENT_CHECK"), "Expected 'Q_SET_PARENT_CHECK' in the output");
+ assert!(response.contains("should-figterm-launch"), "Expected 'should-figterm-launch' in the output");
+ assert!(response.contains("figterm_path"), "Expected 'figterm_path' in the output");
+ assert!(response.contains("exec $figterm_path"), "Expected 'exec $figterm_path' in the output");
+ assert!(!response.contains("fig_pre_execution_hook"), "nu pre should not contain execution hooks");
+
+ println!("✅ Kiro Cli init -v nu pre subcommand executed successfully!");
+
+ Ok(())
+}
\ No newline at end of file
diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs
index ceb3ec32cc..6253c72ce0 100644
--- a/e2etests/tests/integration/test_editor_help_command.rs
+++ b/e2etests/tests/integration/test_editor_help_command.rs
@@ -1,65 +1,15 @@
#[allow(unused_imports)]
use q_cli_e2e_tests::q_chat_helper;
-use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}};
-
-#[allow(dead_code)]
-static TEST_COUNT: AtomicUsize = AtomicUsize::new(0);
-
-// List of covered tests
-#[allow(dead_code)]
-const TEST_NAMES: &[&str] = &[
- "test_editor_help_command",
- "test_help_editor_command",
- "test_editor_h_command",
- "test_editor_command_interaction",
- "test_editor_command_error",
- "test_editor_with_file_path",
-];
-#[allow(dead_code)]
-const TOTAL_TESTS: usize = TEST_NAMES.len();
-
-#[allow(dead_code)]
-static INIT: Once = Once::new();
-#[allow(dead_code)]
-static mut CHAT_SESSION: Option /editor --help command to display help information for the editor functionality including usage and options");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/editor --help")?;
+ let response = chat.execute_command_with_timeout("/editor --help",Some(500))?;
println!("📝 Editor help response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -67,29 +17,24 @@ fn test_editor_help_command() -> Result<(), Box /help editor command to display editor-specific help information and usage instructions");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/help editor")?;
+ let response = chat.execute_command_with_timeout("/help editor",Some(500))?;
println!("📝 Help editor response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -110,29 +55,22 @@ fn test_help_editor_command() -> Result<(), Box /editor -h command (short form) to display editor help information and verify proper flag handling");
- let session = get_chat_session();
+ let session = q_chat_helper::get_chat_session();
let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
- let response = chat.execute_command("/editor -h")?;
+ let response = chat.execute_command_with_timeout("/editor -h",Some(500))?;
println!("📝 Editor help response: {} bytes", response.len());
println!("📝 FULL OUTPUT:");
@@ -153,29 +91,22 @@ fn test_editor_h_command() -> Result<(), Box