Skip to content
Closed
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
9 changes: 6 additions & 3 deletions cli/local-tests/tests/logging_error_feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,24 @@ fn missing_config_outputs_diagnostic_with_fix() {
assert!(
result.stderr.contains("What happened") || result.stdout.contains("What happened"),
"error should contain 'What happened' section. stdout:\n{}\nstderr:\n{}",
result.stdout, result.stderr
result.stdout,
result.stderr
);

// 验证有修复建议(嵌入在错误消息中)
assert!(
result.stderr.contains("Please create it") || result.stdout.contains("Please create it"),
"error should contain fix suggestion. stdout:\n{}\nstderr:\n{}",
result.stdout, result.stderr
result.stdout,
result.stderr
);

// 验证提及配置文件
assert!(
result.stderr.contains(".tnmsc.json") || result.stdout.contains(".tnmsc.json"),
"error should mention .tnmsc.json. stdout:\n{}\nstderr:\n{}",
result.stdout, result.stderr
result.stdout,
result.stderr
);
}

Expand Down
4 changes: 3 additions & 1 deletion cli/local-tests/tests/logging_install_observability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ fn install_outputs_key_spans_and_events() {

// 验证 collector span
assert!(
result.stdout.contains("### collect.aindex_resolvers started"),
result
.stdout
.contains("### collect.aindex_resolvers started"),
"install should output 'collect.aindex_resolvers' span. stdout:\n{}",
result.stdout
);
Expand Down
4 changes: 3 additions & 1 deletion cli/local-tests/tests/logging_levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ fn trace_level_outputs_span_events() {

// Trace 级别应该输出 collector span
assert!(
result.stdout.contains("### collect.aindex_resolvers started"),
result
.stdout
.contains("### collect.aindex_resolvers started"),
"--trace should output collector spans. stdout:\n{}",
result.stdout
);
Expand Down
2 changes: 0 additions & 2 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ impl ResolvedLogLevel {
Self::Error => "error",
}
}


}

/// Resolve log level from CLI flags.
Expand Down
2 changes: 2 additions & 0 deletions mcp/integrate-tests/tests/packaging_smoke.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fs;

#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

Expand Down
13 changes: 8 additions & 5 deletions mcp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ fn main() -> ExitCode {
std::env::var("LOG_LEVEL")
.ok()
.and_then(|s| tnmsd::infra::logger::LogLevel::from_str_loose(&s))
.unwrap_or(tnmsd::infra::logger::LogLevel::Info)
.unwrap_or(tnmsd::infra::logger::LogLevel::Info),
);

let cli = Cli::parse();
Expand All @@ -336,10 +336,13 @@ fn main() -> ExitCode {
match resolve_command(&cli) {
ResolvedCommand::Serve => {
let _span = logger.span("server.serve").enter();
logger.info("MCP server started", Some(json!({
"serverName": SERVER_NAME,
"protocolVersion": PROTOCOL_VERSION,
})));
logger.info(
"MCP server started",
Some(json!({
"serverName": SERVER_NAME,
"protocolVersion": PROTOCOL_VERSION,
})),
);
run_stdio_server();
ExitCode::SUCCESS
}
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/codex_output_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::config;
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};

const CODEX_PLUGIN_NAME: &str = "CodexCLIOutputAdaptor";
const CODEX_INSTRUCTIONS_FILE: &str = "AGENTS.md";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/cursor_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};

const CURSOR_PLUGIN_NAME: &str = "CursorOutputAdaptor";
const CURSOR_MEMORY_FILE: &str = ".cursorrules";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/droid_output_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::config;
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{
FastCommandPrompt, Project, RelativePath, RuleScope, SkillPrompt, SkillResourceEncoding,
Workspace,
};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};

const DROID_PLUGIN_NAME: &str = "DroidCLIOutputAdaptor";
const DROID_MEMORY_FILE: &str = "AGENTS.md";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/gemini_output_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use std::collections::HashSet;
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::config;
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};

const GEMINI_PLUGIN_NAME: &str = "GeminiCLIOutputAdaptor";
const GEMINI_MEMORY_FILE: &str = "GEMINI.md";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/generic_skills_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::BaseOutputPluginPlanDto;
use crate::domain::plugin_shared::Workspace;
use crate::domain::cleanup::CleanupDeclarationsDto;
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::Workspace;

const GENERIC_SKILLS_PLUGIN_NAME: &str = "GenericSkillsOutputAdaptor";

Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/kiro_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::BaseOutputPluginPlanDto;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};

const KIRO_PLUGIN_NAME: &str = "KiroCLIOutputAdaptor";
const PROJECT_SCOPE: &str = "project";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/opencode_output_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use std::path::PathBuf;
use serde_json::Value;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::config;
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};

const OPENCODE_PLUGIN_NAME: &str = "OpencodeCLIOutputAdaptor";
const OPENCODE_MEMORY_FILE: &str = "AGENTS.md";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/qoder_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::BaseOutputPluginPlanDto;
use crate::domain::plugin_shared::Workspace;
use crate::domain::cleanup::CleanupDeclarationsDto;
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::Workspace;

const QODER_PLUGIN_NAME: &str = "QoderIDEPluginOutputAdaptor";

Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/trae_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};

const TRAE_PLUGIN_NAME: &str = "TraeOutputAdaptor";
const TRAE_STEERING_FILE: &str = "GLOBAL.md";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/warp_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};

const WARP_PLUGIN_NAME: &str = "WarpIDEOutputAdaptor";
const WARP_MEMORY_FILE: &str = "WARP.md";
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/domain/output_plans/windsurf_output_plan.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::PathBuf;

use crate::CliError;
use crate::domain::output_context::OutputContext;
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
use crate::domain::output_context::OutputContext;
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};

const WINDSURF_PLUGIN_NAME: &str = "WindsurfOutputAdaptor";
const WINDSURF_MEMORY_FILE: &str = ".windsurfrules";
Expand Down
6 changes: 5 additions & 1 deletion sdk/src/infra/git_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ mod tests {

let result = resolve_git_info_dir(tmp.path());
assert!(result.is_some());
let result_str = result.as_ref().unwrap().to_string_lossy().replace('\\', "/");
let result_str = result
.as_ref()
.unwrap()
.to_string_lossy()
.replace('\\', "/");
// On Windows, absolute paths starting with / get a drive letter prefix
let result_normalized = result_str
.strip_prefix("C:")
Expand Down
18 changes: 13 additions & 5 deletions sdk/src/infra/logger/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use std::time::{Duration, Instant};
use serde::Serialize;
use serde_json::Value;

use super::diagnostic::{DiagnosticInput, invalid_record, record_from_input, validate_diagnostic_input};
use super::diagnostic::{
DiagnosticInput, invalid_record, record_from_input, validate_diagnostic_input,
};
use super::sink::buffer_diagnostic;

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -102,7 +104,10 @@ impl SpanGuard {
fn new(span: Span) -> Self {
// Emit span enter event immediately
crate::infra::logger::sink::write_span_enter(&span);
Self { span, exited: false }
Self {
span,
exited: false,
}
}

pub fn exit(mut self) {
Expand Down Expand Up @@ -204,9 +209,12 @@ impl Logger {
fn log_diagnostic(&self, level: LogLevel, diagnostic: DiagnosticInput) {
let record = match validate_diagnostic_input(&diagnostic) {
Ok(()) => record_from_input(&self.namespace, level.as_str(), diagnostic),
Err(errors) => {
invalid_record(&self.namespace, level.as_str(), serde_json::to_value(&diagnostic).unwrap_or_default(), &errors)
}
Err(errors) => invalid_record(
&self.namespace,
level.as_str(),
serde_json::to_value(&diagnostic).unwrap_or_default(),
&errors,
),
};

// Buffer diagnostics even if level is Silent
Expand Down
14 changes: 7 additions & 7 deletions sdk/src/infra/logger/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ pub fn validate_diagnostic_input(input: &DiagnosticInput) -> Result<(), Vec<Stri
errors.push("rootCause must contain at least one line".to_string());
}

if let Some(lines) = &input.exact_fix && lines.is_empty() {
if let Some(lines) = &input.exact_fix
&& lines.is_empty()
{
errors.push("exactFix must contain at least one line when provided".to_string());
}

Expand All @@ -60,7 +62,9 @@ pub fn validate_diagnostic_input(input: &DiagnosticInput) -> Result<(), Vec<Stri
}
for (index, lines) in fixes.iter().enumerate() {
if lines.is_empty() {
errors.push(format!("possibleFixes[{index}] must contain at least one line"));
errors.push(format!(
"possibleFixes[{index}] must contain at least one line"
));
}
}
}
Expand Down Expand Up @@ -156,11 +160,7 @@ fn append_section(
use super::formatter::value_to_markdown_lines;

/// Build a diagnostic record from validated input.
pub fn record_from_input(
namespace: &str,
level: &str,
input: DiagnosticInput,
) -> DiagnosticRecord {
pub fn record_from_input(namespace: &str, level: &str, input: DiagnosticInput) -> DiagnosticRecord {
let mut record = DiagnosticRecord {
code: input.code.trim().to_string(),
title: input.title.trim().to_string(),
Expand Down
34 changes: 21 additions & 13 deletions sdk/src/infra/logger/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ use super::core::{Event, LogLevel, Span};
/// Format an event as Markdown.
pub fn format_event(event: &Event) -> String {
match event.level {
LogLevel::Warn | LogLevel::Error | LogLevel::Fatal => {
format_diagnostic_event(event)
}
_ => {
format_message_event(event)
}
LogLevel::Warn | LogLevel::Error | LogLevel::Fatal => format_diagnostic_event(event),
_ => format_message_event(event),
}
}

Expand All @@ -22,7 +18,10 @@ pub fn format_span_enter(span: &Span) -> String {
/// Format a span exit event with duration.
pub fn format_span_exit(span: &Span) -> String {
let duration_ms = span.duration().as_millis();
format!("### {} completed\n - duration: {}ms", span.name, duration_ms)
format!(
"### {} completed\n - duration: {}ms",
span.name, duration_ms
)
}

fn format_message_event(event: &Event) -> String {
Expand Down Expand Up @@ -52,10 +51,11 @@ fn format_message_event(event: &Event) -> String {

fn format_diagnostic_event(event: &Event) -> String {
// For diagnostic events, the message contains the serialized DiagnosticRecord
let record: super::diagnostic::DiagnosticRecord = match serde_json::from_value(event.message.clone()) {
Ok(r) => r,
Err(_) => return "### Diagnostic error\n - failed to parse diagnostic record".to_string(),
};
let record: super::diagnostic::DiagnosticRecord =
match serde_json::from_value(event.message.clone()) {
Ok(r) => r,
Err(_) => return "### Diagnostic error\n - failed to parse diagnostic record".to_string(),
};

let mut lines = vec![format!("### {}", record.title)];

Expand Down Expand Up @@ -108,7 +108,10 @@ fn format_diagnostic_event(event: &Event) -> String {
lines.join("\n")
}

fn extract_message_and_meta(message: &Value, meta: Option<&Value>) -> (Option<String>, Vec<String>) {
fn extract_message_and_meta(
message: &Value,
meta: Option<&Value>,
) -> (Option<String>, Vec<String>) {
let (msg, mut lines) = match message {
Value::String(s) => (Some(s.clone()), Vec::new()),
Value::Object(map) => {
Expand Down Expand Up @@ -159,7 +162,12 @@ pub(crate) fn value_to_markdown_lines(value: &Value) -> Vec<String> {
lines
}

pub(crate) fn append_markdown_value(lines: &mut Vec<String>, label: Option<&str>, value: &Value, depth: usize) {
pub(crate) fn append_markdown_value(
lines: &mut Vec<String>,
label: Option<&str>,
value: &Value,
depth: usize,
) {
let prefix = " ".repeat(depth);
let bullet = format!("{prefix}- ");

Expand Down
Loading