Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions crates/app/src/acp/acpx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2137,18 +2137,6 @@ exit 0

#[test]
fn build_mcp_proxy_agent_command_preserves_server_cwd() {
fn decode_quoted_command_part(value: &str) -> String {
let trimmed = value.trim();
let quoted = trimmed.starts_with('"') && trimmed.ends_with('"') && trimmed.len() >= 2;
if !quoted {
return trimmed.to_owned();
}

let inner = &trimmed[1..trimmed.len() - 1];
let unescaped_backslashes = inner.replace("\\\\", "\\");
unescaped_backslashes.replace("\\\"", "\"")
}

let server = AcpxMcpServerEntry {
name: "docs".to_owned(),
command: "uvx".to_owned(),
Expand All @@ -2164,9 +2152,9 @@ exit 0
.expect("proxy command");
let payload_marker = "--payload-file ";
let payload_index = command.find(payload_marker).expect("payload marker");
let payload_path = &command[payload_index + payload_marker.len()..];
let payload_path = decode_quoted_command_part(payload_path);
let payload_bytes = std::fs::read(payload_path).expect("read payload file");
let payload_argument = &command[payload_index + payload_marker.len()..];
let payload_path = decode_test_command_argument(payload_argument);
let payload_bytes = std::fs::read(&payload_path).expect("read payload file");
let payload: Value = serde_json::from_slice(&payload_bytes).expect("parse payload");

assert_eq!(
Expand All @@ -2175,6 +2163,29 @@ exit 0
);
}

fn decode_test_command_argument(argument: &str) -> String {
let trimmed_argument = argument.trim();
let is_quoted = trimmed_argument.starts_with('"') && trimmed_argument.ends_with('"');
if !is_quoted {
return trimmed_argument.to_owned();
}

let quoted_argument = &trimmed_argument[1..trimmed_argument.len() - 1];
let mut decoded = String::new();
let mut chars = quoted_argument.chars();
while let Some(character) = chars.next() {
if character == '\\' {
match chars.next() {
Some(escaped_character) => decoded.push(escaped_character),
None => decoded.push('\\'),
}
continue;
}
decoded.push(character);
}
decoded
}

#[tokio::test]
#[cfg(unix)]
#[allow(clippy::await_holding_lock)]
Expand Down
8 changes: 5 additions & 3 deletions crates/app/src/conversation/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use serde_json::{Value, json};
use sha2::{Digest, Sha256};

use super::super::config::{
AutonomyProfile, LoongClawConfig, MemoryProfile, MemorySystemKind, ProviderConfig,
AuditMode, AutonomyProfile, LoongClawConfig, MemoryProfile, MemorySystemKind, ProviderConfig,
};
use super::persistence::format_provider_error_reply;
use super::runtime::DefaultConversationRuntime;
Expand Down Expand Up @@ -1662,10 +1662,12 @@ impl ConversationRuntime for FakeRuntime {
}

fn test_config() -> LoongClawConfig {
LoongClawConfig {
let mut config = LoongClawConfig {
provider: ProviderConfig::default(),
..LoongClawConfig::default()
}
};
config.audit.mode = AuditMode::InMemory;
config
}

fn enable_guided_autonomy(config: &mut LoongClawConfig) {
Expand Down
1 change: 0 additions & 1 deletion crates/app/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2017,7 +2017,6 @@ mod tests {
"web.fetch",
"web.search",
]);

assert_eq!(names, expected);
}

Expand Down
8 changes: 8 additions & 0 deletions crates/daemon/src/browser_companion_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,4 +507,12 @@ mod tests {
"1.5.0"
));
}

#[test]
fn observed_version_matches_expected_rejects_partial_numeric_matches() {
assert!(!observed_version_matches_expected(
"loongclaw-browser-companion 11.5.0",
"1.5.0"
));
}
}
110 changes: 110 additions & 0 deletions crates/daemon/src/command_kind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use crate::Commands;

impl Commands {
pub fn command_kind_for_logging(&self) -> &'static str {
match self {
Self::Welcome => "welcome",
Self::Demo => "demo",
Self::RunTask { .. } => "run_task",
Self::InvokeConnector { .. } => "invoke_connector",
Self::AuditDemo => "audit_demo",
Self::InitSpec { .. } => "init_spec",
Self::RunSpec { .. } => "run_spec",
Self::BenchmarkProgrammaticPressure { .. } => "benchmark_programmatic_pressure",
Self::BenchmarkProgrammaticPressureLint { .. } => {
"benchmark_programmatic_pressure_lint"
}
Self::BenchmarkWasmCache { .. } => "benchmark_wasm_cache",
Self::BenchmarkMemoryContext { .. } => "benchmark_memory_context",
Self::ValidateConfig { .. } => "validate_config",
Self::Onboard { .. } => "onboard",
Self::Personalize { .. } => "personalize",
Self::Import { .. } => "import",
Self::Migrate { .. } => "migrate",
Self::Doctor { .. } => "doctor",
Self::Audit { .. } => "audit",
Self::Skills { .. } => "skills",
Self::Tasks { .. } => "tasks",
Self::Sessions { .. } => "sessions",
Self::Plugins { .. } => "plugins",
Self::Channels { .. } => "channels",
Self::ListModels { .. } => "list_models",
Self::RuntimeSnapshot { .. } => "runtime_snapshot",
Self::RuntimeRestore { .. } => "runtime_restore",
Self::RuntimeExperiment { .. } => "runtime_experiment",
Self::RuntimeCapability { .. } => "runtime_capability",
Self::ListContextEngines { .. } => "list_context_engines",
Self::ListMemorySystems { .. } => "list_memory_systems",
Self::ListMcpServers { .. } => "list_mcp_servers",
Self::ShowMcpServer { .. } => "show_mcp_server",
Self::ListAcpBackends { .. } => "list_acp_backends",
Self::ListAcpSessions { .. } => "list_acp_sessions",
Self::AcpStatus { .. } => "acp_status",
Self::AcpObservability { .. } => "acp_observability",
Self::AcpEventSummary { .. } => "acp_event_summary",
Self::AcpDispatch { .. } => "acp_dispatch",
Self::AcpDoctor { .. } => "acp_doctor",
Self::ControlPlaneServe { .. } => "control_plane_serve",
Self::Ask { .. } => "ask",
Self::Chat { .. } => "chat",
Self::SafeLaneSummary { .. } => "safe_lane_summary",
Self::SessionSearch { .. } => "session_search",
Self::SessionSearchInspect { .. } => "session_search_inspect",
Self::TrajectoryExport { .. } => "trajectory_export",
Self::TrajectoryInspect { .. } => "trajectory_inspect",
Self::TelegramSend { .. } => "telegram_send",
Self::TelegramServe { .. } => "telegram_serve",
Self::FeishuSend { .. } => "feishu_send",
Self::FeishuServe { .. } => "feishu_serve",
Self::MatrixSend { .. } => "matrix_send",
Self::MatrixServe { .. } => "matrix_serve",
Self::WecomSend { .. } => "wecom_send",
Self::WecomServe { .. } => "wecom_serve",
Self::WhatsappServe { .. } => "whatsapp_serve",
Self::DiscordSend { .. } => "discord_send",
Self::DingtalkSend { .. } => "dingtalk_send",
Self::SlackSend { .. } => "slack_send",
Self::LineSend { .. } => "line_send",
Self::WhatsappSend { .. } => "whatsapp_send",
Self::EmailSend { .. } => "email_send",
Self::WebhookSend { .. } => "webhook_send",
Self::GoogleChatSend { .. } => "google_chat_send",
Self::TeamsSend { .. } => "teams_send",
Self::TlonSend { .. } => "tlon_send",
Self::SignalSend { .. } => "signal_send",
Self::TwitchSend { .. } => "twitch_send",
Self::MattermostSend { .. } => "mattermost_send",
Self::NextcloudTalkSend { .. } => "nextcloud_talk_send",
Self::SynologyChatSend { .. } => "synology_chat_send",
Self::IrcSend { .. } => "irc_send",
Self::ImessageSend { .. } => "imessage_send",
Self::NostrSend { .. } => "nostr_send",
Self::MultiChannelServe { .. } => "multi_channel_serve",
Self::Gateway { .. } => "gateway",
Self::Feishu { .. } => "feishu",
Self::Completions { .. } => "completions",
}
}
}

#[cfg(test)]
mod tests {
use crate::Commands;

#[test]
fn command_kind_for_logging_uses_stable_variant_names() {
assert_eq!(Commands::Welcome.command_kind_for_logging(), "welcome");
assert_eq!(Commands::AuditDemo.command_kind_for_logging(), "audit_demo");
assert_eq!(
Commands::ValidateConfig {
config: None,
output: None,
locale: "en".to_owned(),
json: false,
fail_on_diagnostics: false,
}
.command_kind_for_logging(),
"validate_config"
);
}
}
Loading
Loading