feat: event-driven parity, Windows shell detection, dirty build timestamps, and gatekeeper integration
This commit is contained in:
1 parent
64857f9d5e
commit
f4dcf3acbf
33 files changed
+3501
-143
No files matched your search
@@ -772,6 +772,159 @@ impl MemoryHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
"tasks/complete" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let task_id = params.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
||||
if task_id.is_empty() {
|
||||
return Some(crate::mcp::error(id, -32602, "Missing task id parameter"));
|
||||
}
|
||||
self.state.project.tasks.modify(|tasks| {
|
||||
for t in tasks.iter_mut() {
|
||||
if t.id == task_id {
|
||||
t.status = "completed".to_string();
|
||||
t.updated_at = crate::handlers::utils::now_secs();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
let unblocked = crate::handlers::reconciliation::cascade_unblock_tasks(&self.state);
|
||||
let milestones = crate::handlers::reconciliation::recalculate_milestones(&self.state);
|
||||
self.state.record_activity("task", &format!("Completed task via WebSocket RPC: {}", task_id), Some("completed"));
|
||||
let _ = self.state.event_bus_tx.send(crate::state::GenericEvent {
|
||||
topic: "task:event".to_string(),
|
||||
session_id: None,
|
||||
payload: serde_json::json!({
|
||||
"task_id": task_id,
|
||||
"status": "completed",
|
||||
"unblocked_tasks": unblocked,
|
||||
"updated_milestones": milestones,
|
||||
}),
|
||||
});
|
||||
Some(crate::mcp::success(id, serde_json::json!({
|
||||
"status": "success",
|
||||
"unblocked_tasks": unblocked,
|
||||
"updated_milestones": milestones
|
||||
})))
|
||||
}
|
||||
"tech_debts/resolve" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let debt_id = params.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
||||
if debt_id.is_empty() {
|
||||
return Some(crate::mcp::error(id, -32602, "Missing debt id parameter"));
|
||||
}
|
||||
let mut found = false;
|
||||
self.state.code.tech_debts.modify(|debts| {
|
||||
for d in debts.iter_mut() {
|
||||
if d.id == debt_id {
|
||||
d.is_resolved = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
if found {
|
||||
self.state.record_activity("tech_debt", &format!("Resolved tech debt via WebSocket RPC: {}", debt_id), Some("resolved"));
|
||||
let _ = self.state.event_bus_tx.send(crate::state::GenericEvent {
|
||||
topic: "tech_debt:event".to_string(),
|
||||
session_id: None,
|
||||
payload: serde_json::json!({
|
||||
"id": debt_id,
|
||||
"status": "resolved"
|
||||
}),
|
||||
});
|
||||
Some(crate::mcp::success(id, serde_json::json!({ "status": "success", "message": format!("Tech debt {} resolved", debt_id) })))
|
||||
} else {
|
||||
Some(crate::mcp::error(id, -32602, "Tech debt not found"))
|
||||
}
|
||||
}
|
||||
"gates/authorize" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let gate_id = params.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let mut found = false;
|
||||
self.state.env.gates.modify(|gates| {
|
||||
for g in gates.iter_mut() {
|
||||
if g.id == gate_id {
|
||||
g.status = "authorized".to_string();
|
||||
g.reason = Some("Manually authorized via WebSocket RPC".to_string());
|
||||
g.timestamp = crate::handlers::utils::now_secs();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
if found {
|
||||
self.state.record_activity("gate", &format!("Authorized push gate via WebSocket: {}", gate_id), Some("authorized"));
|
||||
let _ = self.state.event_bus_tx.send(crate::state::GenericEvent {
|
||||
topic: "gate:event".to_string(),
|
||||
session_id: None,
|
||||
payload: serde_json::json!({ "id": gate_id, "status": "authorized", "active_gate": "authorized" }),
|
||||
});
|
||||
Some(crate::mcp::success(id, serde_json::json!({ "status": "success" })))
|
||||
} else {
|
||||
Some(crate::mcp::error(id, -32602, "Gate not found"))
|
||||
}
|
||||
}
|
||||
"gates/block" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let gate_id = params.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let mut found = false;
|
||||
self.state.env.gates.modify(|gates| {
|
||||
for g in gates.iter_mut() {
|
||||
if g.id == gate_id {
|
||||
g.status = "blocked".to_string();
|
||||
g.reason = Some("Manually blocked via WebSocket RPC".to_string());
|
||||
g.timestamp = crate::handlers::utils::now_secs();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
if found {
|
||||
self.state.record_activity("gate", &format!("Blocked push gate via WebSocket: {}", gate_id), Some("blocked"));
|
||||
let _ = self.state.event_bus_tx.send(crate::state::GenericEvent {
|
||||
topic: "gate:event".to_string(),
|
||||
session_id: None,
|
||||
payload: serde_json::json!({ "id": gate_id, "status": "blocked", "active_gate": "blocked" }),
|
||||
});
|
||||
Some(crate::mcp::success(id, serde_json::json!({ "status": "success" })))
|
||||
} else {
|
||||
Some(crate::mcp::error(id, -32602, "Gate not found"))
|
||||
}
|
||||
}
|
||||
"gates/delete" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let gate_id = params.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let mut removed = false;
|
||||
self.state.env.gates.modify(|gates| {
|
||||
if let Some(pos) = gates.iter().position(|g| g.id == gate_id) {
|
||||
gates.remove(pos);
|
||||
removed = true;
|
||||
}
|
||||
});
|
||||
if removed {
|
||||
self.state.record_activity("gate", &format!("Deleted push gate via WebSocket: {}", gate_id), Some("deleted"));
|
||||
let _ = self.state.event_bus_tx.send(crate::state::GenericEvent {
|
||||
topic: "gate:event".to_string(),
|
||||
session_id: None,
|
||||
payload: serde_json::json!({ "id": gate_id, "status": "deleted" }),
|
||||
});
|
||||
Some(crate::mcp::success(id, serde_json::json!({ "status": "success" })))
|
||||
} else {
|
||||
Some(crate::mcp::error(id, -32602, "Gate not found"))
|
||||
}
|
||||
}
|
||||
"resources/subscribe" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let uri = params.get("uri").and_then(|u| u.as_str()).unwrap_or("");
|
||||
tracing::info!("Client subscribed to MCP resource: {}", uri);
|
||||
Some(crate::mcp::success(id, serde_json::json!({})))
|
||||
}
|
||||
"resources/unsubscribe" => {
|
||||
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
|
||||
let uri = params.get("uri").and_then(|u| u.as_str()).unwrap_or("");
|
||||
tracing::info!("Client unsubscribed from MCP resource: {}", uri);
|
||||
Some(crate::mcp::success(id, serde_json::json!({})))
|
||||
}
|
||||
m if m.starts_with("notifications/") => None,
|
||||
"ping" => Some(crate::mcp::success(id, serde_json::json!({}))),
|
||||
_ => {
|
||||
|
||||
Reference in new issue
Block a user