use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum StatusState {
Idle,
Attached,
Titled,
Reconnecting,
Failed,
}
impl StatusState {
pub fn as_str(&self) -> &'static str {
match self {
StatusState::Idle => "idle",
StatusState::Attached => "attached",
StatusState::Titled => "titled",
StatusState::Reconnecting => "reconnecting",
StatusState::Failed => "failed",
}
}
}
pub const TOOL_DISPLAY_EXPIRY_MS: u64 = 30_000;
pub const SHIMMER_INTERVAL_MS: u64 = 150;
pub fn timestamp() -> String {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let h = (now / 3600) % 24;
let m = (now / 60) % 60;
let s = now % 60;
format!("{:02}:{:02}:{:02}", h, m, s)
}
pub fn format_duration(ms: u64) -> String {
let seconds = ms / 1000;
let minutes = seconds / 60;
let hours = minutes / 60;
if hours > 0 {
format!("{}h {}m", hours, minutes % 60)
} else if minutes > 0 {
format!("{}m {}s", minutes, seconds % 60)
} else {
format!("{}s", seconds)
}
}
pub fn truncate_to_width(text: &str, max_width: usize) -> String {
if text.len() <= max_width {
text.to_string()
} else {
format!("{}...", &text[..max_width.saturating_sub(3)])
}
}
pub fn abbreviate_activity(summary: &str) -> String {
truncate_to_width(summary, 30)
}
pub fn build_bridge_connect_url(environment_id: &str, ingress_url: Option<&str>) -> String {
let base_url = get_claude_ai_base_url(None, ingress_url);
format!("{}/code?bridge={}", base_url, environment_id)
}
fn get_claude_ai_base_url(_env: Option<&str>, ingress_url: Option<&str>) -> String {
ingress_url
.map(|s| s.to_string())
.unwrap_or_else(|| "https://claude.ai".to_string())
}
pub fn build_bridge_session_url(
session_id: &str,
environment_id: &str,
ingress_url: Option<&str>,
) -> String {
let base = get_remote_session_url(session_id, ingress_url);
format!("{}?bridge={}", base, environment_id)
}
fn get_remote_session_url(session_id: &str, ingress_url: Option<&str>) -> String {
let base_url = get_claude_ai_base_url(None, ingress_url);
let compat_id = session_id.replace("cse_", "session_");
format!("{}/code/{}", base_url, compat_id)
}
pub fn compute_glimmer_index(tick: u64, message_width: u64) -> u64 {
let cycle_length = message_width + 20;
message_width + 10 - (tick % cycle_length)
}
pub fn compute_shimmer_segments(text: &str, glimmer_index: u64) -> (String, String, String) {
let message_width = string_width(text) as u64;
let shimmer_start = glimmer_index as i64 - 1;
let shimmer_end = glimmer_index as i64 + 1;
if shimmer_start >= message_width as i64 || shimmer_end < 0 {
return (text.to_string(), String::new(), String::new());
}
let clamped_start = shimmer_start.max(0) as usize;
let mut col_pos = 0usize;
let mut before = String::new();
let mut shimmer = String::new();
let mut after = String::new();
for c in text.chars() {
let seg_width = string_width(&c.to_string()) as usize;
if col_pos + seg_width <= clamped_start {
before.push(c);
} else if col_pos > shimmer_end as usize {
after.push(c);
} else {
shimmer.push(c);
}
col_pos += seg_width;
}
(before, shimmer, after)
}
fn string_width(s: &str) -> usize {
s.chars().count()
}
#[derive(Debug, Clone)]
pub struct BridgeStatusInfo {
pub label: BridgeStatusLabel,
pub color: BridgeStatusColor,
}
#[derive(Debug, Clone)]
pub enum BridgeStatusLabel {
RemoteControlFailed,
RemoteControlReconnecting,
RemoteControlActive,
RemoteControlConnecting,
}
impl BridgeStatusLabel {
pub fn as_str(&self) -> &'static str {
match self {
BridgeStatusLabel::RemoteControlFailed => "Remote Control failed",
BridgeStatusLabel::RemoteControlReconnecting => "Remote Control reconnecting",
BridgeStatusLabel::RemoteControlActive => "Remote Control active",
BridgeStatusLabel::RemoteControlConnecting => "Remote Control connecting...",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BridgeStatusColor {
Error,
Warning,
Success,
}
pub fn get_bridge_status(params: &GetBridgeStatusParams) -> BridgeStatusInfo {
if params.error.is_some() {
return BridgeStatusInfo {
label: BridgeStatusLabel::RemoteControlFailed,
color: BridgeStatusColor::Error,
};
}
if params.reconnecting {
return BridgeStatusInfo {
label: BridgeStatusLabel::RemoteControlReconnecting,
color: BridgeStatusColor::Warning,
};
}
if params.session_active || params.connected {
return BridgeStatusInfo {
label: BridgeStatusLabel::RemoteControlActive,
color: BridgeStatusColor::Success,
};
}
BridgeStatusInfo {
label: BridgeStatusLabel::RemoteControlConnecting,
color: BridgeStatusColor::Warning,
}
}
pub struct GetBridgeStatusParams<'a> {
pub error: Option<&'a str>,
pub connected: bool,
pub session_active: bool,
pub reconnecting: bool,
}
pub fn build_idle_footer_text(url: &str) -> String {
format!("Code everywhere with the Claude app or {}", url)
}
pub fn build_active_footer_text(url: &str) -> String {
format!("Continue coding in the Claude app or {}", url)
}
pub const FAILED_FOOTER_TEXT: &str = "Something went wrong, please try again";
pub fn wrap_with_osc8_link(text: &str, url: &str) -> String {
format!("\x1b]8;;{}\x07{}\x1b]8;;\x07", url, text)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_timestamp() {
let ts = timestamp();
assert_eq!(ts.len(), 8);
assert!(ts.contains(':'));
}
#[test]
fn test_truncate_to_width() {
assert_eq!(truncate_to_width("hello", 10), "hello");
assert_eq!(truncate_to_width("hello world", 8), "hello...");
}
#[test]
fn test_compute_glimmer_index() {
assert_eq!(compute_glimmer_index(0, 50), 60);
assert_eq!(compute_glimmer_index(10, 50), 50);
}
}