feat(dashboard): extract inline script to standalone dashboard.ts/js, add UI build/check recipes, and add route unit tests
This commit is contained in:
1 parent
4b307b55b9
commit
19f9c7ace7
24 files changed
+2343
-1819
No files matched your search
+47
-125
@@ -495,94 +495,46 @@ impl MemoryHandler {
|
||||
|
||||
register!(tasks::TasksHandler);
|
||||
register!(tasks::MilestonesHandler);
|
||||
register!(tasks::AddTaskHandler);
|
||||
register!(tasks::DeleteTaskHandler);
|
||||
register!(tasks::UpdateTaskStatusHandler);
|
||||
register!(tasks::ListActiveTasksHandler);
|
||||
register!(tasks::SetAcceptanceCriteriaHandler);
|
||||
register!(tasks::VerifyAcceptanceCriteriaHandler);
|
||||
register!(tasks::AddMilestoneHandler);
|
||||
register!(tasks::UpdateMilestoneHandler);
|
||||
register!(tasks::ListMilestonesHandler);
|
||||
|
||||
register!(notes::StickyNotesHandler);
|
||||
register!(notes::HandoffMemosHandler);
|
||||
register!(notes::AddStickyNoteHandler);
|
||||
register!(notes::ReadStickyNotesHandler);
|
||||
register!(notes::DeleteStickyNoteHandler);
|
||||
register!(notes::ClearStickyNotesHandler);
|
||||
register!(notes::AddSessionSummaryHandler);
|
||||
register!(notes::GenerateStandupReportHandler);
|
||||
register!(notes::PromoteToEntityHandler);
|
||||
|
||||
register!(meta::DecisionsHandler);
|
||||
register!(meta::TechDebtHandler);
|
||||
register!(meta::LogDecisionHandler);
|
||||
register!(meta::QueryDecisionsHandler);
|
||||
register!(meta::DeleteDecisionHandler);
|
||||
register!(meta::LogErrorFixHandler);
|
||||
register!(meta::SearchErrorFixesHandler);
|
||||
register!(meta::LogCodeChangeHandler);
|
||||
register!(meta::QueryRecentChangesHandler);
|
||||
register!(meta::LearnPreferenceHandler);
|
||||
register!(meta::ReadPreferencesHandler);
|
||||
register!(meta::LogTechDebtHandler);
|
||||
register!(meta::ResolveTechDebtHandler);
|
||||
register!(meta::ListTechDebtHandler);
|
||||
register!(meta::OmniSearchHandler);
|
||||
register!(meta::GetProjectHealthHandler);
|
||||
|
||||
register!(env::EnvironmentHandler);
|
||||
register!(env::UpdateEnvFingerprintHandler);
|
||||
register!(env::ReadEnvFingerprintHandler);
|
||||
register!(env::LogEnvRequirementHandler);
|
||||
register!(env::RegisterEnvironmentHandler);
|
||||
register!(env::GetEnvironmentDetailsHandler);
|
||||
|
||||
register!(workspaces::PinnedFilesHandler);
|
||||
register!(workspaces::ContextWorkspacesHandler);
|
||||
register!(workspaces::PrChecklistHandler);
|
||||
register!(workspaces::SnippetsHandler);
|
||||
register!(workspaces::PinFileHandler);
|
||||
register!(workspaces::UnpinFileHandler);
|
||||
register!(workspaces::ListPinnedFilesHandler);
|
||||
register!(workspaces::StoreSnippetHandler);
|
||||
register!(workspaces::SearchSnippetsHandler);
|
||||
register!(workspaces::DeleteSnippetHandler);
|
||||
register!(workspaces::SaveContextWorkspaceHandler);
|
||||
register!(workspaces::LoadContextWorkspaceHandler);
|
||||
register!(workspaces::ListContextWorkspacesHandler);
|
||||
register!(workspaces::DeleteContextWorkspaceHandler);
|
||||
register!(workspaces::AddPrChecklistItemHandler);
|
||||
register!(workspaces::GetPrChecklistHandler);
|
||||
register!(workspaces::ClearPrChecklistHandler);
|
||||
register!(vision::ClipboardHandler);
|
||||
register!(vision::ReadClipboardHandler);
|
||||
register!(vision::WriteClipboardHandler);
|
||||
|
||||
register!(git::GetActiveWorktreeContextHandler);
|
||||
register!(git::QueryGitDiffsHandler);
|
||||
register!(logs::WatchProcessLogsHandler);
|
||||
register!(logs::GetRecentLogsHandler);
|
||||
register!(ast::ReadFileSkeletonHandler);
|
||||
register!(vision::ToggleClipboardWatchModeHandler);
|
||||
register!(ast::ReplaceAstNodeHandler);
|
||||
register!(ast::FindSymbolReferencesHandler);
|
||||
register!(ast::GetCallersHandler);
|
||||
register!(ast::AnalyzeImpactHandler);
|
||||
register!(workspaces::ReadDirectoryArchitectureHandler);
|
||||
register!(workspaces::SemanticCodeSearchHandler);
|
||||
register!(workspaces::CreateSnapshotHandler);
|
||||
register!(workspaces::RestoreSnapshotHandler);
|
||||
register!(workspaces::CreateSubagentNamespaceHandler);
|
||||
register!(workspaces::ManageSubagentNamespaceHandler);
|
||||
register!(graph::GetSubgraphHandler);
|
||||
register!(meta::SuggestErrorFixHandler);
|
||||
register!(meta::CheckpointStateHandler);
|
||||
register!(meta::ManageCheckpointHandler);
|
||||
register!(meta::RestoreStateHandler);
|
||||
register!(workspaces::TagSnippetHandler);
|
||||
register!(workspaces::PurgeSubagentNamespaceHandler);
|
||||
register!(workspaces::CondenseSubagentNamespaceHandler);
|
||||
register!(graph::SweepGraphHealthHandler);
|
||||
register!(meta::QueryLineageHandler);
|
||||
register!(meta::GetNextActionableTasksHandler);
|
||||
@@ -595,7 +547,6 @@ impl MemoryHandler {
|
||||
register!(meta::BroadcastAgentSignalHandler);
|
||||
register!(meta::QueryAgentSignalsHandler);
|
||||
register!(meta::AutoSessionCheckpointHandler);
|
||||
register!(meta::SearchSnippetsHybridHandler);
|
||||
|
||||
Self {
|
||||
state,
|
||||
@@ -763,19 +714,21 @@ impl MemoryHandler {
|
||||
.unwrap_or(serde_json::Value::Object(Default::default()));
|
||||
|
||||
let category = match name {
|
||||
"read_clipboard" | "write_clipboard" | "toggle_clipboard_watch_mode" => "CLIPBOARD",
|
||||
"clipboard" => "CLIPBOARD",
|
||||
"create_entities" | "create_relations" | "read_graph" | "get_subgraph" | "search_graph" | "get_schema" => "GRAPH",
|
||||
"log_decision" => "DECISION",
|
||||
"decisions" => "DECISION",
|
||||
"log_code_change" => "CODE",
|
||||
"log_error_fix" => "ERROR_FIX",
|
||||
"log_tech_debt" => "TECH_DEBT",
|
||||
"add_task" | "update_task_status" | "delete_task" | "add_milestone" => "TASK",
|
||||
"manage_sticky_notes" | "read_notes" => "STICKY_NOTE",
|
||||
"tech_debt" => "TECH_DEBT",
|
||||
"tasks" | "milestones" => "TASK",
|
||||
"sticky_notes" | "handoff_memos" => "STICKY_NOTE",
|
||||
"manage_checkpoint" => "CHECKPOINT",
|
||||
"manage_subagent_namespace" => "SUBAGENT",
|
||||
"search_snippets" => "SNIPPET",
|
||||
"snippets" => "SNIPPET",
|
||||
"search_web" => "WEB_SEARCH",
|
||||
"omni_search" => "OMNI_SEARCH",
|
||||
"environment" => "ENVIRONMENT",
|
||||
"pinned_files" | "context_workspaces" | "pr_checklist" => "WORKSPACE",
|
||||
_ => "TOOL",
|
||||
};
|
||||
|
||||
@@ -829,10 +782,38 @@ impl MemoryHandler {
|
||||
|
||||
pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) -> String {
|
||||
let (action, detail) = match name {
|
||||
"tasks" => {
|
||||
let act = args.get("action").and_then(|v| v.as_str()).unwrap_or("manage");
|
||||
let title = args.get("title").or_else(|| args.get("id")).and_then(|v| v.as_str()).unwrap_or("");
|
||||
("Tasks", format!("{}: {}", act, title).trim_end_matches(": ").to_string())
|
||||
}
|
||||
"decisions" => {
|
||||
let act = args.get("action").and_then(|v| v.as_str()).unwrap_or("log");
|
||||
let title = args.get("title").or_else(|| args.get("query")).and_then(|v| v.as_str()).unwrap_or("");
|
||||
("Decisions", format!("{}: {}", act, title).trim_end_matches(": ").to_string())
|
||||
}
|
||||
"tech_debt" => {
|
||||
let act = args.get("action").and_then(|v| v.as_str()).unwrap_or("log");
|
||||
let desc = args.get("description").or_else(|| args.get("id")).and_then(|v| v.as_str()).unwrap_or("");
|
||||
("Tech Debt", format!("{}: {}", act, desc).trim_end_matches(": ").to_string())
|
||||
}
|
||||
"sticky_notes" => {
|
||||
let act = args.get("action").and_then(|v| v.as_str()).unwrap_or("add");
|
||||
let preview = args.get("content").and_then(|v| v.as_str()).map(|c| c.chars().take(40).collect::<String>()).unwrap_or_default();
|
||||
("Sticky Notes", format!("{}: {}", act, preview).trim_end_matches(": ").to_string())
|
||||
}
|
||||
"clipboard" => {
|
||||
let act = args.get("action").and_then(|v| v.as_str()).unwrap_or("read");
|
||||
("Clipboard", act.to_string())
|
||||
}
|
||||
"snippets" => {
|
||||
let act = args.get("action").and_then(|v| v.as_str()).unwrap_or("search");
|
||||
let q = args.get("query").and_then(|v| v.as_str()).unwrap_or("");
|
||||
("Snippets", format!("{}: {}", act, q).trim_end_matches(": ").to_string())
|
||||
}
|
||||
"log_code_change" => {
|
||||
let file = args.get("file_path")
|
||||
.or_else(|| args.get("file"))
|
||||
.or_else(|| args.get("path"))
|
||||
.or_else(|| args.get("target_file"))
|
||||
.and_then(|v| v.as_str());
|
||||
let summary = args.get("summary")
|
||||
@@ -847,15 +828,6 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
|
||||
};
|
||||
("Log Code Change", d)
|
||||
}
|
||||
"log_decision" => {
|
||||
let d = args.get("title")
|
||||
.or_else(|| args.get("decision"))
|
||||
.or_else(|| args.get("summary"))
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
("Log Decision", d)
|
||||
}
|
||||
"log_error_fix" => {
|
||||
let d = args.get("error")
|
||||
.or_else(|| args.get("summary"))
|
||||
@@ -865,16 +837,6 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
|
||||
.to_string();
|
||||
("Log Error Fix", d)
|
||||
}
|
||||
"log_tech_debt" => {
|
||||
let d = if let Some(summary) = args.get("summary").or_else(|| args.get("description")).and_then(|v| v.as_str()) {
|
||||
summary.to_string()
|
||||
} else if let Some(file) = args.get("file_path").or_else(|| args.get("file")).and_then(|v| v.as_str()) {
|
||||
file.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
("Log Tech Debt", d)
|
||||
}
|
||||
"create_entities" => {
|
||||
let d = if let Some(entities) = args.get("entities").and_then(|v| v.as_array()) {
|
||||
let names: Vec<&str> = entities
|
||||
@@ -917,54 +879,17 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
|
||||
};
|
||||
("Create Relations", d)
|
||||
}
|
||||
"add_task" => {
|
||||
let d = args.get("title")
|
||||
.or_else(|| args.get("name"))
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
("Add Task", d)
|
||||
}
|
||||
"update_task_status" => {
|
||||
let d = if let (Some(id), Some(status)) = (
|
||||
args.get("task_id").or_else(|| args.get("id")).and_then(|v| v.as_str()),
|
||||
args.get("status").and_then(|v| v.as_str()),
|
||||
) {
|
||||
format!("Task {} -> {}", id, status)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
("Update Task Status", d)
|
||||
}
|
||||
"omni_search" | "search_graph" | "search_snippets" | "search_web" => {
|
||||
"omni_search" | "search_graph" | "search_web" => {
|
||||
let d = args.get("query")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|q| format!("\"{}\"", q))
|
||||
.unwrap_or_default();
|
||||
("Search", d)
|
||||
}
|
||||
"manage_sticky_notes" | "add_sticky_note" => {
|
||||
let action = args.get("action").and_then(|v| v.as_str()).unwrap_or("add");
|
||||
let d = if let Some(content) = args.get("content").and_then(|v| v.as_str()) {
|
||||
let preview: String = content.chars().take(40).collect();
|
||||
format!("{} \"{}\"", action, preview)
|
||||
} else {
|
||||
action.to_string()
|
||||
};
|
||||
("Sticky Note", d)
|
||||
}
|
||||
"write_clipboard" => {
|
||||
let d = if let Some(text) = args.get("text").or_else(|| args.get("content")).and_then(|v| v.as_str()) {
|
||||
let preview: String = text.chars().take(40).collect();
|
||||
format!("\"{}\"", preview)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
("Write Clipboard", d)
|
||||
}
|
||||
_ => {
|
||||
let d = if let Some(title) = args
|
||||
let d = args
|
||||
.get("title")
|
||||
.or_else(|| args.get("action"))
|
||||
.or_else(|| args.get("summary"))
|
||||
.or_else(|| args.get("description"))
|
||||
.or_else(|| args.get("name"))
|
||||
@@ -973,12 +898,8 @@ pub fn format_tool_activity_description(name: &str, args: &serde_json::Value) ->
|
||||
.or_else(|| args.get("file"))
|
||||
.or_else(|| args.get("path"))
|
||||
.and_then(|v| v.as_str())
|
||||
{
|
||||
title.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
(name, d)
|
||||
.unwrap_or("");
|
||||
(name, d.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1021,7 +942,7 @@ mod tests {
|
||||
|
||||
// Assert some known tools are registered
|
||||
assert!(handler.tools.contains_key("create_entities"));
|
||||
assert!(handler.tools.contains_key("add_task"));
|
||||
assert!(handler.tools.contains_key("tasks"));
|
||||
|
||||
// Ensure we can fetch list of tools
|
||||
let list_tools_req = json!({
|
||||
@@ -1145,10 +1066,11 @@ mod tests {
|
||||
"id": 3,
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "update_task_status",
|
||||
"name": "tasks",
|
||||
"arguments": {
|
||||
"action": "update",
|
||||
"id": "nonexistent_task_123",
|
||||
"status": "in_progress"
|
||||
"status": "completed"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user