Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cd0567d
docs: expand planned features documentation with comprehensive analysis
avrabe Jul 23, 2025
e9cf7aa
feat(mcp): activate automatic streaming when listeners are added
avrabe Jul 24, 2025
7f46e40
feat(mcp): expose streaming methods in McpService API
avrabe Jul 24, 2025
71fe303
feat(diagram): integrate real-time streaming for diagram updates
avrabe Jul 24, 2025
ef1ee0f
feat(app): add comprehensive MCP streaming integration at app level
avrabe Jul 24, 2025
8387071
feat(mcp): enable comprehensive notification system for bidirectional…
avrabe Jul 24, 2025
c5ab923
feat(mcp): enhance stream listeners for real-time component and valid…
avrabe Jul 24, 2025
d1a0cc1
feat(mcp): implement comprehensive connection health monitoring UI
avrabe Jul 24, 2025
d0583b8
fix(lint): remove unnecessary try/catch wrapper in ping method
avrabe Jul 24, 2025
5006224
fix: resolve circular import preventing AppController initialization
avrabe Jul 24, 2025
3364c77
feat: implement AI Assistant model selection with offline handling
avrabe Jul 24, 2025
0804d1c
feat: implement dynamic edge creation types (Issue #8)
avrabe Jul 24, 2025
11d9423
feat: implement comprehensive responsive header behavior
avrabe Jul 25, 2025
1eb9bba
fix: ensure AI Assistant floats properly on desktop breakpoints
avrabe Jul 25, 2025
142a881
fix: correctly mount toolbar in sidebar instead of covering canvas
avrabe Jul 25, 2025
9b9de36
chore: update diagram workspace files after testing
avrabe Jul 26, 2025
702d813
feat: implement comprehensive tooltip and notification systems
avrabe Jul 26, 2025
7c59f1c
feat: implement comprehensive UML interface view with separate compon…
avrabe Jul 26, 2025
ed658a2
fix: resolve Clippy uninlined format arguments warnings
avrabe Jul 29, 2025
611fdd2
feat: activate WIT icon system for enhanced element visualization
avrabe Jul 29, 2025
3b0a2e4
feat: enhance WASM component rendering and analysis capabilities
avrabe Jul 29, 2025
6d5e597
feat: enhance dialog system with improved UX and effects
avrabe Jul 29, 2025
07a5705
refactor: activate planned features and improve system integration
avrabe Jul 29, 2025
5a91277
fix: resolve WASM component loading field name mismatch
avrabe Jul 30, 2025
a77a678
ci: update CI to use Ubuntu 24.04 to fix GLIBC compatibility
avrabe Jul 30, 2025
5888dc6
Update CI dependencies for Ubuntu 24.04 compatibility
avrabe Jul 30, 2025
b96e7be
Add libsoup2.4-dev for Tauri compatibility in Ubuntu 24.04
avrabe Jul 30, 2025
bccc350
Add libjavascriptcoregtk-4.1-dev for WebKit support in Ubuntu 24.04
avrabe Jul 30, 2025
54bb919
Add both JavaScriptCore GTK 4.0 and 4.1 for compatibility
avrabe Jul 30, 2025
36b86c2
Create JavaScriptCore GTK 4.0 compatibility symlink for 4.1
avrabe Jul 30, 2025
26a9380
Implement official Tauri Ubuntu 24.04 workaround using Ubuntu 22.04 r…
avrabe Jul 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, windows-latest, macOS-latest]
os: [ubuntu-24.04, windows-latest, macOS-latest]
rust: [stable]
steps:
- uses: actions/checkout@v4
Expand All @@ -41,7 +41,13 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev libsoup2.4-dev
# Official Tauri workaround for Ubuntu 24.04 - temporarily add Ubuntu 22.04 repos for legacy WebKit
echo "deb http://archive.ubuntu.com/ubuntu jammy main universe" | sudo tee /etc/apt/sources.list.d/ubuntu22.list
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev
# Clean up temporary repository
sudo rm /etc/apt/sources.list.d/ubuntu22.list
sudo apt-get update

- name: Check formatting
run: cargo fmt -- --check
Expand Down Expand Up @@ -72,7 +78,7 @@ jobs:

build-web-client:
name: Build Web Client
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

Expand All @@ -96,7 +102,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, windows-latest, macOS-latest]
os: [ubuntu-24.04, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v4

Expand All @@ -112,7 +118,13 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev libsoup2.4-dev
# Official Tauri workaround for Ubuntu 24.04 - temporarily add Ubuntu 22.04 repos for legacy WebKit
echo "deb http://archive.ubuntu.com/ubuntu jammy main universe" | sudo tee /etc/apt/sources.list.d/ubuntu22.list
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev
# Clean up temporary repository
sudo rm /etc/apt/sources.list.d/ubuntu22.list
sudo apt-get update

- name: Install web client dependencies
working-directory: ./glsp-web-client
Expand Down
251 changes: 232 additions & 19 deletions glsp-mcp-server/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,51 @@ impl GlspBackend {
});
}

// Add resources for individual WASM components
let wasm_watcher = self.wasm_watcher.lock().await;
let wasm_components = wasm_watcher.get_components();
for component in wasm_components {
resources.push(Resource {
uri: format!("wasm://component/{}", component.name),
name: format!("WASM Component: {}", component.name),
description: Some(format!("Details for {} component", component.name)),
mime_type: Some("application/json".to_string()),
annotations: None,
raw: None,
});

// Add WIT-specific resources for each component
resources.push(Resource {
uri: format!("wasm://component/{}/wit", component.name),
name: format!("WIT Analysis: {}", component.name),
description: Some(format!(
"WIT interface analysis for {} component",
component.name
)),
mime_type: Some("application/json".to_string()),
annotations: None,
raw: None,
});

resources.push(Resource {
uri: format!("wasm://component/{}/wit/raw", component.name),
name: format!("Raw WIT: {}", component.name),
description: Some(format!("Raw WIT content for {} component", component.name)),
mime_type: Some("text/plain".to_string()),
annotations: None,
raw: None,
});

resources.push(Resource {
uri: format!("wasm://component/{}/interfaces", component.name),
name: format!("Interfaces: {}", component.name),
description: Some(format!("All interfaces for {} component", component.name)),
mime_type: Some("application/json".to_string()),
annotations: None,
raw: None,
});
}

Ok(ListResourcesResult {
resources,
next_cursor: None,
Expand Down Expand Up @@ -1336,33 +1381,32 @@ impl GlspBackend {
}],
})
} else if request.uri == "wasm://components/list" {
// Get WASM files from the filesystem watcher
let filesystem_watcher = self.filesystem_watcher.read().await;
let known_files = filesystem_watcher.get_known_files().await;
// Get WASM components from the wasm watcher (with analyzed data)
let wasm_watcher = self.wasm_watcher.lock().await;
let wasm_components = wasm_watcher.get_components();

let component_list: Vec<serde_json::Value> = known_files
let component_list: Vec<serde_json::Value> = wasm_components
.iter()
.filter_map(|path| {
// Extract component name from file path
let file_name = path.file_stem()?.to_str()?;
let component_name = file_name.replace('-', "_");

Some(json!({
"name": component_name,
"path": path.to_string_lossy(),
"description": format!("WASM component: {component_name}"),
"status": "available",
"interfaces": 2, // Default interface count
"uri": format!("wasm://component/{component_name}")
}))
.map(|component| {
json!({
"name": component.name,
"path": component.path,
"description": format!("WASM component: {}", component.name),
"status": if component.file_exists { "available" } else { "missing" },
"interfaces": component.interfaces.len(),
"uri": format!("wasm://component/{}", component.name)
})
})
.collect();

let available_count = wasm_components.iter().filter(|c| c.file_exists).count();
let missing_count = wasm_components.len() - available_count;

let wasm_list = json!({
"components": component_list,
"total": component_list.len(),
"available": component_list.len(),
"missing": 0
"available": available_count,
"missing": missing_count
});

Ok(ReadResourceResult {
Expand All @@ -1373,6 +1417,30 @@ impl GlspBackend {
blob: None,
}],
})
} else if request.uri.starts_with("wasm://component/") {
let path = request
.uri
.strip_prefix("wasm://component/")
.ok_or_else(|| {
GlspError::NotImplemented(format!(
"Invalid WASM component URI: {}",
request.uri
))
})?;

if let Some((component_name, suffix)) = path.split_once('/') {
match suffix {
"wit" => self.get_component_wit_analysis(component_name).await,
"wit/raw" => self.get_component_raw_wit(component_name).await,
"interfaces" => self.get_component_interfaces(component_name).await,
_ => Err(GlspError::NotImplemented(format!(
"Unknown component resource: {}",
request.uri
))),
}
} else {
self.get_wasm_component_details(path).await
}
} else {
Err(GlspError::NotImplemented(format!(
"Resource type not supported: {}",
Expand All @@ -1381,6 +1449,151 @@ impl GlspBackend {
}
}

// Helper methods for component-specific resources
async fn get_wasm_component_details(
&self,
component_name: &str,
) -> std::result::Result<ReadResourceResult, GlspError> {
let wasm_watcher = self.wasm_watcher.lock().await;
let component = wasm_watcher.get_component(component_name).ok_or_else(|| {
GlspError::NotImplemented(format!("WASM component not found: {component_name}"))
})?;

let content = json!({
"name": component.name,
"path": component.path,
"description": component.description,
"fileExists": component.file_exists,
"lastSeen": component.last_seen,
"removedAt": component.removed_at,
"interfaces": component.interfaces,
"metadata": component.metadata,
"witInterfaces": component.wit_interfaces,
"dependencies": component.dependencies
});

Ok(ReadResourceResult {
contents: vec![ResourceContents {
uri: format!("wasm://component/{component_name}"),
mime_type: Some("application/json".to_string()),
text: Some(content.to_string()),
blob: None,
}],
})
}

async fn get_component_interfaces(
&self,
component_name: &str,
) -> std::result::Result<ReadResourceResult, GlspError> {
let wasm_watcher = self.wasm_watcher.lock().await;
let component = wasm_watcher.get_component(component_name).ok_or_else(|| {
GlspError::NotImplemented(format!("WASM component not found: {component_name}"))
})?;

let content = json!({
"componentName": component.name,
"interfaces": component.interfaces,
"totalInterfaces": component.interfaces.len()
});

Ok(ReadResourceResult {
contents: vec![ResourceContents {
uri: format!("wasm://component/{component_name}/interfaces"),
mime_type: Some("application/json".to_string()),
text: Some(content.to_string()),
blob: None,
}],
})
}

async fn get_component_wit_analysis(
&self,
component_name: &str,
) -> std::result::Result<ReadResourceResult, GlspError> {
let wasm_watcher = self.wasm_watcher.lock().await;
let component = wasm_watcher.get_component(component_name).ok_or_else(|| {
GlspError::NotImplemented(format!("WASM component not found: {component_name}"))
})?;

// Analyze WIT interfaces specifically
let mut imports = Vec::new();
let mut exports = Vec::new();

for interface in &component.interfaces {
let interface_data = json!({
"name": interface.name,
"functions": interface.functions.iter().map(|f| json!({
"name": f.name,
"parameters": f.params.iter().map(|p| json!({
"name": p.name,
"type": p.param_type
})).collect::<Vec<_>>(),
"returns": f.returns.iter().map(|r| json!({
"name": r.name,
"type": r.param_type
})).collect::<Vec<_>>()
})).collect::<Vec<_>>()
});

match interface.interface_type.as_str() {
"import" => imports.push(interface_data),
"export" => exports.push(interface_data),
_ => {}
}
}

let content = json!({
"componentName": component.name,
"witAnalysis": {
"imports": imports,
"exports": exports,
"summary": {
"totalImports": imports.len(),
"totalExports": exports.len(),
"totalFunctions": component.interfaces.iter()
.map(|i| i.functions.len())
.sum::<usize>()
}
},
"metadata": component.metadata,
"dependencies": component.dependencies
});

Ok(ReadResourceResult {
contents: vec![ResourceContents {
uri: format!("wasm://component/{component_name}/wit"),
mime_type: Some("application/json".to_string()),
text: Some(content.to_string()),
blob: None,
}],
})
}

async fn get_component_raw_wit(
&self,
component_name: &str,
) -> std::result::Result<ReadResourceResult, GlspError> {
let wasm_watcher = self.wasm_watcher.lock().await;
let component = wasm_watcher.get_component(component_name).ok_or_else(|| {
GlspError::NotImplemented(format!("WASM component not found: {component_name}"))
})?;

let wit_content = component
.wit_interfaces
.clone()
.unwrap_or_else(|| "// No WIT content available for this component".to_string());

Ok(ReadResourceResult {
contents: vec![ResourceContents {
uri: format!("wasm://component/{component_name}/wit/raw"),
mime_type: Some("text/plain".to_string()),
text: Some(wit_content),
blob: None,
}],
})
}

pub async fn list_prompts(
&self,
_request: PaginatedRequestParam,
Expand Down
Loading
Loading