pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
#[async_trait]
impl DemoProtocol for HttpDemoAdapter {
    type Request = HttpRequest;
    type Response = HttpResponse;
    type Error = HttpDemoError;

    async fn decode_request(&self, raw: &[u8]) -> Result<Self::Request, Self::Error> {
        let value: Value = serde_json::from_slice(raw)?;

        let method = value
            .get("method")
            .and_then(|v| v.as_str())
            .unwrap_or("GET")
            .to_string();

        let path = value
            .get("path")
            .and_then(|v| v.as_str())
            .unwrap_or("/demo/analyze")
            .to_string();

        let query_params = value
            .get("query")
            .and_then(|v| v.as_object())
            .map(|obj| {
                obj.iter()
                    .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
                    .collect()
            })
            .unwrap_or_default();

        let headers = value
            .get("headers")
            .and_then(|v| v.as_object())
            .map(|obj| {
                obj.iter()
                    .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
                    .collect()
            })
            .unwrap_or_else(|| {
                [("Accept".to_string(), "application/json".to_string())]
                    .into_iter()
                    .collect()
            });

        let body = value.get("body").cloned();
        let remote_addr = value
            .get("remote_addr")
            .and_then(|v| v.as_str())
            .map(std::string::ToString::to_string);

        Ok(HttpRequest {
            method,
            path,
            query_params,
            headers,
            body,
            remote_addr,
        })
    }

    async fn encode_response(&self, resp: Self::Response) -> Result<Vec<u8>, Self::Error> {
        let json = serde_json::to_vec_pretty(&resp)?;
        Ok(json)
    }

    async fn get_protocol_metadata(&self) -> ProtocolMetadata {
        ProtocolMetadata {
            name: "http",
            version: "1.1",
            description: "HTTP/REST protocol for web-based access".to_string(),
            request_schema: serde_json::json!({
                "type": "object",
                "properties": {
                    "method": {
                        "type": "string",
                        "enum": ["GET", "POST"],
                        "default": "GET"
                    },
                    "path": {
                        "type": "string",
                        "description": "Request path",
                        "default": "/demo/analyze"
                    },
                    "query": {
                        "type": "object",
                        "description": "Query parameters"
                    },
                    "headers": {
                        "type": "object",
                        "description": "HTTP headers"
                    },
                    "body": {
                        "description": "Request body (for POST requests)"
                    }
                }
            }),
            response_schema: serde_json::json!({
                "type": "object",
                "properties": {
                    "status": {
                        "type": "integer",
                        "description": "HTTP status code"
                    },
                    "headers": {
                        "type": "object",
                        "description": "Response headers"
                    },
                    "body": {
                        "description": "Response body (varies by endpoint)"
                    }
                },
                "required": ["status", "body"]
            }),
            example_requests: vec![
                serde_json::json!({
                    "method": "GET",
                    "path": "/demo/analyze",
                    "query": {"path": "/repo"},
                    "headers": {"Accept": "application/json"}
                }),
                serde_json::json!({
                    "method": "GET",
                    "path": "/demo/api"
                }),
            ],
            capabilities: vec![
                "rest_api".to_string(),
                "async_requests".to_string(),
                "status_polling".to_string(),
                "api_introspection".to_string(),
                "json_responses".to_string(),
            ],
        }
    }

    async fn execute_demo(&self, request: Self::Request) -> Result<Self::Response, Self::Error> {
        let request_id = Uuid::new_v4().to_string();

        let body = match request.path.as_str() {
            path if path.starts_with("/demo/analyze") => {
                self.handle_analyze_request(&request).await?
            }
            path if path.starts_with("/demo/status/") => {
                self.handle_status_request(&request).await?
            }
            path if path.starts_with("/demo/results/") => {
                self.handle_results_request(&request).await?
            }
            "/demo/api" => self.handle_api_introspection().await?,
            _ => {
                return Err(HttpDemoError::InvalidPath(format!(
                    "Unknown endpoint: {}",
                    request.path
                )));
            }
        };

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_string(), "application/json".to_string());
        headers.insert("X-Request-ID".to_string(), request_id.clone());
        headers.insert("Access-Control-Allow-Origin".to_string(), "*".to_string());

        Ok(HttpResponse {
            status: 200,
            headers,
            body,
            request_id,
        })
    }
}