story-kit: merge 141_story_improve_server_logging_with_timestamps_and_error_visibility

This commit is contained in:
Dave
2026-02-24 13:48:25 +00:00
parent b042c77fed
commit 73614fe5e8
4 changed files with 254 additions and 72 deletions

View File

@@ -1,6 +1,7 @@
use crate::agents::{close_bug_to_archive, move_story_to_archived, move_story_to_merge, move_story_to_qa};
use crate::config::ProjectConfig;
use crate::log_buffer;
use crate::slog_warn;
use crate::http::context::AppContext;
use crate::http::settings::get_editor_command_from_store;
use crate::http::workflow::{
@@ -757,6 +758,10 @@ fn handle_tools_list(id: Option<Value>) -> JsonRpcResponse {
"filter": {
"type": "string",
"description": "Optional substring filter (e.g. 'watcher', 'mcp', 'permission')"
},
"severity": {
"type": "string",
"description": "Filter by severity level: ERROR, WARN, or INFO. Returns only entries at that level."
}
}
}
@@ -848,13 +853,16 @@ async fn handle_tools_call(
"content": [{ "type": "text", "text": content }]
}),
),
Err(msg) => JsonRpcResponse::success(
id,
json!({
"content": [{ "type": "text", "text": msg }],
"isError": true
}),
),
Err(msg) => {
slog_warn!("[mcp] Tool call failed: tool={tool_name} error={msg}");
JsonRpcResponse::success(
id,
json!({
"content": [{ "type": "text", "text": msg }],
"isError": true
}),
)
}
}
}
@@ -1577,12 +1585,15 @@ fn tool_get_server_logs(args: &Value) -> Result<String, String> {
.map(|n| n.min(1000) as usize)
.unwrap_or(100);
let filter = args.get("filter").and_then(|v| v.as_str());
let severity = args
.get("severity")
.and_then(|v| v.as_str())
.and_then(log_buffer::LogLevel::from_str_ci);
// Fetch extra buffer entries to account for multi-line entries within each
let fetch = lines_count.saturating_mul(4).min(4000);
let recent = log_buffer::global().get_recent(fetch, filter);
// Flatten buffer entries into individual lines, then take the last lines_count
let all_lines: Vec<&str> = recent.iter().flat_map(|s| s.lines()).collect();
let recent = log_buffer::global().get_recent(lines_count, filter, severity.as_ref());
let joined = recent.join("\n");
// Clamp to lines_count actual lines in case any entry contains embedded newlines.
let all_lines: Vec<&str> = joined.lines().collect();
let start = all_lines.len().saturating_sub(lines_count);
Ok(all_lines[start..].join("\n"))
}
@@ -1620,12 +1631,17 @@ async fn tool_prompt_permission(args: &Value, ctx: &AppContext) -> Result<String
response_rx,
)
.await
.map_err(|_| format!("Permission request for '{tool_name}' timed out after 5 minutes"))?
.map_err(|_| {
let msg = format!("Permission request for '{tool_name}' timed out after 5 minutes");
slog_warn!("[permission] {msg}");
msg
})?
.map_err(|_| "Permission response channel closed unexpectedly".to_string())?;
if approved {
Ok(json!({"behavior": "allow"}).to_string())
} else {
slog_warn!("[permission] User denied permission for '{tool_name}'");
Ok(json!({
"behavior": "deny",
"message": format!("User denied permission for '{tool_name}'")