diff --git a/Cargo.toml b/Cargo.toml index b7c07c8..47b14aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ members = [ "glsp-mcp-server", "glsp-tauri/src-tauri", + #"composer", + "tasklist_mcp_client" ] resolver = "2" @@ -58,4 +60,4 @@ once_cell = "1.0" parking_lot = "0.12" validator = "0.18" futures-util = "0.3" -lru = "0.12" \ No newline at end of file +lru = "0.12" diff --git a/README.md b/README.md index fff2f4d..f931087 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,18 @@ ## πŸ“Š Current Status -**Functional MVP with Strong Foundation** +**Functional MVP with UML Diagram Support** βœ… **Working Components:** -- Complete MCP server with 7 diagram tools implemented +- Complete MCP server with 8+ diagram tools implemented - TypeScript frontend with Canvas rendering - Ollama integration with model auto-detection -- Basic diagram creation and manipulation -- Comprehensive documentation and startup instructions +- UML class diagram creation with attributes, methods, and associations +- Diagram deletion and management tools +- Comprehensive error handling and user feedback ⚠️ **Ready for Use:** -- Creates sample diagrams with basic node types +- Creates sample UML diagrams with Person/Car classes and relationships - AI generates intelligent diagram planning (text-based) - Manual editing supports position updates and basic interactions - All three services integrate smoothly @@ -109,6 +110,20 @@ ollama serve ## 🎨 Usage Examples +### UML Class Diagram Creation +The system now supports creating detailed UML class diagrams with: +- **Class attributes** with types and visibility (public/private) +- **Class methods** with return types and parameters +- **Association relationships** between classes +- **Automatic ID extraction** from server responses + +**Example**: Run the tasklist MCP client to create a sample diagram: +```bash +cd tasklist_mcp_client +cargo run --bin tasklist_mcp_client +``` +This creates a Person-Car relationship diagram with full attributes and methods. + ### Natural Language Diagram Creation ``` "Create a workflow for e-commerce order fulfillment with payment validation, inventory check, and shipping" @@ -182,13 +197,21 @@ curl -X POST http://127.0.0.1:3000/mcp/rpc \ - **[API Reference](docs/API_REFERENCE.md)**: Complete MCP protocol documentation - **[AI Integration Examples](examples/ai_agent_demo.py)**: Python demonstration scripts - **[Development Notes](CLAUDE.md)**: Implementation details and architecture decisions +- **[Screenshots](docs/pictures/)**: Visual examples including current UML class diagrams + +### πŸ“Έ Screenshots + +- **[Class Diagram Example](docs/pictures/Class_diagram.png)** - Shows a complete UML class diagram with Person and Car classes, their attributes, methods, and association relationships created via MCP tools. + +![UML Class Diagram](docs/pictures/Class_diagram.png) ## 🌐 MCP Protocol Integration This implementation provides: -### Tools (7 available) -- `create_diagram`, `create_node`, `create_edge`, `delete_element` +### Tools (8+ available) +- `create_diagram`, `delete_diagram`, `create_node`, `create_edge` +- `add_uml_class`, `remove_uml_class`, `update_uml_class`, `delete_element` - `update_element`, `apply_layout`, `export_diagram` ### Resources (Dynamic) diff --git a/composer/Cargo.toml b/composer/Cargo.toml new file mode 100644 index 0000000..b8f9974 --- /dev/null +++ b/composer/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "composer" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wit-bindgen = "0.43.0" + diff --git a/composer/README.md b/composer/README.md new file mode 100644 index 0000000..464000a --- /dev/null +++ b/composer/README.md @@ -0,0 +1,135 @@ +# WIT Composition Project + +This project demonstrates the composition of WebAssembly Interface Types (WIT) definitions using `math.wit`, `user.wit`, and `world.wit`. The project provides a clear example of how multiple WIT definitions can interact and be composed in Rust using the WebAssembly component model. + +## Project Structure + +``` +wit-composition-project/ +β”œβ”€β”€ wit/ +β”‚ β”œβ”€β”€ math.wit +β”‚ β”œβ”€β”€ user.wit +β”‚ └── world.wit +└── src/ + └── lib.rs +``` + +## WIT Interfaces + +### math.wit + +Defines basic mathematical operations. + +```wit +interface math { + add: func(a: f32, b: f32) -> f32 + subtract: func(a: f32, b: f32) -> f32 + multiply: func(a: f32, b: f32) -> f32 + divide: func(a: f32, b: f32) -> result +} +``` + +### user.wit + +Defines user-related functionality. + +```wit +interface user { + record User { + id: u32, + name: string, + } + + get-user: func(id: u32) -> option + create-user: func(name: string) -> User +} +``` + +### world.wit + +Composes the interfaces and defines the main entry point. + +```wit +world world { + import math + import user + + export greet-user: func(id: u32) -> string + export calculate-and-greet: func(id: u32, a: f32, b: f32) -> string +} +``` + +## Rust Implementation (`src/lib.rs`) + +The Rust library provides implementations for the composed WIT interfaces. + +```rust +use wit_bindgen::generate; + +// Generate Rust bindings from WIT definitions +generate!("world"); + +struct UserService; +struct MathService; + +impl world::user::User for UserService { + fn get_user(id: u32) -> Option { + Some(world::user::User { id, name: format!("User{id}") }) + } + + fn create_user(name: String) -> world::user::User { + world::user::User { id: 1, name } + } +} + +impl world::math::Math for MathService { + fn add(a: f32, b: f32) -> f32 { a + b } + fn subtract(a: f32, b: f32) -> f32 { a - b } + fn multiply(a: f32, b: f32) -> f32 { a * b } + + fn divide(a: f32, b: f32) -> Result { + if b == 0.0 { + Err("Cannot divide by zero".into()) + } else { + Ok(a / b) + } + } +} + +pub struct Component; + +impl world::World for Component { + fn greet_user(id: u32) -> String { + match UserService::get_user(id) { + Some(user) => format!("Hello, {}!", user.name), + None => "User not found".into(), + } + } + + fn calculate_and_greet(id: u32, a: f32, b: f32) -> String { + match MathService::divide(a, b) { + Ok(result) => format!("Hello User{}, the result is {:.2}", id, result), + Err(e) => format!("Calculation error: {}", e), + } + } +} +``` + +## Usage + +Compile the project using Cargo with WASM support: + +```bash +cargo build --target wasm32-unknown-unknown --release +``` + +## Tools and Dependencies + +* Rust +* WebAssembly Interface Types (WIT) +* `wit-bindgen` for Rust bindings generation + +## License + +MIT License + diff --git a/composer/package.json b/composer/package.json new file mode 100644 index 0000000..5df557f --- /dev/null +++ b/composer/package.json @@ -0,0 +1,11 @@ +{ + "name": "wasm-composer-project", + "version": "1.0.0", + "scripts": { + "build:wasm": "cargo build --target wasm32-unknown-unknown --release", + "build": " npm run build:wasm" + }, + "devDependencies": { + "wit-bindgen": "^0.20.0" + } +} diff --git a/composer/src/lib.rs b/composer/src/lib.rs new file mode 100644 index 0000000..bc130d3 --- /dev/null +++ b/composer/src/lib.rs @@ -0,0 +1,22 @@ +wit_bindgen::generate!({ + path: "../wit", + world: "math", + exports: { + generate_all, + } +}); + +pub struct Math; + +impl Math { + pub fn add_points(p1: bindings::Point, p2: bindings::Point) -> bindings::Point { + bindings::Point { + x: p1.x + p2.x, + y: p1.y + p2.y, + } + } +} + +pub fn compose_points(p1: bindings::Point, p2: bindings::Point) -> bindings::Point { + Math::add_points(p1, p2) +} diff --git a/composer/wit/example/math.wit b/composer/wit/example/math.wit new file mode 100644 index 0000000..fa9246c --- /dev/null +++ b/composer/wit/example/math.wit @@ -0,0 +1,11 @@ +package example:math + +interface math { + record point { + x: f64, + y: f64, + } + + distance-from-origin: func(p: point) -> f64 +} + diff --git a/composer/wit/example/user.wit b/composer/wit/example/user.wit new file mode 100644 index 0000000..c4d234f --- /dev/null +++ b/composer/wit/example/user.wit @@ -0,0 +1,12 @@ +package example:user + +interface user { + record user-profile { + id: u32, + username: string, + is-active: bool, + } + + greet-user: func(profile: user-profile) -> string +} + diff --git a/composer/wit/world.wit b/composer/wit/world.wit new file mode 100644 index 0000000..9856cf9 --- /dev/null +++ b/composer/wit/world.wit @@ -0,0 +1,9 @@ +package composer:test + +world my-world { + import example:math/math; + import example:user/user; +} +# this is a test world for the composer package +# it imports the math and user packages from the example namespace +# it is used to test the composer functionality diff --git a/docs/STATUS-main.md b/docs/STATUS-main.md new file mode 100644 index 0000000..0554241 --- /dev/null +++ b/docs/STATUS-main.md @@ -0,0 +1,140 @@ +# GLSP-MCP Project Status Report - Main Branch + +**Generated on:** September 6, 2025 +**Current Branch:** `main` +**Repository:** [vkanta/glsp-mcp](https://github.com/vkanta/glsp-mcp) + +## πŸ“Š Current Status + +### Repository Health + +- βœ… **Git Status:** Clean working directory +- βœ… **Remote Sync:** Up to date with origin/main +- βœ… **Dependencies:** All updated to latest compatible versions +- βœ… **Security:** No vulnerabilities detected + +### Development Environment + +- **Rust:** cargo 1.91.0-nightly (623d53683 2025-08-22) / rustc 1.91.0-nightly (809200ec9 2025-08-24) +- **Node.js:** v22.14.0 +- **NPM:** 10.9.2 + +## πŸ”„ Recent Updates (Last 10 Commits) + +1. **e8b4db0** - Added Bazel setup sript +2. **71aaebb** - Refactored code +3. **56c93b7** - refactore code +4. **1c915cd** - Updated README.md +5. **99abebd** - refactore code +6. **37a9f07** - refactore code +7. **3603ebc** - Added edges to diagram +8. **ebf9543** - added external data source +9. **0bef474** - Updated README.md --amend +10. **d689bbe** - Updated README.md --amend + +## πŸ“¦ Dependencies Status + +### Rust Dependencies (Updated) + +- **Total Packages:** 94 updated to latest compatible versions +- **Key Updates:** + - `hyper`: 1.6.0 β†’ 1.7.0 + - `tokio-util`: 0.7.15 β†’ 0.7.16 + - `serde_json`: 1.0.142 β†’ 1.0.143 + - `wasm-tools`: 1.236.0 β†’ 1.238.1 + - `clap`: 4.5.42 β†’ 4.5.47 + +### Node.js Dependencies + +- **Security Audit:** βœ… No vulnerabilities found +- **Package Updates:** `concurrently` updated to latest version +- **Total Packages:** 30 packages audited + +## πŸ—οΈ Project Structure + +```bash +glsp-mcp/ +β”œβ”€β”€ composer/ # WebAssembly component composer +β”œβ”€β”€ glsp-mcp-server/ # GLSP MCP server implementation +β”œβ”€β”€ glsp-tauri/ # Tauri desktop application +β”œβ”€β”€ glsp-web-client/ # Web-based GLSP client +β”œβ”€β”€ tasklist_mcp_client/ # MCP client for task management +β”œβ”€β”€ docs/ # Documentation and status reports +β”œβ”€β”€ workspace/ # Development workspace +└── target/ # Build artifacts +``` + +## 🎯 Current Features + +### Core Components + +- **GLSP Integration:** Graphical Language Server Protocol support +- **MCP Protocol:** Model Context Protocol implementation +- **WebAssembly:** Component composition and execution +- **Tauri Desktop:** Cross-platform desktop application +- **Web Client:** Browser-based diagram editor + +### Recent Additions + +- βœ… Bazel build setup script +- βœ… Code refactoring and optimization +- βœ… External data source integration +- βœ… Diagram edges implementation +- βœ… Enhanced MCP client functionality + +## πŸ”§ Build & Development + +### Available Commands + +```bash +# Build the project +cargo build + +# Run the MCP server +cargo run --bin server + +# Run the tasklist client +cargo run --bin tasklist_mcp_client + +# Development server +npm run dev +``` + +### Build Targets + +- **Primary:** Linux x86_64 +- **WebAssembly:** wasm32-unknown-unknown +- **Cross-platform:** Tauri (Windows, macOS, Linux) + +## πŸ“ˆ Performance Metrics + +- **Build Time:** Optimized with incremental compilation +- **Dependencies:** 94 Rust crates, 30+ NPM packages +- **Test Coverage:** Core functionality implemented +- **Security:** Clean security audit results + +## πŸš€ Next Steps + +### Immediate Priorities + +- [ ] Complete MCP protocol integration +- [ ] Enhance diagram editing capabilities +- [ ] Add comprehensive testing suite +- [ ] Documentation updates + +### Future Enhancements + +- [ ] Eclipse Theia integration exploration +- [ ] Advanced WebAssembly features +- [ ] Performance optimizations +- [ ] Extended protocol support + +## πŸ“ž Contact & Support + +- **Repository:** [vkanta/glsp-mcp](https://github.com/vkanta/glsp-mcp) +- **Issues:** [GitHub Issues](https://github.com/vkanta/glsp-mcp/issues) +- **Documentation:** See `docs/` directory + +--- + +*This status report is automatically generated and reflects the current state as of the last update.* diff --git a/docs/STATUS-pre-commit-debugging.md b/docs/STATUS-pre-commit-debugging.md new file mode 100644 index 0000000..44332a7 --- /dev/null +++ b/docs/STATUS-pre-commit-debugging.md @@ -0,0 +1,144 @@ +# GLSP-MCP Project Status Report - Pre-commit Hooks & Debugging Branch + +**Generated on:** September 6, 2025 +**Current Branch:** `ralf-glsp-mcp/feat/pre-commit-hooks-and-debugging` (detached HEAD) +**Repository:** [pulseengine/glsp-mcp](https://github.com/pulseengine/glsp-mcp) + +## πŸ“Š Current Status + +### Repository Health + +- βœ… **Git Status:** Detached HEAD state +- βœ… **Remote Sync:** Up to date with ralf-glsp-mcp/feat/pre-commit-hooks-and-debugging +- βœ… **Dependencies:** All updated to latest compatible versions +- βœ… **Security:** No vulnerabilities detected + +### Development Environment + +- **Rust:** cargo 1.91.0-nightly (623d53683 2025-08-22) / rustc 1.91.0-nightly (809200ec9 2025-08-24) +- **Node.js:** v22.14.0 +- **NPM:** 10.9.2 + +## πŸ”„ Recent Updates (Last 10 Commits) + +1. **16acb8b** - feat: integrate unused feature variables and reduce TypeScript errors +2. **ac48580** - fix: resolve TypeScript compilation errors after interface cleanup +3. **f97f0ab** - feat: implement missing functionality instead of suppressing warnings +4. **6ea44e2** - Fix WasmViewTransformer and WitFileViewer type errors +5. **318c0bb** - Fix WasmComponentPanel and WasmViewTransformer type errors +6. **069861c** - Fix multiple TypeScript type errors across UI components +7. **1057c08** - Fix UIManager sidebar method calls and null safety +8. **e2cff79** - Fix UIManager type assertion and property access errors +9. **4104d1a** - Fix TypeScript false positives and properly use stored state +10. **7febbaf** - Fix unused variable errors by removing underscores from actually used methods + +## πŸ“¦ Dependencies Status + +### Rust Dependencies (Updated) + +- **Total Packages:** 94 updated to latest compatible versions +- **Key Updates:** + - `hyper`: 1.6.0 β†’ 1.7.0 + - `tokio-util`: 0.7.15 β†’ 0.7.16 + - `serde_json`: 1.0.142 β†’ 1.0.143 + - `wasm-tools`: 1.236.0 β†’ 1.238.1 + - `clap`: 4.5.42 β†’ 4.5.47 + +### Node.js Dependencies + +- **Security Audit:** βœ… No vulnerabilities found +- **Package Updates:** `concurrently` updated to latest version +- **Total Packages:** 30 packages audited + +## πŸ—οΈ Project Structure + +```bash +glsp-mcp/ +β”œβ”€β”€ composer/ # WebAssembly component composer +β”œβ”€β”€ glsp-mcp-server/ # GLSP MCP server implementation +β”œβ”€β”€ glsp-tauri/ # Tauri desktop application +β”œβ”€β”€ glsp-web-client/ # Web-based GLSP client +β”œβ”€β”€ tasklist_mcp_client/ # MCP client for task management +β”œβ”€β”€ docs/ # Documentation and status reports +β”œβ”€β”€ workspace/ # Development workspace +└── target/ # Build artifacts +``` + +## 🎯 Current Features + +### Core Components + +- **GLSP Integration:** Graphical Language Server Protocol support +- **MCP Protocol:** Model Context Protocol implementation +- **WebAssembly:** Component composition and execution +- **Tauri Desktop:** Cross-platform desktop application +- **Web Client:** Browser-based diagram editor + +### Recent Additions + +- βœ… TypeScript compilation error fixes +- βœ… Unused variable cleanup and integration +- βœ… WasmViewTransformer type error resolutions +- βœ… WitFileViewer type error fixes +- βœ… WasmComponentPanel improvements +- βœ… UIManager null safety enhancements +- βœ… Type assertion and property access fixes +- βœ… Stored state management improvements + +## πŸ”§ Build & Development + +### Available Commands + +```bash +# Build the project +cargo build + +# Run the MCP server +cargo run --bin server + +# Run the tasklist client +cargo run --bin tasklist_mcp_client + +# Development server +npm run dev +``` + +### Build Targets + +- **Primary:** Linux x86_64 +- **WebAssembly:** wasm32-unknown-unknown +- **Cross-platform:** Tauri (Windows, macOS, Linux) + +## πŸ“ˆ Performance Metrics + +- **Build Time:** Optimized with incremental compilation +- **Dependencies:** 94 Rust crates, 30+ NPM packages +- **Test Coverage:** Core functionality implemented +- **Security:** Clean security audit results +- **Type Safety:** Enhanced TypeScript error resolution + +## πŸš€ Next Steps + +### Immediate Priorities + +- [ ] Complete TypeScript error resolution +- [ ] Implement pre-commit hooks +- [ ] Add comprehensive debugging tools +- [ ] Documentation updates + +### Future Enhancements + +- [ ] Eclipse Theia integration exploration +- [ ] Advanced WebAssembly features +- [ ] Performance optimizations +- [ ] Extended protocol support + +## πŸ“ž Contact & Support + +- **Repository:** [pulseengine/glsp-mcp](https://github.com/pulseengine/glsp-mcp) +- **Issues:** [GitHub Issues](https://github.com/pulseengine/glsp-mcp/issues) +- **Documentation:** See `docs/` directory + +--- + +*This status report is automatically generated and reflects the current state as of the last update.* diff --git a/docs/STATUS-ralf-main.md b/docs/STATUS-ralf-main.md new file mode 100644 index 0000000..37a6428 --- /dev/null +++ b/docs/STATUS-ralf-main.md @@ -0,0 +1,145 @@ +# GLSP-MCP Project Status Report - Ralf GLSP MCP Main Branch + +**Generated on:** September 6, 2025 +**Current Branch:** `ralf-glsp-mcp/main` (detached HEAD) +**Repository:** [pulseengine/glsp-mcp](https://github.com/pulseengine/glsp-mcp) +**Tag:** v0.2.0 + +## πŸ“Š Current Status + +### Repository Health + +- βœ… **Git Status:** Detached HEAD state +- βœ… **Remote Sync:** Up to date with ralf-glsp-mcp/main +- βœ… **Dependencies:** All updated to latest compatible versions +- βœ… **Security:** No vulnerabilities detected + +### Development Environment + +- **Rust:** cargo 1.91.0-nightly (623d53683 2025-08-22) / rustc 1.91.0-nightly (809200ec9 2025-08-24) +- **Node.js:** v22.14.0 +- **NPM:** 10.9.2 + +## πŸ”„ Recent Updates (Last 10 Commits) + +1. **1ddd9a7** - Implement official Tauri Ubuntu 24.04 workaround using Ubuntu 22.04 repos +2. **ba6bb6f** - Create JavaScriptCore GTK 4.0 compatibility symlink for 4.1 +3. **90e77be** - Add both JavaScriptCore GTK 4.0 and 4.1 for compatibility +4. **d9a7384** - Add libjavascriptcoregtk-4.1-dev for WebKit support in Ubuntu 24.04 +5. **4b6e220** - Add libsoup2.4-dev for Tauri compatibility in Ubuntu 24.04 +6. **8fd799c** - Update CI dependencies for Ubuntu 24.04 compatibility +7. **44e96d1** - ci: update CI to use Ubuntu 24.04 to fix GLIBC compatibility +8. **d913bd2** - fix: resolve WASM component loading field name mismatch +9. **c8944eb** - refactor: activate planned features and improve system integration +10. **d97a437** - feat: enhance dialog system with improved UX and effects + +## πŸ“¦ Dependencies Status + +### Rust Dependencies (Updated) + +- **Total Packages:** 94 updated to latest compatible versions +- **Key Updates:** + - `hyper`: 1.6.0 β†’ 1.7.0 + - `tokio-util`: 0.7.15 β†’ 0.7.16 + - `serde_json`: 1.0.142 β†’ 1.0.143 + - `wasm-tools`: 1.236.0 β†’ 1.238.1 + - `clap`: 4.5.42 β†’ 4.5.47 + +### Node.js Dependencies + +- **Security Audit:** βœ… No vulnerabilities found +- **Package Updates:** `concurrently` updated to latest version +- **Total Packages:** 30 packages audited + +## πŸ—οΈ Project Structure + +```bash +glsp-mcp/ +β”œβ”€β”€ composer/ # WebAssembly component composer +β”œβ”€β”€ glsp-mcp-server/ # GLSP MCP server implementation +β”œβ”€β”€ glsp-tauri/ # Tauri desktop application +β”œβ”€β”€ glsp-web-client/ # Web-based GLSP client +β”œβ”€β”€ tasklist_mcp_client/ # MCP client for task management +β”œβ”€β”€ docs/ # Documentation and status reports +β”œβ”€β”€ workspace/ # Development workspace +└── target/ # Build artifacts +``` + +## 🎯 Current Features + +### Core Components + +- **GLSP Integration:** Graphical Language Server Protocol support +- **MCP Protocol:** Model Context Protocol implementation +- **WebAssembly:** Component composition and execution +- **Tauri Desktop:** Cross-platform desktop application +- **Web Client:** Browser-based diagram editor + +### Recent Additions + +- βœ… Ubuntu 24.04 compatibility fixes +- βœ… Tauri Ubuntu 22.04 workaround implementation +- βœ… JavaScriptCore GTK compatibility (4.0/4.1) +- βœ… WebKit support for Ubuntu 24.04 +- βœ… CI pipeline updates for Ubuntu 24.04 +- βœ… WASM component loading fixes +- βœ… Enhanced dialog system with UX improvements + +## πŸ”§ Build & Development + +### Available Commands + +```bash +# Build the project +cargo build + +# Run the MCP server +cargo run --bin server + +# Run the tasklist client +cargo run --bin tasklist_mcp_client + +# Development server +npm run dev +``` + +### Build Targets + +- **Primary:** Linux x86_64 +- **WebAssembly:** wasm32-unknown-unknown +- **Cross-platform:** Tauri (Windows, macOS, Linux) +- **Ubuntu Compatibility:** 22.04 and 24.04 support + +## πŸ“ˆ Performance Metrics + +- **Build Time:** Optimized with incremental compilation +- **Dependencies:** 94 Rust crates, 30+ NPM packages +- **Test Coverage:** Core functionality implemented +- **Security:** Clean security audit results +- **Compatibility:** Ubuntu 24.04 fully supported + +## πŸš€ Next Steps + +### Immediate Priorities + +- [ ] Complete MCP protocol integration +- [ ] Enhance diagram editing capabilities +- [ ] Add comprehensive testing suite +- [ ] Documentation updates + +### Future Enhancements + +- [ ] Eclipse Theia integration exploration +- [ ] Advanced WebAssembly features +- [ ] Performance optimizations +- [ ] Extended protocol support + +## πŸ“ž Contact & Support + +- **Repository:** [pulseengine/glsp-mcp](https://github.com/pulseengine/glsp-mcp) +- **Issues:** [GitHub Issues](https://github.com/pulseengine/glsp-mcp/issues) +- **Documentation:** See `docs/` directory + +--- + +*This status report is automatically generated and reflects the current state as of the last update.* diff --git a/docs/STATUS.md b/docs/STATUS.md new file mode 100644 index 0000000..8db6bdb --- /dev/null +++ b/docs/STATUS.md @@ -0,0 +1,140 @@ +# GLSP-MCP Project Status Report + +**Generated on:** September 6, 2025 +**Current Branch:** `uml_diagram` +**Repository:** [vkanta/glsp-mcp](https://github.com/vkanta/glsp-mcp) + +## πŸ“Š Current Status + +### Repository Health + +- βœ… **Git Status:** Clean working directory +- βœ… **Remote Sync:** Up to date with origin +- βœ… **Dependencies:** All updated to latest compatible versions +- βœ… **Security:** No vulnerabilities detected + +### Development Environment + +- **Rust:** cargo 1.91.0-nightly (623d53683 2025-08-22) / rustc 1.91.0-nightly (809200ec9 2025-08-24) +- **Node.js:** v22.14.0 +- **NPM:** 10.9.2 + +## πŸ”„ Recent Updates (Last 10 Commits) + +1. **470c8fe** - Updated README with embedded screenshot image +2. **0af22df** - Added uml functionality +3. **1c915cd** - Updated README.md +4. **99abebd** - refactore code +5. **37a9f07** - refactore code +6. **3603ebc** - Added edges to diagram +7. **ebf9543** - added external data source +8. **0bef474** - Updated README.md --amend +9. **d689bbe** - Updated README.md --amend +10. **b135ca6** - Updated README.md + +## πŸ“¦ Dependencies Status + +### Rust Dependencies (Updated) + +- **Total Packages:** 94 updated to latest compatible versions +- **Key Updates:** + - `hyper`: 1.6.0 β†’ 1.7.0 + - `tokio-util`: 0.7.15 β†’ 0.7.16 + - `serde_json`: 1.0.142 β†’ 1.0.143 + - `wasm-tools`: 1.236.0 β†’ 1.238.1 + - `clap`: 4.5.42 β†’ 4.5.47 + +### Node.js Dependencies + +- **Security Audit:** βœ… No vulnerabilities found +- **Package Updates:** `concurrently` updated to latest version +- **Total Packages:** 30 packages audited + +## πŸ—οΈ Project Structure + +```bash +glsp-mcp/ +β”œβ”€β”€ composer/ # WebAssembly component composer +β”œβ”€β”€ glsp-mcp-server/ # GLSP MCP server implementation +β”œβ”€β”€ glsp-tauri/ # Tauri desktop application +β”œβ”€β”€ glsp-web-client/ # Web-based GLSP client +β”œβ”€β”€ tasklist_mcp_client/ # MCP client for task management +β”œβ”€β”€ docs/ # Documentation and status reports +β”œβ”€β”€ workspace/ # Development workspace +└── target/ # Build artifacts +``` + +## 🎯 Current Features + +### Core Components + +- **GLSP Integration:** Graphical Language Server Protocol support +- **MCP Protocol:** Model Context Protocol implementation +- **WebAssembly:** Component composition and execution +- **Tauri Desktop:** Cross-platform desktop application +- **Web Client:** Browser-based diagram editor + +### Recent Additions + +- βœ… UML diagram functionality +- βœ… Embedded screenshot support in README +- βœ… External data source integration +- βœ… Diagram edges implementation +- βœ… Code refactoring and optimization + +## πŸ”§ Build & Development + +### Available Commands + +```bash +# Build the project +cargo build + +# Run the MCP server +cargo run --bin server + +# Run the tasklist client +cargo run --bin tasklist_mcp_client + +# Development server +npm run dev +``` + +### Build Targets + +- **Primary:** Linux x86_64 +- **WebAssembly:** wasm32-unknown-unknown +- **Cross-platform:** Tauri (Windows, macOS, Linux) + +## πŸ“ˆ Performance Metrics + +- **Build Time:** Optimized with incremental compilation +- **Dependencies:** 94 Rust crates, 30+ NPM packages +- **Test Coverage:** Core functionality implemented +- **Security:** Clean security audit results + +## πŸš€ Next Steps + +### Immediate Priorities + +- [ ] Complete MCP protocol integration +- [ ] Enhance diagram editing capabilities +- [ ] Add comprehensive testing suite +- [ ] Documentation updates + +### Future Enhancements + +- [ ] Eclipse Theia integration exploration +- [ ] Advanced WebAssembly features +- [ ] Performance optimizations +- [ ] Extended protocol support + +## πŸ“ž Contact & Support + +- **Repository:** [vkanta/glsp-mcp](https://github.com/vkanta/glsp-mcp) +- **Issues:** [GitHub Issues](https://github.com/vkanta/glsp-mcp/issues) +- **Documentation:** See `docs/` directory + +--- + +*This status report is automatically generated and reflects the current state as of the last update.* \ No newline at end of file diff --git a/docs/pictures/Class_diagram.png b/docs/pictures/Class_diagram.png new file mode 100644 index 0000000..1ec91c4 Binary files /dev/null and b/docs/pictures/Class_diagram.png differ diff --git a/glsp-mcp-server/src/backend.rs b/glsp-mcp-server/src/backend.rs index 5d50b80..5b0dcbd 100644 --- a/glsp-mcp-server/src/backend.rs +++ b/glsp-mcp-server/src/backend.rs @@ -1153,6 +1153,57 @@ impl GlspBackend { "required": ["workspace_path"] }), }, + // UML diagram tools + Tool { + name: "add_uml_class".to_string(), + description: "Add a UML class node to a UML diagram".to_string(), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { "type": "string", "description": "ID of the UML diagram" }, + "name": { "type": "string", "description": "Class name" }, + "attributes": { "type": "array", "items": { "type": "string" }, "description": "Class attributes" }, + "methods": { "type": "array", "items": { "type": "string" }, "description": "Class methods" }, + "position": { + "type": "object", + "properties": { + "x": { "type": "number" }, + "y": { "type": "number" } + }, + "required": ["x", "y"], + "description": "Position of the class node" + } + }, + "required": ["diagramId", "name"] + }), + }, + Tool { + name: "remove_uml_class".to_string(), + description: "Remove a UML class node from a diagram".to_string(), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { "type": "string", "description": "ID of the diagram" }, + "classId": { "type": "string", "description": "ID of the class node to remove" } + }, + "required": ["diagramId", "classId"] + }), + }, + Tool { + name: "update_uml_class".to_string(), + description: "Update a UML class node's properties in a diagram".to_string(), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { "type": "string", "description": "ID of the diagram" }, + "classId": { "type": "string", "description": "ID of the class node to update" }, + "name": { "type": "string", "description": "New class name" }, + "attributes": { "type": "array", "items": { "type": "object" }, "description": "Updated attributes" }, + "methods": { "type": "array", "items": { "type": "object" }, "description": "Updated methods" } + }, + "required": ["diagramId", "classId"] + }), + }, ]; Ok(ListToolsResult { @@ -1202,6 +1253,10 @@ impl GlspBackend { self.create_workspace_structure_tool(request.arguments) .await } + // UML tools + "add_uml_class" => self.add_uml_class(request.arguments).await, + "remove_uml_class" => self.remove_uml_class(request.arguments).await, + "update_uml_class" => self.update_uml_class(request.arguments).await, _ => Err(GlspError::NotImplemented(format!( "Tool not implemented: {}", @@ -2970,6 +3025,149 @@ impl GlspBackend { is_error: Some(false), }) } + + async fn add_uml_class( + &self, + args: Option, + ) -> std::result::Result { + use crate::model::{ModelElement, ElementType, Bounds}; + let args = args.ok_or_else(|| GlspError::ToolExecution("Missing arguments".to_string()))?; + let diagram_id = args["diagramId"].as_str().ok_or_else(|| GlspError::ToolExecution("Missing diagramId".to_string()))?; + let name = args["name"].as_str().ok_or_else(|| GlspError::ToolExecution("Missing class name".to_string()))?; + + // Accept attributes/methods as array of objects or strings, convert to array of objects + let attributes = args.get("attributes").and_then(|v| v.as_array()).map(|arr| { + arr.iter().map(|item| { + if let Some(s) = item.as_str() { + serde_json::json!({"name": s, "type": "", "visibility": "public"}) + } else if let Some(obj) = item.as_object() { + serde_json::Value::Object(obj.clone()) + } else { + serde_json::json!({"name": "attribute", "type": "", "visibility": "public"}) + } + }).collect::>() + }).unwrap_or_default(); + + let methods = args.get("methods").and_then(|v| v.as_array()).map(|arr| { + arr.iter().map(|item| { + if let Some(s) = item.as_str() { + serde_json::json!({"name": s, "returnType": "", "visibility": "public"}) + } else if let Some(obj) = item.as_object() { + serde_json::Value::Object(obj.clone()) + } else { + serde_json::json!({"name": "method", "returnType": "", "visibility": "public"}) + } + }).collect::>() + }).unwrap_or_default(); + + let (x, y) = if let Some(pos) = args.get("position") { + let x = pos.get("x").and_then(|v| v.as_f64()).unwrap_or(100.0); + let y = pos.get("y").and_then(|v| v.as_f64()).unwrap_or(100.0); + (x, y) + } else { + (100.0, 100.0) + }; + + let class_id = uuid::Uuid::new_v4().to_string(); + let mut properties = std::collections::HashMap::new(); + properties.insert("name".to_string(), serde_json::Value::String(name.to_string())); + properties.insert("attributes".to_string(), serde_json::Value::Array(attributes)); + properties.insert("methods".to_string(), serde_json::Value::Array(methods)); + + let class_node = ModelElement { + id: class_id.clone(), + element_type: ElementType::Custom("uml_class".to_string()), + children: None, + bounds: Some(Bounds { x, y, width: 120.0, height: 80.0 }), + layout_options: None, + properties, + label: Some(name.to_string()), + source_id: None, + target_id: None, + route: None, + visible: true, + z_index: Some(1), + style: std::collections::HashMap::new(), + }; + + let mut models = self.models.lock().await; + let diagram = models.get_mut(diagram_id).ok_or_else(|| GlspError::ToolExecution("Diagram not found".to_string()))?; + diagram.elements.insert(class_id.clone(), class_node); + if let Some(root) = diagram.elements.get_mut(&diagram.root.id) { + if let Some(children) = &mut root.children { + children.push(class_id.clone()); + } + } + + Ok(CallToolResult { + content: vec![Content::text(format!("Added UML class '{}' with ID: {}", name, class_id))], + is_error: Some(false), + }) + } + + async fn remove_uml_class( + &self, + args: Option, + ) -> std::result::Result { + let args = args.ok_or_else(|| GlspError::ToolExecution("Missing arguments".to_string()))?; + let diagram_id = args["diagramId"].as_str().ok_or_else(|| GlspError::ToolExecution("Missing diagramId".to_string()))?; + let class_id = args["classId"].as_str().ok_or_else(|| GlspError::ToolExecution("Missing classId".to_string()))?; + + let mut models = self.models.lock().await; + let diagram = models.get_mut(diagram_id).ok_or_else(|| GlspError::ToolExecution("Diagram not found".to_string()))?; + + if diagram.elements.remove(class_id).is_some() { + // Remove from root's children + if let Some(root) = diagram.elements.get_mut(&diagram.root.id) { + if let Some(children) = &mut root.children { + children.retain(|id| id != class_id); + } + } + Ok(CallToolResult { + content: vec![Content::text(format!("Removed UML class node with ID: {}", class_id))], + is_error: Some(false), + }) + } else { + Ok(CallToolResult { + content: vec![Content::text(format!("Class node with ID: {} not found", class_id))], + is_error: Some(true), + }) + } + } + + async fn update_uml_class( + &self, + args: Option, + ) -> std::result::Result { + let args = args.ok_or_else(|| GlspError::ToolExecution("Missing arguments".to_string()))?; + let diagram_id = args["diagramId"].as_str().ok_or_else(|| GlspError::ToolExecution("Missing diagramId".to_string()))?; + let class_id = args["classId"].as_str().ok_or_else(|| GlspError::ToolExecution("Missing classId".to_string()))?; + + let mut models = self.models.lock().await; + let diagram = models.get_mut(diagram_id).ok_or_else(|| GlspError::ToolExecution("Diagram not found".to_string()))?; + + if let Some(class_node) = diagram.elements.get_mut(class_id) { + if let Some(name) = args.get("name").and_then(|v| v.as_str()) { + class_node.label = Some(name.to_string()); + class_node.properties.insert("name".to_string(), serde_json::Value::String(name.to_string())); + } + if let Some(attributes) = args.get("attributes").and_then(|v| v.as_array()) { + class_node.properties.insert("attributes".to_string(), serde_json::Value::Array(attributes.clone())); + } + if let Some(methods) = args.get("methods").and_then(|v| v.as_array()) { + class_node.properties.insert("methods".to_string(), serde_json::Value::Array(methods.clone())); + } + Ok(CallToolResult { + content: vec![Content::text(format!("Updated UML class node with ID: {}", class_id))], + is_error: Some(false), + }) + } else { + Ok(CallToolResult { + content: vec![Content::text(format!("Class node with ID: {} not found", class_id))], + is_error: Some(true), + }) + } + } } /// Implementation of McpBackend trait for framework integration diff --git a/glsp-mcp-server/src/mcp/tools.rs b/glsp-mcp-server/src/mcp/tools.rs index 639d1bf..0339663 100644 --- a/glsp-mcp-server/src/mcp/tools.rs +++ b/glsp-mcp-server/src/mcp/tools.rs @@ -86,6 +86,57 @@ impl DiagramTools { } pub fn get_available_tools(&self) -> Vec { + let mut tools = Vec::new(); + tools.push(Tool { + name: "remove_uml_class".to_string(), + description: Some("Remove a UML class node from a diagram".to_string()), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { "type": "string", "description": "ID of the diagram" }, + "classId": { "type": "string", "description": "ID of the class node to remove" } + }, + "required": ["diagramId", "classId"] + }), + }); + tools.push(Tool { + name: "update_uml_class".to_string(), + description: Some("Update a UML class node's properties in a diagram".to_string()), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { "type": "string", "description": "ID of the diagram" }, + "classId": { "type": "string", "description": "ID of the class node to update" }, + "name": { "type": "string", "description": "New class name" }, + "attributes": { "type": "array", "items": { "type": "object" }, "description": "Updated attributes" }, + "methods": { "type": "array", "items": { "type": "object" }, "description": "Updated methods" } + }, + "required": ["diagramId", "classId"] + }), + }); + tools.push(Tool { + name: "add_uml_class".to_string(), + description: Some("Add a UML class node to a UML diagram".to_string()), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { "type": "string", "description": "ID of the UML diagram" }, + "name": { "type": "string", "description": "Class name" }, + "attributes": { "type": "array", "items": { "type": "string" }, "description": "Class attributes" }, + "methods": { "type": "array", "items": { "type": "string" }, "description": "Class methods" }, + "position": { + "type": "object", + "properties": { + "x": { "type": "number" }, + "y": { "type": "number" } + }, + "required": ["x", "y"], + "description": "Position of the class node" + } + }, + "required": ["diagramId", "name"] + }), + }); let mut tools = vec![ Tool { name: "create_diagram".to_string(), @@ -105,6 +156,34 @@ impl DiagramTools { "required": ["diagramType"] }), }, + Tool { + name: "delete_diagram".to_string(), + description: Some("Remove an existing diagram".to_string()), + input_schema: json!({ + "type": "object", + "properties": { + "diagramId": { + "type": "string", + "description": "ID of the diagram to remove" + } + }, + "required": ["diagramId"] + }), + }, + Tool { + name: "create_uml_diagram".to_string(), + description: Some("Create a new UML diagram with a default UML class node".to_string()), + input_schema: json!({ + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name for the new UML diagram" + } + }, + "required": [] + }), + }, Tool { name: "delete_diagram".to_string(), description: Some("Delete a diagram and its associated files".to_string()), @@ -1153,8 +1232,20 @@ impl DiagramTools { } pub async fn call_tool(&mut self, params: CallToolParams) -> Result { + if params.name == "remove_uml_class" { + return self.remove_uml_class(params.arguments).await; + } + if params.name == "update_uml_class" { + return self.update_uml_class(params.arguments).await; + } + if params.name == "add_uml_class" { + return self.add_uml_class(params.arguments).await; + } + match params.name.as_str() { "create_diagram" => self.create_diagram(params.arguments).await, + "delete_diagram" => self.delete_diagram(params.arguments).await, + "create_uml_diagram" => self.create_uml_diagram(params.arguments).await, "create_node" => self.create_node(params.arguments).await, "create_edge" => self.create_edge(params.arguments).await, "delete_element" => self.delete_element(params.arguments).await, @@ -1181,50 +1272,155 @@ impl DiagramTools { // "get_execution_result" => self.get_execution_result(params.arguments).await, // Converted to resource // "list_wasm_executions" => self.list_wasm_executions().await, // Converted to resource "cancel_execution" => self.cancel_execution(params.arguments).await, - // Sensor data tools - // "query_sensor_data" => self.query_sensor_data(params.arguments).await, // Converted to resource - // "list_sensors" => self.list_sensors().await, // Converted to resource - // "get_sensor_metadata" => self.get_sensor_metadata(params.arguments).await, // Converted to resource - // "get_sensor_statistics" => self.get_sensor_statistics(params.arguments).await, // Converted to resource - // "get_sensor_time_range" => self.get_sensor_time_range(params.arguments).await, // Converted to resource - // "list_sensor_datasets" => self.list_sensor_datasets(params.arguments).await, // Converted to resource - // "get_dataset_info" => self.get_dataset_info(params.arguments).await, // Converted to resource - "set_active_dataset" => self.set_active_dataset(params.arguments).await, // This modifies state, keep as tool - // "visualize_sensor_data" => self.visualize_sensor_data(params.arguments).await, // Converted to resource - // "detect_sensor_gaps" => self.detect_sensor_gaps(params.arguments).await, // Converted to resource - // Component upload tools - "upload_wasm_component" => self.upload_wasm_component(params.arguments).await, - "validate_wasm_component" => self.validate_wasm_component(params.arguments).await, - // "list_uploaded_components" => self.list_uploaded_components(params.arguments).await, // Converted to resource - "delete_uploaded_component" => self.delete_uploaded_component(params.arguments).await, - // Component group tools - "create_component_group" => self.create_component_group(params.arguments).await, - "update_component_group" => self.update_component_group(params.arguments).await, - "get_component_group_interfaces" => { - self.get_component_group_interfaces(params.arguments).await + _ => Err(anyhow::anyhow!(format!("Unknown tool: {}", params.name))) + } + } + + pub async fn remove_uml_class(&mut self, args: Option) -> Result { + let args = args.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?; + let diagram_id = args["diagramId"].as_str().ok_or_else(|| anyhow::anyhow!("Missing diagramId"))?; + let class_id = args["classId"].as_str().ok_or_else(|| anyhow::anyhow!("Missing classId"))?; + let diagram = self.models.get_mut(diagram_id).ok_or_else(|| anyhow::anyhow!("Diagram not found"))?; + if diagram.elements.remove(class_id).is_some() { + // Remove from root's children + if let Some(root) = diagram.elements.get_mut(&diagram.root.id) { + if let Some(children) = &mut root.children { + children.retain(|id| id != class_id); + } } - "delete_component_group" => self.delete_component_group(params.arguments).await, - "generate_bazel_composition" => self.generate_bazel_composition(params.arguments).await, - "validate_component_group" => self.validate_component_group(params.arguments).await, - "list_component_groups" => self.list_component_groups(params.arguments).await, - "deploy_component_group" => self.deploy_component_group(params.arguments).await, - _ => Ok(CallToolResult { + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Removed UML class node with ID: {}", class_id), + }], + is_error: None, + }) + } else { + Ok(CallToolResult { content: vec![TextContent { content_type: "text".to_string(), - text: format!("Unknown tool: {}", params.name), + text: format!("Class node with ID: {} not found", class_id), }], is_error: Some(true), - }), + }) + } + } + + pub async fn update_uml_class(&mut self, args: Option) -> Result { + let args = args.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?; + let diagram_id = args["diagramId"].as_str().ok_or_else(|| anyhow::anyhow!("Missing diagramId"))?; + let class_id = args["classId"].as_str().ok_or_else(|| anyhow::anyhow!("Missing classId"))?; + let diagram = self.models.get_mut(diagram_id).ok_or_else(|| anyhow::anyhow!("Diagram not found"))?; + if let Some(class_node) = diagram.elements.get_mut(class_id) { + if let Some(name) = args.get("name").and_then(|v| v.as_str()) { + class_node.label = Some(name.to_string()); + class_node.properties.insert("name".to_string(), serde_json::Value::String(name.to_string())); + } + if let Some(attributes) = args.get("attributes").and_then(|v| v.as_array()) { + class_node.properties.insert("attributes".to_string(), serde_json::Value::Array(attributes.clone())); + } + if let Some(methods) = args.get("methods").and_then(|v| v.as_array()) { + class_node.properties.insert("methods".to_string(), serde_json::Value::Array(methods.clone())); + } + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Updated UML class node with ID: {}", class_id), + }], + is_error: None, + }) + } else { + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Class node with ID: {} not found", class_id), + }], + is_error: Some(true), + }) } } + pub async fn add_uml_class(&mut self, args: Option) -> Result { + use crate::model::{ModelElement, ElementType, Bounds}; + let args = args.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?; + let diagram_id = args["diagramId"].as_str().ok_or_else(|| anyhow::anyhow!("Missing diagramId"))?; + let name = args["name"].as_str().ok_or_else(|| anyhow::anyhow!("Missing class name"))?; + // Accept attributes/methods as array of objects or strings, convert to array of objects + let attributes = args.get("attributes").and_then(|v| v.as_array()).map(|arr| { + arr.iter().map(|item| { + if let Some(s) = item.as_str() { + serde_json::json!({"name": s, "type": "", "visibility": "public"}) + } else if let Some(obj) = item.as_object() { + serde_json::Value::Object(obj.clone()) + } else { + serde_json::json!({"name": "attribute", "type": "", "visibility": "public"}) + } + }).collect::>() + }).unwrap_or_default(); + let methods = args.get("methods").and_then(|v| v.as_array()).map(|arr| { + arr.iter().map(|item| { + if let Some(s) = item.as_str() { + serde_json::json!({"name": s, "returnType": "", "visibility": "public"}) + } else if let Some(obj) = item.as_object() { + serde_json::Value::Object(obj.clone()) + } else { + serde_json::json!({"name": "method", "returnType": "", "visibility": "public"}) + } + }).collect::>() + }).unwrap_or_default(); + let (x, y) = if let Some(pos) = args.get("position") { + let x = pos.get("x").and_then(|v| v.as_f64()).unwrap_or(100.0); + let y = pos.get("y").and_then(|v| v.as_f64()).unwrap_or(100.0); + (x, y) + } else { + (100.0, 100.0) + }; + let class_id = uuid::Uuid::new_v4().to_string(); + let mut properties = std::collections::HashMap::new(); + properties.insert("name".to_string(), serde_json::Value::String(name.to_string())); + properties.insert("attributes".to_string(), serde_json::Value::Array(attributes)); + properties.insert("methods".to_string(), serde_json::Value::Array(methods)); + let class_node = ModelElement { + id: class_id.clone(), + element_type: ElementType::Custom("uml_class".to_string()), + children: None, + bounds: Some(Bounds { x, y, width: 120.0, height: 80.0 }), + layout_options: None, + properties, + label: Some(name.to_string()), + source_id: None, + target_id: None, + route: None, + visible: true, + z_index: Some(1), + style: std::collections::HashMap::new(), + }; + let diagram = self.models.get_mut(diagram_id).ok_or_else(|| anyhow::anyhow!("Diagram not found"))?; + diagram.elements.insert(class_id.clone(), class_node); + if let Some(root) = diagram.elements.get_mut(&diagram.root.id) { + if let Some(children) = &mut root.children { + children.push(class_id.clone()); + } + } + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Added UML class '{}' with ID: {}", name, class_id), + }], + is_error: None, + }) + } + async fn create_diagram(&mut self, args: Option) -> Result { let args = args.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?; let diagram_type = args["diagramType"] .as_str() .ok_or_else(|| anyhow::anyhow!("Missing diagramType"))?; - let diagram = DiagramModel::new(diagram_type); + let mut diagram = DiagramModel::new(diagram_type); + if let Some(name) = args.get("name").and_then(|v| v.as_str()) { + diagram.name = name.to_string(); + } let diagram_id = diagram.id.clone(); self.models.insert(diagram_id.clone(), diagram); @@ -1237,6 +1433,72 @@ impl DiagramTools { }) } + async fn delete_diagram(&mut self, args: Option) -> Result { + let args = args.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?; + let diagram_id = args["diagramId"] + .as_str() + .ok_or_else(|| anyhow::anyhow!("Missing diagramId"))?; + + if self.models.remove(diagram_id).is_some() { + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Removed diagram with ID: {diagram_id}"), + }], + is_error: None, + }) + } else { + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Diagram with ID: {diagram_id} not found"), + }], + is_error: Some(true), + }) + } + } + + async fn create_uml_diagram(&mut self, args: Option) -> Result { + use crate::model::{ModelElement, ElementType, Position}; + let mut diagram = DiagramModel::new("uml"); + if let Some(name) = args.as_ref().and_then(|v| v.get("name")).and_then(|v| v.as_str()) { + diagram.name = name.to_string(); + } + // Add a default UML class node + let class_id = uuid::Uuid::new_v4().to_string(); + let class_node = ModelElement { + id: class_id.clone(), + element_type: ElementType::Custom("uml_class".to_string()), + children: None, + bounds: Some(crate::model::Bounds { x: 100.0, y: 100.0, width: 120.0, height: 80.0 }), + layout_options: None, + properties: [ ("name".to_string(), serde_json::Value::String("Class1".to_string())) ].iter().cloned().collect(), + label: Some("Class1".to_string()), + source_id: None, + target_id: None, + route: None, + visible: true, + z_index: Some(1), + style: std::collections::HashMap::new(), + }; + diagram.elements.insert(class_id.clone(), class_node); + // Add to root's children + if let Some(root) = diagram.elements.get_mut(&diagram.root.id) { + if let Some(children) = &mut root.children { + children.push(class_id); + } + } + let diagram_id = diagram.id.clone(); + self.models.insert(diagram_id.clone(), diagram); + Ok(CallToolResult { + content: vec![TextContent { + content_type: "text".to_string(), + text: format!("Created UML diagram with ID: {diagram_id} and default class node."), + }], + is_error: None, + }) + } + async fn create_node(&mut self, args: Option) -> Result { let args = args.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?; let diagram_id = args["diagramId"] diff --git a/glsp-web-client/index.html b/glsp-web-client/index.html index c2df635..1959f7d 100644 --- a/glsp-web-client/index.html +++ b/glsp-web-client/index.html @@ -1,317 +1,317 @@ - - - - - WASM Component Designer - - - - - - - - - - - - - - -