use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub mod filesystem;
pub mod mem8;
pub mod openapi;
pub mod qcp;
pub mod sse;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContextNode {
pub id: String,
pub name: String,
pub node_type: NodeType,
pub quantum_state: Option<QuantumState>,
pub children: Vec<ContextNode>,
pub metadata: serde_json::Value,
pub entanglements: Vec<Entanglement>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NodeType {
Directory,
File,
ApiEndpoint,
ApiSchema,
WebSocketChannel,
QuantumWave,
EntangledState,
Superposition,
EventSource,
EventType,
MemoryWave,
ConsciousnessStream,
EmotionalContext,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuantumState {
pub amplitude: f64,
pub frequency: f64,
pub phase: f64,
pub collapse_probability: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entanglement {
pub target_id: String,
pub strength: f64,
pub relationship: String,
}
#[async_trait]
pub trait InputAdapter: Send + Sync {
fn name(&self) -> &'static str;
fn supported_formats(&self) -> Vec<&'static str>;
async fn can_handle(&self, input: &InputSource) -> bool;
async fn parse(&self, input: InputSource) -> Result<ContextNode>;
fn wave_signature(&self) -> Option<String> {
None
}
}
#[derive(Debug, Clone)]
pub enum InputSource {
Path(PathBuf),
Url(String),
Raw {
data: Vec<u8>,
format_hint: Option<String>,
},
QcpQuery { endpoint: String, query: String },
Mem8Stream {
stream_id: String,
temporal_range: Option<(i64, i64)>,
},
}
pub struct InputProcessor {
adapters: Vec<Box<dyn InputAdapter>>,
}
impl Default for InputProcessor {
fn default() -> Self {
Self::new()
}
}
impl InputProcessor {
pub fn new() -> Self {
Self {
adapters: vec![
Box::new(filesystem::FileSystemAdapter),
Box::new(qcp::QcpAdapter::new()),
Box::new(sse::SseAdapter),
Box::new(openapi::OpenApiAdapter),
Box::new(mem8::Mem8Adapter),
],
}
}
pub async fn process(&self, input: InputSource) -> Result<ContextNode> {
for adapter in &self.adapters {
if adapter.can_handle(&input).await {
eprintln!("🌊 Using {} adapter for input", adapter.name());
return adapter.parse(input).await;
}
}
anyhow::bail!("No adapter found for input source")
}
pub fn detect_input_type(input: &str) -> InputSource {
if input.starts_with("http://") || input.starts_with("https://") {
InputSource::Url(input.to_string())
} else if input.starts_with("qcp://") {
let parts: Vec<&str> = input.splitn(2, "://").collect();
InputSource::QcpQuery {
endpoint: "https://qcp.q8.is".to_string(),
query: parts.get(1).unwrap_or(&"").to_string(),
}
} else if input.starts_with("mem8://") {
let stream_id = input.trim_start_matches("mem8://");
InputSource::Mem8Stream {
stream_id: stream_id.to_string(),
temporal_range: None,
}
} else {
InputSource::Path(PathBuf::from(input))
}
}
}
pub fn context_to_file_nodes(context: ContextNode) -> Vec<crate::FileNode> {
let mut nodes = Vec::new();
convert_node(&context, &mut nodes, 0);
nodes
}
fn convert_node(context: &ContextNode, nodes: &mut Vec<crate::FileNode>, depth: usize) {
use crate::scanner::FileType;
use crate::{FileCategory, FileNode, FilesystemType};
use std::time::SystemTime;
let node = FileNode {
path: PathBuf::from(&context.id),
is_dir: !context.children.is_empty(),
size: context
.metadata
.get("size")
.and_then(|s| s.as_u64())
.unwrap_or(0),
modified: SystemTime::now(), permissions: 0o755,
uid: 1000,
gid: 1000,
is_symlink: false,
is_hidden: false,
permission_denied: false,
is_ignored: false,
depth,
file_type: match context.node_type {
NodeType::Directory => FileType::Directory,
NodeType::File => FileType::RegularFile,
NodeType::ApiEndpoint => FileType::RegularFile,
NodeType::QuantumWave => FileType::RegularFile,
NodeType::EventSource => FileType::RegularFile,
NodeType::MemoryWave => FileType::RegularFile,
_ => FileType::RegularFile,
},
category: match context.node_type {
NodeType::ApiEndpoint => FileCategory::Json,
NodeType::QuantumWave => FileCategory::Binary,
NodeType::EventSource => FileCategory::Json,
NodeType::MemoryWave => FileCategory::Binary,
_ => FileCategory::Unknown,
},
search_matches: None,
filesystem_type: FilesystemType::Unknown,
git_branch: None,
traversal_context: None,
interest: None,
security_findings: Vec::new(),
change_status: None,
content_hash: None,
};
nodes.push(node);
for child in &context.children {
convert_node(child, nodes, depth + 1);
}
}