Skip to content

Commit 9213904

Browse files
authored
add update announcement (#3433)
* add update announcement * update copy
1 parent d4f02e6 commit 9213904

File tree

4 files changed

+121
-43
lines changed

4 files changed

+121
-43
lines changed

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

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,9 @@ impl ChatArgs {
463463
// Maximum number of times to show the changelog announcement per version
464464
const CHANGELOG_MAX_SHOW_COUNT: i64 = 2;
465465

466+
// Maximum number of times to show the Kiro upgrade announcement
467+
const KIRO_UPGRADE_MAX_SHOW_COUNT: i64 = 2;
468+
466469
const GREETING_BREAK_POINT: usize = 80;
467470

468471
const RESPONSE_TIMEOUT_CONTENT: &str = "Response timed out - message took too long to generate";
@@ -1207,6 +1210,32 @@ impl ChatSession {
12071210
Ok(())
12081211
}
12091212

1213+
async fn show_kiro_upgrade_announcement(&mut self, os: &mut Os) -> Result<bool> {
1214+
let show_count = os.database.get_kiro_upgrade_show_count()?.unwrap_or(0);
1215+
1216+
// Only show if we haven't reached the max count
1217+
if show_count < KIRO_UPGRADE_MAX_SHOW_COUNT {
1218+
let announcement_with_styling = crate::constants::kiro_upgrade_announcement();
1219+
1220+
draw_box(
1221+
&mut self.stderr,
1222+
"",
1223+
&announcement_with_styling,
1224+
GREETING_BREAK_POINT,
1225+
crate::theme::theme().ui.secondary_text,
1226+
)?;
1227+
1228+
execute!(self.stderr, style::Print("\n"))?;
1229+
1230+
// Update the show count
1231+
os.database.set_kiro_upgrade_show_count(show_count + 1)?;
1232+
1233+
Ok(true)
1234+
} else {
1235+
Ok(false)
1236+
}
1237+
}
1238+
12101239
/// Reload built-in tools to reflect experiment changes while preserving MCP tools
12111240
pub async fn reload_builtin_tools(&mut self, os: &mut Os) -> Result<(), ChatError> {
12121241
self.conversation
@@ -1308,6 +1337,11 @@ impl ChatSession {
13081337

13091338
async fn spawn(&mut self, os: &mut Os) -> Result<()> {
13101339
let is_small_screen = self.terminal_width() < GREETING_BREAK_POINT;
1340+
1341+
// Check if Kiro upgrade announcement will be shown
1342+
let show_count = os.database.get_kiro_upgrade_show_count()?.unwrap_or(0);
1343+
let kiro_announcement_will_show = show_count < KIRO_UPGRADE_MAX_SHOW_COUNT;
1344+
13111345
if os
13121346
.database
13131347
.settings
@@ -1324,26 +1358,30 @@ impl ChatSession {
13241358

13251359
execute!(self.stderr, style::Print(&welcome_text), style::Print("\n\n"),)?;
13261360

1327-
let rotating_tips = tips::get_rotating_tips();
1328-
let tip = &rotating_tips[usize::try_from(rand::random::<u32>()).unwrap_or(0) % rotating_tips.len()];
1329-
if is_small_screen {
1330-
// If the screen is small, print the tip in a single line
1331-
execute!(
1332-
self.stderr,
1333-
style::Print("💡 ".to_string()),
1334-
style::Print(tip),
1335-
style::Print("\n")
1336-
)?;
1337-
} else {
1338-
draw_box(
1339-
&mut self.stderr,
1340-
"Did you know?",
1341-
tip,
1342-
GREETING_BREAK_POINT,
1343-
crate::theme::theme().ui.secondary_text,
1344-
)?;
1361+
// Only show rotating tips if Kiro announcement won't be shown
1362+
if !kiro_announcement_will_show {
1363+
let rotating_tips = tips::get_rotating_tips();
1364+
let tip = &rotating_tips[usize::try_from(rand::random::<u32>()).unwrap_or(0) % rotating_tips.len()];
1365+
if is_small_screen {
1366+
// If the screen is small, print the tip in a single line
1367+
execute!(
1368+
self.stderr,
1369+
style::Print("💡 ".to_string()),
1370+
style::Print(tip),
1371+
style::Print("\n")
1372+
)?;
1373+
} else {
1374+
draw_box(
1375+
&mut self.stderr,
1376+
"Did you know?",
1377+
tip,
1378+
GREETING_BREAK_POINT,
1379+
crate::theme::theme().ui.secondary_text,
1380+
)?;
1381+
}
13451382
}
13461383

1384+
// Always show shortcuts and separator
13471385
execute!(
13481386
self.stderr,
13491387
style::Print("\n"),
@@ -1361,8 +1399,10 @@ impl ChatSession {
13611399
execute!(self.stderr, style::Print("\n"), StyledText::reset())?;
13621400
}
13631401

1364-
// Check if we should show the whats-new announcement
1365-
self.show_changelog_announcement(os).await?;
1402+
// Only show changelog if Kiro announcement won't be shown
1403+
if !kiro_announcement_will_show {
1404+
self.show_changelog_announcement(os).await?;
1405+
}
13661406

13671407
if self.all_tools_trusted() {
13681408
queue!(
@@ -1422,6 +1462,9 @@ impl ChatSession {
14221462
self.conversation.checkpoint_manager = checkpoint_manager;
14231463
}
14241464

1465+
// Show Kiro upgrade announcement (limited to 2 times)
1466+
self.show_kiro_upgrade_announcement(os).await?;
1467+
14251468
if let Some(user_input) = self.initial_input.take() {
14261469
self.inner = Some(ChatState::HandleInput { input: user_input });
14271470
}

crates/chat-cli/src/cli/chat/util/ui.rs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,36 @@ pub fn draw_box(
2626
let inner_width = box_width - 4; // account for │ and padding
2727

2828
// wrap the single line into multiple lines respecting inner width
29-
// Manually wrap the text by splitting at word boundaries
29+
// Manually wrap the text by splitting at word boundaries, using visible length for styled text
3030
let mut wrapped_lines = Vec::new();
3131
let mut line = String::new();
3232

3333
for word in content.split_whitespace() {
34-
if line.len() + word.len() < inner_width {
35-
if !line.is_empty() {
36-
line.push(' ');
37-
}
38-
line.push_str(word);
34+
let test_line = if line.is_empty() {
35+
word.to_string()
36+
} else {
37+
format!("{} {}", line, word)
38+
};
39+
40+
let visible_len = strip_str(&test_line).len();
41+
42+
if visible_len <= inner_width {
43+
line = test_line;
3944
} else {
40-
// Here we need to account for words that are too long as well
41-
if word.len() >= inner_width {
42-
let mut start = 0_usize;
43-
for (i, _) in word.chars().enumerate() {
44-
if i - start >= inner_width {
45-
wrapped_lines.push(word[start..i].to_string());
46-
start = i;
47-
}
45+
// Check if the word alone is too long
46+
let word_visible_len = strip_str(word).len();
47+
if word_visible_len >= inner_width {
48+
// Word is too long, we need to break it (but this is rare with styled text)
49+
if !line.is_empty() {
50+
wrapped_lines.push(line);
4851
}
49-
wrapped_lines.push(word[start..].to_string());
52+
wrapped_lines.push(word.to_string());
5053
line = String::new();
5154
} else {
52-
wrapped_lines.push(line);
55+
// Start a new line with this word
56+
if !line.is_empty() {
57+
wrapped_lines.push(line);
58+
}
5359
line = word.to_string();
5460
}
5561
}
@@ -59,13 +65,22 @@ pub fn draw_box(
5965
wrapped_lines.push(line);
6066
}
6167

62-
let side_len = (box_width.saturating_sub(title.len())) / 2;
63-
let top_border = format!(
64-
"{} {} {}",
65-
style::style(format!("╭{}", "─".repeat(side_len - 2))).with(border_color),
66-
title,
67-
style::style(format!("{}╮", "─".repeat(box_width - side_len - title.len() - 2))).with(border_color)
68-
);
68+
let top_border = if title.is_empty() {
69+
// Closed box with no title
70+
format!(
71+
"{}",
72+
style::style(format!("╭{}╮", "─".repeat(box_width - 2))).with(border_color)
73+
)
74+
} else {
75+
// Box with title
76+
let side_len = (box_width.saturating_sub(title.len())) / 2;
77+
format!(
78+
"{} {} {}",
79+
style::style(format!("╭{}", "─".repeat(side_len - 2))).with(border_color),
80+
title,
81+
style::style(format!("{}╮", "─".repeat(box_width - side_len - title.len() - 2))).with(border_color)
82+
)
83+
};
6984

7085
execute!(
7186
output,

crates/chat-cli/src/constants.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,15 @@ Notes:
220220
}
221221
}
222222

223+
/// Announcement text for Kiro CLI upgrade
224+
pub fn kiro_upgrade_announcement() -> String {
225+
format!(
226+
"Q CLI users can now upgrade to the Kiro CLI. Type {} to update today. The Kiro CLI leverages the agentic features of Q CLI and can be used with your existing Q Developer subscription. If you have auto updates enabled for the Q CLI, unless you disable that setting, Q CLI will auto update to Kiro CLI on 11/24. Kiro CLI is licensed as AWS Content under your Agreement and the AWS Intellectual Property License ({}). By updating to Kiro CLI, you agree to the AWS Intellectual Property License.",
227+
StyledText::command("q update"),
228+
StyledText::command("https://aws.amazon.com/legal/aws-ip-license-terms/")
229+
)
230+
}
231+
223232
/// Tips and rotating messages
224233
pub mod tips {
225234
use super::StyledText;

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,17 @@ impl Database {
298298
Ok(())
299299
}
300300

301+
/// Get Kiro upgrade announcement show count from state table
302+
pub fn get_kiro_upgrade_show_count(&self) -> Result<Option<i64>, DatabaseError> {
303+
self.get_entry::<i64>(Table::State, "kiroUpgrade.showCount")
304+
}
305+
306+
/// Set Kiro upgrade announcement show count in state table
307+
pub fn set_kiro_upgrade_show_count(&self, count: i64) -> Result<(), DatabaseError> {
308+
self.set_entry(Table::State, "kiroUpgrade.showCount", count)?;
309+
Ok(())
310+
}
311+
301312
/// Set the client ID used for telemetry requests.
302313
pub fn set_client_id(&mut self, client_id: Uuid) -> Result<usize, DatabaseError> {
303314
self.set_json_entry(Table::State, CLIENT_ID_KEY, client_id.to_string())

0 commit comments

Comments
 (0)