diff --git a/APP_LAUNCHER_INTEGRATION.md b/APP_LAUNCHER_INTEGRATION.md
deleted file mode 100644
index b4901c1a8..000000000
--- a/APP_LAUNCHER_INTEGRATION.md
+++ /dev/null
@@ -1,194 +0,0 @@
-# App Launcher Integration Guide
-
-## Overview
-
-The `apps-manifest.json` file provides a complete mapping between Cargo.toml features and user-friendly app descriptions for the botui app launcher.
-
-## File Location
-
-```
-botserver/apps-manifest.json
-```
-
-## Structure
-
-### Categories
-
-Apps are organized into 8 categories:
-
-1. **Communication** (π¬) - Chat, Mail, Meet, WhatsApp, Telegram, etc.
-2. **Productivity** (β‘) - Tasks, Calendar, Project, Goals, Workspaces, etc.
-3. **Documents** (π) - Drive, Docs, Sheet, Slides, Paper
-4. **Media** (π¬) - Video, Player, Canvas
-5. **Learning** (π) - Learn, Research, Sources
-6. **Analytics** (π) - Analytics, Dashboards, Monitoring
-7. **Development** (βοΈ) - Automation, Designer, Editor
-8. **Administration** (π) - Attendant, Security, Settings, Directory
-9. **Core** (ποΈ) - Cache, LLM, Vector DB
-
-### App Schema
-
-Each app includes:
-
-```json
-{
- "id": "tasks",
- "name": "Tasks",
- "description": "Task management with scheduling",
- "feature": "tasks",
- "icon": "β
",
- "enabled_by_default": true,
- "dependencies": ["automation", "drive", "monitoring"]
-}
-```
-
-### Bundles
-
-Pre-configured feature sets:
-
-- **minimal** - Essential infrastructure (chat, automation, drive, cache)
-- **lightweight** - Basic productivity (chat, drive, tasks, people)
-- **full** - Complete feature set
-- **communications** - All communication apps
-- **productivity** - Productivity suite
-- **documents** - Document suite
-
-## Integration with botui
-
-### Reading the Manifest
-
-```javascript
-// In botui/ui/suite/js/app-launcher.js
-fetch('/api/apps/manifest')
- .then(res => res.json())
- .then(manifest => {
- renderAppLauncher(manifest);
- });
-```
-
-### Rendering Apps
-
-```javascript
-function renderAppLauncher(manifest) {
- const categories = manifest.categories;
-
- for (const [categoryId, category] of Object.entries(categories)) {
- const categoryEl = createCategory(category);
-
- category.apps.forEach(app => {
- const appCard = createAppCard(app);
- categoryEl.appendChild(appCard);
- });
- }
-}
-```
-
-### App Card Template
-
-```html
-
-
${app.icon}
-
${app.name}
-
${app.description}
-
-
-
- ${app.dependencies.length > 0 ?
- `
Requires: ${app.dependencies.join(', ')}
`
- : ''}
-
-```
-
-## Backend API Endpoint
-
-Add to `botserver/src/main.rs`:
-
-```rust
-async fn get_apps_manifest() -> Json {
- let manifest = include_str!("../apps-manifest.json");
- let value: serde_json::Value = serde_json::from_str(manifest)
- .expect("Invalid apps-manifest.json");
- Json(value)
-}
-
-// In router configuration:
-api_router = api_router.route("/api/apps/manifest", get(get_apps_manifest));
-```
-
-## Compilation Testing
-
-Use the `test_apps.sh` script to verify all apps compile:
-
-```bash
-cd /home/rodriguez/src/gb
-./test_apps.sh
-```
-
-This will:
-1. Test each app feature individually
-2. Report which apps pass/fail compilation
-3. Provide a summary of results
-
-## Core Dependencies
-
-These apps cannot be disabled (marked with `core_dependency: true`):
-
-- **automation** - Required for .gbot script execution
-- **drive** - S3 storage used throughout
-- **cache** - Redis integrated into sessions
-
-## Feature Bundling
-
-When a user enables an app, all its dependencies are automatically enabled:
-
-- Enable `tasks` β Automatically enables `automation`, `drive`, `monitoring`
-- Enable `mail` β Automatically enables `mail_core`, `drive`
-- Enable `research` β Automatically enables `llm`, `vectordb`
-
-## Syncing with Cargo.toml
-
-When adding new features to `Cargo.toml`:
-
-1. Add the feature definition in `Cargo.toml`
-2. Add the app entry in `apps-manifest.json`
-3. Update the app launcher UI in botui
-4. Run `./test_apps.sh` to verify compilation
-5. Commit both files together
-
-## Example: Adding a New App
-
-### 1. In Cargo.toml
-
-```toml
-[features]
-myapp = ["dep:myapp-crate", "drive"]
-```
-
-### 2. In apps-manifest.json
-
-```json
-{
- "id": "myapp",
- "name": "My App",
- "description": "My awesome app",
- "feature": "myapp",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": ["drive"]
-}
-```
-
-### 3. Test
-
-```bash
-cargo check -p botserver --no-default-features --features myapp
-```
-
-## Notes
-
-- Icons use emoji for cross-platform compatibility
-- Dependencies are automatically resolved by Cargo
-- Core dependencies are shown but cannot be toggled off
-- The manifest version matches botserver version
diff --git a/Cargo.toml b/Cargo.toml
index b48ef2a9d..5edb2fe3b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,8 @@ features = ["database", "i18n"]
default = ["chat", "automation", "drive", "tasks", "cache", "directory"]
# ===== CORE INFRASTRUCTURE (Can be used standalone) =====
-automation = ["dep:rhai", "dep:cron"]
+scripting = ["dep:rhai"]
+automation = ["scripting", "dep:cron"]
drive = ["dep:aws-config", "dep:aws-sdk-s3", "dep:aws-smithy-async", "dep:pdf-extract"]
cache = ["dep:redis"]
directory = []
@@ -25,10 +26,6 @@ people = ["automation", "drive", "cache"]
mail = ["automation", "drive", "cache", "dep:lettre", "dep:mailparse", "dep:imap", "dep:native-tls"]
meet = ["automation", "drive", "cache", "dep:livekit"]
social = ["automation", "drive", "cache"]
-whatsapp = ["automation", "drive", "cache"]
-telegram = ["automation", "drive", "cache"]
-instagram = ["automation", "drive", "cache"]
-msteams = ["automation", "drive", "cache"]
# Productivity
calendar = ["automation", "drive", "cache"]
@@ -41,7 +38,7 @@ billing = ["automation", "drive", "cache"]
# Documents
docs = ["automation", "drive", "cache", "docx-rs", "ooxmlsdk"]
-sheet = ["automation", "drive", "cache", "calamine", "spreadsheet-ods"]
+sheet = ["automation", "drive", "cache", "calamine", "spreadsheet-ods", "dep:rust_xlsxwriter", "dep:umya-spreadsheet"]
slides = ["automation", "drive", "cache", "ooxmlsdk"]
paper = ["automation", "drive", "cache"]
@@ -69,6 +66,10 @@ attendant = ["automation", "drive", "cache"]
security = ["automation", "drive", "cache"]
settings = ["automation", "drive", "cache"]
+whatsapp = ["automation", "drive", "cache"]
+telegram = ["automation", "drive", "cache"]
+instagram = ["automation", "drive", "cache"]
+msteams = ["automation", "drive", "cache"]
# Core Tech
llm = ["automation", "drive", "cache"]
vectordb = ["automation", "drive", "cache", "dep:qdrant-client"]
@@ -163,9 +164,11 @@ qdrant-client = { workspace = true, optional = true }
# Document Processing
docx-rs = { workspace = true, optional = true }
-ooxmlsdk = { workspace = true, optional = true }
+ooxmlsdk = { workspace = true, optional = true, features = ["parts"] }
calamine = { workspace = true, optional = true }
spreadsheet-ods = { workspace = true, optional = true }
+rust_xlsxwriter = { workspace = true, optional = true }
+umya-spreadsheet = { workspace = true, optional = true }
# File Storage & Drive (drive feature)
aws-config = { workspace = true, features = ["behavior-version-latest", "rt-tokio", "rustls"], optional = true }
diff --git a/DEPENDENCY_FIX_PLAN.md b/DEPENDENCY_FIX_PLAN.md
deleted file mode 100644
index 963b7f7b4..000000000
--- a/DEPENDENCY_FIX_PLAN.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Professional Dependency & Feature Architecture Plan
-
-## Objective
-Create a robust, "ease-of-selection" feature architecture where enabling a high-level **App** (e.g., `tasks`) automatically enables all required **Capabilities** (e.g., `drive`, `automation`). Simultaneously ensure the codebase compiles cleanly in a **Minimal** state (no default features).
-
-## Current Status: β
MINIMAL BUILD WORKING
-
-### Completed Work
-β
**Cargo.toml restructuring** - Feature bundling implemented
-β
**AppState guards** - Conditional fields for `drive`, `cache`, `tasks`
-β
**main.rs guards** - Initialization logic properly guarded
-β
**SessionManager guards** - Redis usage conditionally compiled
-β
**bootstrap guards** - S3/Drive operations feature-gated
-β
**compiler guards** - SET SCHEDULE conditionally compiled
-β
**Task/NewTask exports** - Properly guarded in shared/mod.rs
-β
**Minimal build compiles** - `cargo check -p botserver --no-default-features --features minimal` β
SUCCESS
-
-### Architecture Decision Made
-
-**Accepted Core Dependencies:**
-- **`automation`** (Rhai scripting) - Required for .gbot script execution (100+ files depend on it)
-- **`drive`** (S3 storage) - Used in 80+ places throughout codebase
-- **`cache`** (Redis) - Integrated into session management and state
-
-**Minimal Feature Set:**
-```toml
-minimal = ["chat", "automation", "drive", "cache"]
-```
-
-This provides a functional bot with:
-- Chat capabilities
-- Script execution (.gbot files)
-- File storage (S3)
-- Session caching (Redis)
-
-## Part 1: Feature Architecture (Cargo.toml) β
-
-**Status: COMPLETE**
-
-We successfully restructured `Cargo.toml` using a **Bundle Pattern**:
-- User selects **Apps** β Apps select **Capabilities** β Capabilities select **Dependencies**
-
-### Implemented Hierarchy
-
-#### User-Facing Apps (The Menu)
-* **`tasks`** β includes `automation`, `drive`, `monitoring`
-* **`drive`** β includes `storage_core`, `pdf`
-* **`chat`** β includes (base functionality)
-* **`mail`** β includes `mail_core`, `drive`
-
-#### Core Capabilities (Internal Bundles)
-* `automation_core` β `rhai`, `cron`
-* `storage_core` β `aws-sdk-s3`, `aws-config`, `aws-smithy-async`
-* `cache_core` β `redis`
-* `mail_core` β `lettre`, `mailparse`, `imap`, `native-tls`
-* `realtime_core` β `livekit`
-* `pdf_core` β `pdf-extract`
-
-## Part 2: Codebase Compilation Fixes β
-
-### Completed Guards
-
-1. β
**`AppState` Struct** (`src/core/shared/state.rs`)
- * Fields `s3_client`, `drive`, `redis`, `task_engine`, `task_scheduler` are guarded
-
-2. β
**`main.rs` Initialization**
- * S3 client creation guarded with `#[cfg(feature = "drive")]`
- * Redis client creation guarded with `#[cfg(feature = "cache")]`
- * Task engine/scheduler guarded with `#[cfg(feature = "tasks")]`
-
-3. β
**`bootstrap/mod.rs` Logic**
- * `get_drive_client()` guarded with `#[cfg(feature = "drive")]`
- * `upload_templates_to_drive()` has both feature-enabled and disabled versions
-
-4. β
**`SessionManager`** (`src/core/session/mod.rs`)
- * Redis imports and usage properly guarded with `#[cfg(feature = "cache")]`
-
-5. β
**`compiler/mod.rs`**
- * `execute_set_schedule` import and usage guarded with `#[cfg(feature = "tasks")]`
- * Graceful degradation when tasks feature is disabled
-
-6. β
**`shared/mod.rs`**
- * `Task` and `NewTask` types properly exported with `#[cfg(feature = "tasks")]`
- * Separate pub use statements for conditional compilation
-
-## Verification Results
-
-### β
Minimal Build
-```bash
-cargo check -p botserver --no-default-features --features minimal
-# Result: SUCCESS β
(Exit code: 0)
-```
-
-### Feature Bundle Test
-```bash
-# Test tasks bundle (should include automation, drive, monitoring)
-cargo check -p botserver --no-default-features --features tasks
-# Expected: SUCCESS (includes all dependencies)
-```
-
-## Success Criteria β
-
-β
**ACHIEVED**:
-- `cargo check --no-default-features --features minimal` compiles successfully β
-- Feature bundles work as expected (enabling `tasks` enables `automation`, `drive`, `monitoring`)
-- All direct dependencies are maintained and secure
-- GTK3 transitive warnings are documented as accepted risk
-- Clippy warnings in botserver eliminated
-
-## Summary
-
-The feature bundling architecture is **successfully implemented** and the minimal build is **working**.
-
-**Key Achievements:**
-1. β
Feature bundling pattern allows easy selection (e.g., `tasks` β `automation` + `drive` + `monitoring`)
-2. β
Minimal build compiles with core infrastructure (`chat` + `automation` + `drive` + `cache`)
-3. β
Conditional compilation guards properly applied throughout codebase
-4. β
No compilation warnings in botserver
-
-**Accepted Trade-offs:**
-- `automation` (Rhai) is a core dependency - too deeply integrated to make optional
-- `drive` (S3) is a core dependency - used throughout for file storage
-- `cache` (Redis) is a core dependency - integrated into session management
-
-This provides a solid foundation for feature selection while maintaining a working minimal build.
diff --git a/TASKS.md b/TASKS.md
deleted file mode 100644
index dff15f8db..000000000
--- a/TASKS.md
+++ /dev/null
@@ -1,290 +0,0 @@
-# Cargo Audit Migration Strategy - Task Breakdown
-
-## Project Context
-**Tauri Desktop Application** using GTK3 bindings for Linux support with 1143 total dependencies.
-
----
-
-## CRITICAL: 1 Vulnerability (Fix Immediately)
-
-### Task 1.1: Fix idna Punycode Vulnerability β οΈ HIGH PRIORITY
-**Issue**: RUSTSEC-2024-0421 - Accepts invalid Punycode labels
-**Status**: β
FIXED (Updated validator to 0.20)
-
-### Task 2.1: Replace atty (Used by clap 2.34.0)
-**Issue**: RUSTSEC-2024-0375 + RUSTSEC-2021-0145 (unmaintained + unsound)
-**Status**: β
FIXED (Replaced `ksni` with `tray-icon`)
-
-### Task 2.2: Replace ansi_term (Used by clap 2.34.0)
-**Issue**: RUSTSEC-2021-0139 (unmaintained)
-**Status**: β
FIXED (Replaced `ksni` with `tray-icon`)
-
-### Task 2.3: Replace rustls-pemfile
-**Issue**: RUSTSEC-2025-0134 (unmaintained)
-**Status**: β
FIXED (Updated axum-server to 0.8 and qdrant-client to 1.16)
-
-### Task 2.4: Fix aws-smithy-runtime (Yanked Version)
-**Issue**: Version 1.9.6 was yanked
-**Status**: β
FIXED (Updated aws-sdk-s3 to 1.120.0)
-
-### Task 2.5: Replace fxhash
-**Issue**: RUSTSEC-2025-0057 (unmaintained)
-**Current**: `fxhash 0.2.1`
-**Used by**: `selectors 0.24.0` β `kuchikiki` (speedreader fork) β Tauri
-**Status**: β³ PENDING (Wait for upstream Tauri update)
-
-### Task 2.6: Replace instant
-**Issue**: RUSTSEC-2024-0384 (unmaintained)
-**Status**: β
FIXED (Updated rhai)
-
-### Task 2.7: Replace lru (Unsound Iterator)
-**Issue**: RUSTSEC-2026-0002 (unsound - violates Stacked Borrows)
-**Status**: β
FIXED (Updated ratatui to 0.30 and aws-sdk-s3 to 1.120.0)
-
----
-
-## MEDIUM PRIORITY: Tauri/GTK Stack (Major Effort)
-
-### Task 3.1: Evaluate GTK3 β Tauri Pure Approach
-**Issue**: All GTK3 crates unmaintained (12 crates total)
-**Current**: Using Tauri with GTK3 Linux backend
-
-**Strategic Question**: Do you actually need GTK3?
-
-**Investigation Items**:
-- [ ] Audit what GTK3 features you're using:
- - System tray? (ksni 0.2.2 uses it)
- - Native file dialogs? (rfd 0.15.4)
- - Native menus? (muda 0.17.1)
- - WebView? (wry uses webkit2gtk)
-- [ ] Check if Tauri v2 can work without GTK3 on Linux
-- [ ] Test if removing `ksni` and using Tauri's built-in tray works
-
-**Decision Point**:
-- **If GTK3 is only for tray/dialogs**: Migrate to pure Tauri approach
-- **If GTK3 is deeply integrated**: Plan GTK4 migration
-
-**Estimated effort**: 4-8 hours investigation
-
----
-
-### Task 3.2: Option A - Migrate to Tauri Pure (Recommended)
-**If Task 3.1 shows GTK3 isn't essential**
-
-**Action Items**:
-- [ ] Replace `ksni` with Tauri's `tauri-plugin-tray` or `tray-icon`
-- [ ] Remove direct GTK dependencies from Cargo.toml
-- [ ] Update Tauri config to use modern Linux backend
-- [ ] Test on: Ubuntu 22.04+, Fedora, Arch
-- [ ] Verify all system integrations work
-
-**Benefits**:
-- Removes 12 unmaintained crates
-- Lighter dependency tree
-- Better cross-platform consistency
-
-**Estimated effort**: 1-2 days
-
----
-
-### Task 3.3: Option B - Migrate to GTK4 (If GTK Required)
-**If Task 3.1 shows GTK3 is essential**
-
-**Action Items**:
-- [ ] Create migration branch
-- [ ] Update Cargo.toml GTK dependencies:
- ```toml
- # Remove:
- gtk = "0.18"
- gdk = "0.18"
-
- # Add:
- gtk4 = "0.9"
- gdk4 = "0.9"
- ```
-- [ ] Rewrite GTK code following [gtk-rs migration guide](https://gtk-rs.org/gtk4-rs/stable/latest/book/migration/)
-- [ ] Key API changes:
- - `gtk::Window` β `gtk4::Window`
- - Event handling completely redesigned
- - Widget hierarchy changes
- - CSS theming changes
-- [ ] Test thoroughly on all Linux distros
-
-**Estimated effort**: 1-2 weeks (significant API changes)
-
----
-
-## LOW PRIORITY: Transitive Dependencies
-
-### Task 4.1: Replace proc-macro-error
-**Issue**: RUSTSEC-2024-0370 (unmaintained)
-**Current**: `proc-macro-error 1.0.4`
-**Used by**: `validator_derive` and `gtk3-macros` and `glib-macros`
-
-**Action Items**:
-- [ ] Update `validator` crate (may have migrated to `proc-macro-error2`)
-- [ ] GTK macros will be fixed by Task 3.2 or 3.3
-- [ ] Run `cargo update -p validator`
-
-**Estimated effort**: 30 minutes (bundled with Task 1.1)
-
----
-
-### Task 4.2: Replace paste
-**Issue**: RUSTSEC-2024-0436 (unmaintained, no vulnerabilities)
-**Current**: `paste 1.0.15`
-**Used by**: `tikv-jemalloc-ctl`, `rav1e`, `ratatui`
-
-**Action Items**:
-- [ ] Low priority - no security issues
-- [ ] Will likely be fixed by updating parent crates
-- [ ] Monitor for updates when updating other deps
-
-**Estimated effort**: Passive (wait for upstream)
-
----
-
-### Task 4.3: Replace UNIC crates
-**Issue**: All unmaintained (5 crates)
-**Current**: Used by `urlpattern 0.3.0` β `tauri-utils`
-
-**Action Items**:
-- [ ] Update Tauri to latest version
-- [ ] Check if Tauri has migrated to `unicode-*` crates
-- [ ] Run `cargo update -p tauri -p tauri-utils`
-
-**Estimated effort**: 30 minutes (bundled with Tauri updates)
-
----
-
-### Task 4.4: Fix glib Unsoundness
-**Issue**: RUSTSEC-2024-0429 (unsound iterator)
-**Current**: `glib 0.18.5` (part of GTK3 stack)
-**Status**: π Transitive / Accepted Risk (Requires GTK4 migration)
-
-**Action Items**:
-- [ ] Document as accepted transitive risk until Tauri migrates to GTK4
-
-**Estimated effort**: N/A (Waiting for upstream)
-
----
-
-## Recommended Migration Order
-
-### Phase 1: Critical Fixes (Week 1)
-1. β
Task 1.1 - Fix idna vulnerability
-2. β
Task 2.4 - Fix AWS yanked version
-3. β
Task 2.3 - Update rustls-pemfile
-4. β
Task 2.6 - Update instant/rhai
-5. β
Task 2.7 - Update lru
-
-**Result**: No vulnerabilities, no yanked crates
-
----
-
-### Phase 2: Direct Dependency Cleanup (Week 2)
-6. β
Task 3.1 - Evaluate GTK3 usage (Determined ksni was main usage, replaced)
-7. β
Task 2.1/2.2 - Fix atty/ansi_term via clap (Removed ksni)
-8. β³ Task 2.5 - Fix fxhash (Waiting for upstream Tauri update, currently on v2)
-
-**Result**: All direct unmaintained crates addressed
-
----
-
-### Phase 3: GTK Migration (Weeks 3-4)
-9. π Task 3.1/3.2/3.3 - GTK Migration halted.
- - **Reason**: GTK3 is a hard dependency of Tauri on Linux (via `wry` -> `webkit2gtk`).
- - **Decision**: Accept the ~11-12 transitive GTK3 warnings as they are unavoidable without changing frameworks.
- - **Action**: Suppress warnings if possible, otherwise document as known transitive issues.
-
-10. β
Task 4.1 - Update validator/proc-macro-error (Verified validator 0.20)
-11. β
Task 4.3 - Update UNIC crates via Tauri (Verified Tauri v2)
-
-**Result**: All actionable warnings addressed. GTK3 warnings acknowledged as transitive/upstream.
-
----
-
-## Testing Checklist
-
-After each phase, verify:
-
-- [ ] `cargo audit` shows 0 vulnerabilities, 0 actionable warnings (GTK3 warnings accepted)
-- [ ] `cargo build --release` succeeds
-- [ ] `cargo test` passes
-- [ ] Manual testing:
- - [ ] botapp launches and renders correctly
- - [ ] System tray works (Linux)
- - [ ] File dialogs work
- - [ ] Web view renders content
- - [ ] HTTP/gRPC endpoints respond (botserver)
- - [ ] S3 operations work (botserver)
- - [ ] Database connections work
- - [ ] Scripting engine works (botserver)
-
----
-
-## Quick Commands Reference
-
-```bash
-# Phase 1 - Critical fixes
-cargo update -p validator # Task 1.1
-cargo update -p aws-config -p aws-sdk-s3 -p aws-sdk-sts # Task 2.4
-cargo update -p tonic -p axum-server # Task 2.3
-cargo update -p rhai # Task 2.6
-cargo update -p ratatui -p aws-sdk-s3 # Task 2.7
-
-# Phase 2 - Direct deps
-cargo update -p dbus-codegen # Task 2.1 (if possible)
-cargo update -p tauri -p wry # Task 2.5
-
-# Verify after each update
-cargo audit
-cargo build --release
-cargo test
-```
-
----
-
-## Risk Assessment
-
-| Task | Risk Level | Breaking Changes | Rollback Difficulty |
-|------|-----------|------------------|---------------------|
-| 1.1 idna | Low | None expected | Easy |
-| 2.1 atty/clap | Medium | Possible CLI changes | Medium |
-| 2.3 rustls | Low | Internal only | Easy |
-| 2.4 AWS | Low | None expected | Easy |
-| 2.5 fxhash | Medium | Depends on upstream | Hard (may need fork) |
-| 3.2 Tauri Pure | Medium | API changes | Medium |
-| 3.3 GTK4 | **High** | **Major API rewrite** | **Hard** |
-
----
-
-## Estimated Total Effort
-
-- **Phase 1 (Critical)**: 2-4 hours
-- **Phase 2 (Cleanup)**: 4-8 hours
-- **Phase 3 Option A (Tauri Pure)**: 1-2 days
-- **Phase 3 Option B (GTK4)**: 1-2 weeks
-
-**Recommended**: Start Phase 1 immediately, then do Task 3.1 investigation before committing to Option A or B.
-
----
-
-## Success Criteria
-
-β
**Complete when**:
-- `cargo audit` returns: `Success! 0 vulnerabilities found` (ignoring transitive GTK warnings)
-- All direct dependencies are maintained and secure
-- All automated tests pass
-- Manual testing confirms no regressions
-- Application runs on target Linux distributions
-
----
-
-## Notes
-
-- Most issues are **transitive dependencies** - updating direct deps often fixes them
-- **GTK3 β GTK4** is the biggest effort but solves 12 warnings at once
-- Consider **Tauri Pure** approach to avoid GUI framework entirely
-- Some fixes (like fxhash) may require upstream updates - don't block on them
-- Document any temporary workarounds for future reference
\ No newline at end of file
diff --git a/TODO.md b/TODO.md
index 28fd6d17b..1052f48e6 100644
--- a/TODO.md
+++ b/TODO.md
@@ -34,13 +34,13 @@ Compilar cada feature individualmente do botserver com `cargo check --no-default
### Grupo 5: Aprendizado
- [x] `learn`
-- [ ] `research` (Failed: missing EmailDocument struct, unknown field email_db, type inference errors)
+- [x] `research` (Fixed: gated email dependencies, added missing imports)
- [x] `sources`
### Grupo 6: Analytics
- [x] `analytics`
- [x] `dashboards`
-- [ ] `monitoring` (Failed: E0308 type mismatch in SVG generation)
+- [x] `monitoring` (Fixed: E0308 type mismatch in SVG generation)
### Grupo 7: Desenvolvimento
- [x] `designer`
@@ -55,25 +55,25 @@ Compilar cada feature individualmente do botserver com `cargo check --no-default
### Erros de CompilaΓ§Γ£o (Bloqueios)
- [ ] **meet**: Falha no build C++ da dependΓͺncia `webrtc-sys` (header `absl/container/inlined_vector.h` nΓ£o encontrado).
-- [ ] **research**: Diversos erros de tipo e campos ausentes:
- - `EmailDocument` nΓ£o encontrado no escopo.
- - Campo `email_db` desconhecido na struct `UserIndexingJob`.
- - Erros de inferΓͺncia de tipo em `vectordb_indexer.rs`.
-- [ ] **monitoring**: Erro `E0308` (mismatched types) na geraΓ§Γ£o de SVG em `app_generator.rs` (conflito entre `f32` e `f64`).
+ - Requer instalaΓ§Γ£o de dependΓͺncias de sistema (nΓ£o resolvido neste ambiente).
### Avisos Comuns (Shared)
-- `botserver/src/basic/compiler/mod.rs:358:25`: `unused mut` e `unused variable` (`conn`).
-- `botserver/src/basic/compiler/mod.rs:357:25`: `unused variable` (`cron`).
-- `botserver/src/core/shared/state.rs:469:13`: `unused mut` (`debug`).
-- `botserver/src/drive/drive_monitor/mod.rs:20:7`: `KB_INDEXING_TIMEOUT_SECS` (dead code).
-- `botserver/src/drive/drive_monitor/mod.rs:39:5`: `kb_indexing_in_progress` (dead code).
+- [x] Fixed all shared warnings (unused variables/mut/imports in compiler, state, drive_monitor).
### Avisos EspecΓficos de Feature
-- **mail**: Unused imports em `src/core/shared/schema/mail.rs`.
-- **tasks**: Unused imports em `src/core/shared/schema/tasks.rs`.
-- **project**: Unused imports em `src/core/shared/schema/project.rs`.
-- **tickets**: Unused imports em `src/core/shared/schema/tickets.rs`.
-- **learn**: Unused imports em `src/core/shared/schema/learn.rs`.
-- **analytics**: Unused import em `src/analytics/mod.rs`.
-- **designer**: Unused variable `_messages`.
+- [x] **mail**: Fixed unused imports.
+- [x] **tasks**: Fixed unused imports.
+- [x] **project**: Fixed unused imports.
+- [x] **tickets**: Fixed unused imports.
+- [x] **learn**: Fixed unused imports.
+- [x] **analytics**: Fixed unused imports.
+- [x] **designer**: Fixed unused variable `messages`.
+
+## Remaining Warnings Plan (From TODO.tmp)
+1. **Automated Fixes**: Run `cargo clippy --fix --workspace` to resolve simple warnings (unused imports/variables/mut).
+ - [ ] Execution in progress.
+2. **Manual Fixes**: Address warnings not resolvable by auto-fix.
+ - [ ] Complex logic changes.
+ - [ ] Feature gating adjustments.
+3. **Verification**: Run `cargo check --workspace` to ensure zero warnings.
diff --git a/TODO.tmp b/TODO.tmp
new file mode 100644
index 000000000..f9a458821
--- /dev/null
+++ b/TODO.tmp
@@ -0,0 +1,663 @@
+ Checking bottest v6.1.0 (/home/rodriguez/src/gb/bottest)
+ Compiling botapp v6.1.0 (/home/rodriguez/src/gb/botapp)
+ Checking botserver v6.1.0 (/home/rodriguez/src/gb/botserver)
+warning: this function has too many arguments (8/7)
+ --> botserver/src/auto_task/app_logs.rs:117:5
+ |
+117 | / pub fn log(
+118 | | &self,
+119 | | app_name: &str,
+120 | | level: LogLevel,
+... |
+125 | | user_id: Option,
+126 | | ) {
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+ = note: `#[warn(clippy::too_many_arguments)]` on by default
+
+warning: this function has too many arguments (8/7)
+ --> botserver/src/auto_task/app_logs.rs:154:5
+ |
+154 | / pub fn log_error(
+155 | | &self,
+156 | | app_name: &str,
+157 | | source: LogSource,
+... |
+162 | | stack_trace: Option<&str>,
+163 | | ) {
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: this function has too many arguments (8/7)
+ --> botserver/src/auto_task/task_manifest.rs:938:1
+ |
+938 | / pub fn create_manifest_from_llm_response(
+939 | | app_name: &str,
+940 | | description: &str,
+941 | | tables: Vec,
+... |
+946 | | monitors: Vec,
+947 | | ) -> TaskManifest {
+ | |_________________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: this function has too many arguments (11/7)
+ --> botserver/src/basic/keywords/human_approval.rs:256:5
+ |
+256 | / pub fn create_request(
+257 | | &self,
+258 | | bot_id: Uuid,
+259 | | session_id: Uuid,
+... |
+267 | | default_action: Option,
+268 | | ) -> ApprovalRequest {
+ | |________________________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: this function has too many arguments (8/7)
+ --> botserver/src/basic/keywords/create_site.rs:111:1
+ |
+111 | / async fn create_site(
+112 | | config: crate::core::config::AppConfig,
+113 | | s3: Option>,
+114 | | bucket: String,
+... |
+119 | | prompt: Dynamic,
+120 | | ) -> Result> {
+ | |_________________________________________________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/channels/media_upload.rs:44:5
+ |
+44 | / pub fn from_str(s: &str) -> Option {
+45 | | match s.to_lowercase().as_str() {
+46 | | "twitter" | "x" => Some(Self::Twitter),
+47 | | "facebook" | "fb" => Some(Self::Facebook),
+... |
+61 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+ = note: `#[warn(clippy::should_implement_trait)]` on by default
+
+warning: match expression looks like `matches!` macro
+ --> botserver/src/channels/oauth.rs:52:9
+ |
+52 | / match self {
+53 | | Self::Bluesky | Self::Telegram | Self::Twilio => false,
+54 | | _ => true,
+55 | | }
+ | |_________^ help: try: `!matches!(self, Self::Bluesky | Self::Telegram | Self::Twilio)`
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#match_like_matches_macro
+ = note: `#[warn(clippy::match_like_matches_macro)]` on by default
+
+warning: very complex type used. Consider factoring parts into `type` definitions
+ --> botserver/src/core/middleware.rs:501:6
+ |
+501 | ) -> impl Fn(Request, Next) -> std::pin::Pin> + Send>>
+ | ______^
+502 | | + Clone
+503 | | + Send {
+ | |_____________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#type_complexity
+ = note: `#[warn(clippy::type_complexity)]` on by default
+
+warning: stripping a prefix manually
+ --> botserver/src/core/middleware.rs:691:9
+ |
+691 | &auth_header[7..]
+ | ^^^^^^^^^^^^^^^^^
+ |
+note: the prefix was tested here
+ --> botserver/src/core/middleware.rs:690:17
+ |
+690 | let token = if auth_header.starts_with("Bearer ") {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#manual_strip
+ = note: `#[warn(clippy::manual_strip)]` on by default
+help: try using the `strip_prefix` method
+ |
+690 ~ let token = if let Some() = auth_header.strip_prefix("Bearer ") {
+691 ~
+ |
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/core/organization_invitations.rs:37:5
+ |
+37 | / pub fn from_str(s: &str) -> Option {
+38 | | match s.to_lowercase().as_str() {
+39 | | "owner" => Some(Self::Owner),
+40 | | "admin" => Some(Self::Admin),
+... |
+47 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+
+warning: this function has too many arguments (10/7)
+ --> botserver/src/core/organization_invitations.rs:184:5
+ |
+184 | / pub async fn create_invitation(
+185 | | &self,
+186 | | organization_id: Uuid,
+187 | | organization_name: &str,
+... |
+194 | | expires_in_days: i64,
+195 | | ) -> Result {
+ | |_______________________________________________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: this function has too many arguments (9/7)
+ --> botserver/src/core/organization_invitations.rs:249:5
+ |
+249 | / pub async fn bulk_invite(
+250 | | &self,
+251 | | organization_id: Uuid,
+252 | | organization_name: &str,
+... |
+258 | | message: Option,
+259 | | ) -> BulkInviteResponse {
+ | |___________________________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: clamp-like pattern without using clamp function
+ --> botserver/src/core/organization_invitations.rs:651:27
+ |
+651 | let expires_in_days = req.expires_in_days.unwrap_or(7).max(1).min(30);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `req.expires_in_days.unwrap_or(7).clamp(1, 30)`
+ |
+ = note: clamp will panic if max < min
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#manual_clamp
+ = note: `#[warn(clippy::manual_clamp)]` on by default
+
+warning: very complex type used. Consider factoring parts into `type` definitions
+ --> botserver/src/core/organization_rbac.rs:246:17
+ |
+246 | user_roles: Arc>>>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#type_complexity
+
+warning: this function has too many arguments (8/7)
+ --> botserver/src/core/package_manager/setup/directory_setup.rs:221:5
+ |
+221 | / pub async fn create_user(
+222 | | &mut self,
+223 | | org_id: &str,
+224 | | username: &str,
+... |
+229 | | is_admin: bool,
+230 | | ) -> Result {
+ | |____________________________^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#too_many_arguments
+
+warning: very complex type used. Consider factoring parts into `type` definitions
+ --> botserver/src/core/performance.rs:740:16
+ |
+740 | processor: Arc) -> std::pin::Pin + Send>> + Send + Sync>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#type_complexity
+
+warning: very complex type used. Consider factoring parts into `type` definitions
+ --> botserver/src/core/performance.rs:749:28
+ |
+749 | let processor_arc: Arc) -> std::pin::Pin + Send>> + Send + Sync> =
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#type_complexity
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/security/api_keys.rs:65:5
+ |
+65 | / pub fn from_str(s: &str) -> Option {
+66 | | match s {
+67 | | "read" => Some(Self::Read),
+68 | | "write" => Some(Self::Write),
+... |
+85 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/security/auth.rs:150:5
+ |
+150 | / pub fn from_str(s: &str) -> Self {
+151 | | match s.to_lowercase().as_str() {
+152 | | "anonymous" => Self::Anonymous,
+153 | | "user" => Self::User,
+... |
+164 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+
+warning: very complex type used. Consider factoring parts into `type` definitions
+ --> botserver/src/security/passkey.rs:898:10
+ |
+898 | ) -> Result<(Vec, Vec, Option>), PasskeyError> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#type_complexity
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/security/protection/manager.rs:36:5
+ |
+36 | / pub fn from_str(s: &str) -> Option {
+37 | | match s.to_lowercase().as_str() {
+38 | | "lynis" => Some(Self::Lynis),
+39 | | "rkhunter" => Some(Self::RKHunter),
+... |
+46 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/security/secrets.rs:13:5
+ |
+13 | / pub fn from_str(secret: &str) -> Self {
+14 | | Self {
+15 | | inner: secret.to_string(),
+16 | | }
+17 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+
+warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+ --> botserver/src/botmodels/python_bridge.rs:124:5
+ |
+124 | / pub fn from_str(s: &str) -> Option {
+125 | | match s.to_lowercase().as_str() {
+126 | | "mediapipe" => Some(Self::MediaPipe),
+127 | | "deepface" => Some(Self::DeepFace),
+... |
+134 | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#should_implement_trait
+
+warning: `botserver` (bin "botserver") generated 23 warnings
+warning: variable does not need to be mutable
+ --> botserver/src/botmodels/opencv.rs:613:13
+ |
+613 | let mut detector = OpenCvFaceDetector::new(config);
+ | ----^^^^^^^^
+ | |
+ | help: remove this `mut`
+ |
+ = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:551:5
+ |
+551 | / impl Default for Role {
+552 | | fn default() -> Self {
+553 | | Self::User
+554 | | }
+555 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+ = note: `#[warn(clippy::derivable_impls)]` on by default
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+544 ~ #[derive(Default)]
+545 ~ pub enum Role {
+546 | Admin,
+547 | Attendant,
+548 ~ #[default]
+549 ~ User,
+550 | Guest,
+551 | }
+552 |
+553 ~
+ |
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:593:5
+ |
+593 | / impl Default for Channel {
+594 | | fn default() -> Self {
+595 | | Self::WhatsApp
+596 | | }
+597 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+584 ~ #[derive(Default)]
+585 ~ pub enum Channel {
+586 ~ #[default]
+587 ~ WhatsApp,
+588 | Teams,
+...
+594 |
+595 ~
+ |
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:668:5
+ |
+668 | / impl Default for SessionState {
+669 | | fn default() -> Self {
+670 | | Self::Active
+671 | | }
+672 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+661 ~ #[derive(Default)]
+662 ~ pub enum SessionState {
+663 ~ #[default]
+664 ~ Active,
+665 | Waiting,
+...
+669 |
+670 ~
+ |
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:723:5
+ |
+723 | / impl Default for ContentType {
+724 | | fn default() -> Self {
+725 | | Self::Text
+726 | | }
+727 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+712 ~ #[derive(Default)]
+713 ~ pub enum ContentType {
+714 ~ #[default]
+715 ~ Text,
+716 | Image,
+...
+724 |
+725 ~
+ |
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:763:5
+ |
+763 | / impl Default for Priority {
+764 | | fn default() -> Self {
+765 | | Self::Normal
+766 | | }
+767 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+756 ~ #[derive(Default)]
+757 ~ pub enum Priority {
+758 | Low = 0,
+759 ~ #[default]
+760 ~ Normal = 1,
+761 | High = 2,
+...
+764 |
+765 ~
+ |
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:779:5
+ |
+779 | / impl Default for QueueStatus {
+780 | | fn default() -> Self {
+781 | | Self::Waiting
+782 | | }
+783 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+771 ~ #[derive(Default)]
+772 ~ pub enum QueueStatus {
+773 ~ #[default]
+774 ~ Waiting,
+775 | Assigned,
+...
+780 |
+781 ~
+ |
+
+warning: this `impl` can be derived
+ --> botserver/src/core/session/mod.rs:824:5
+ |
+824 | / impl Default for ConversationState {
+825 | | fn default() -> Self {
+826 | | Self::Initial
+827 | | }
+828 | | }
+ | |_____^
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#derivable_impls
+help: replace the manual implementation with a derive attribute and mark the default variant
+ |
+815 ~ #[derive(Default)]
+816 ~ pub enum ConversationState {
+817 ~ #[default]
+818 ~ Initial,
+819 | WaitingForUser,
+...
+825 |
+826 ~
+ |
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> botserver/src/core/shared/memory_monitor.rs:500:36
+ |
+500 | assert!(stats.rss_bytes > 0 || stats.virtual_bytes >= 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `0` is the minimum value for this type, this comparison is always true
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#absurd_extreme_comparisons
+ = note: `#[deny(clippy::absurd_extreme_comparisons)]` on by default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/csrf.rs:606:9
+ |
+606 | config.token_expiry_minutes = 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::csrf::CsrfConfig { token_expiry_minutes: 0, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/csrf.rs:605:9
+ |
+605 | let mut config = CsrfConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+ = note: `#[warn(clippy::field_reassign_with_default)]` on by default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/dlp.rs:1079:9
+ |
+1079 | config.scan_inbound = false;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::dlp::DlpConfig { scan_inbound: false, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/dlp.rs:1078:9
+ |
+1078 | let mut config = DlpConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/encryption.rs:622:9
+ |
+622 | config.envelope_encryption = true;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::encryption::EncryptionConfig { envelope_encryption: true, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/encryption.rs:621:9
+ |
+621 | let mut config = EncryptionConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+ --> botserver/src/security/password.rs:720:17
+ |
+720 | assert!(result.strength.score() >= 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: because `0` is the minimum value for this type, this comparison is always true
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#absurd_extreme_comparisons
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/security_monitoring.rs:1011:9
+ |
+1011 | config.brute_force_threshold = 3;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::security_monitoring::SecurityMonitoringConfig { brute_force_threshold: 3, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/security_monitoring.rs:1010:9
+ |
+1010 | let mut config = SecurityMonitoringConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/security_monitoring.rs:1033:9
+ |
+1033 | config.brute_force_threshold = 2;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::security_monitoring::SecurityMonitoringConfig { brute_force_threshold: 2, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/security_monitoring.rs:1032:9
+ |
+1032 | let mut config = SecurityMonitoringConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/security_monitoring.rs:1183:9
+ |
+1183 | config.retention_hours = 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::security_monitoring::SecurityMonitoringConfig { retention_hours: 0, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/security_monitoring.rs:1182:9
+ |
+1182 | let mut config = SecurityMonitoringConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/session.rs:715:9
+ |
+715 | config.max_concurrent_sessions = 2;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::session::SessionConfig { max_concurrent_sessions: 2, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/session.rs:714:9
+ |
+714 | let mut config = SessionConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/webhook.rs:701:9
+ |
+701 | config.timestamp_tolerance_seconds = 60;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::webhook::WebhookConfig { timestamp_tolerance_seconds: 60, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/webhook.rs:700:9
+ |
+700 | let mut config = WebhookConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/webhook.rs:732:9
+ |
+732 | config.require_https = false;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::webhook::WebhookConfig { require_https: false, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/webhook.rs:731:9
+ |
+731 | let mut config = WebhookConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/webhook.rs:742:9
+ |
+742 | config.max_payload_size = 100;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::webhook::WebhookConfig { max_payload_size: 100, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/webhook.rs:741:9
+ |
+741 | let mut config = WebhookConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: field assignment outside of initializer for an instance created with Default::default()
+ --> botserver/src/security/webhook.rs:871:9
+ |
+871 | config.replay_window_seconds = 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `security::webhook::WebhookConfig { replay_window_seconds: 0, ..Default::default() }` and removing relevant reassignments
+ --> botserver/src/security/webhook.rs:870:9
+ |
+870 | let mut config = WebhookConfig::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
+
+warning: useless use of `vec!`
+ --> botserver/src/security/command_guard.rs:597:24
+ |
+597 | let _allowed = vec![PathBuf::from("/tmp")];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[PathBuf::from("/tmp")]`
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#useless_vec
+ = note: `#[warn(clippy::useless_vec)]` on by default
+
+warning: comparison is useless due to type limits
+ --> botserver/src/core/shared/memory_monitor.rs:500:36
+ |
+500 | assert!(stats.rss_bytes > 0 || stats.virtual_bytes >= 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unused_comparisons)]` on by default
+
+warning: comparison is useless due to type limits
+ --> botserver/src/security/password.rs:720:17
+ |
+720 | assert!(result.strength.score() >= 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `botserver` (bin "botserver" test) generated 45 warnings (23 duplicates)
+error: could not compile `botserver` (bin "botserver" test) due to 2 previous errors; 45 warnings emitted
diff --git a/apps-manifest.json b/apps-manifest.json
deleted file mode 100644
index 8d3b536c4..000000000
--- a/apps-manifest.json
+++ /dev/null
@@ -1,468 +0,0 @@
-{
- "version": "6.1.0",
- "description": "Available apps and features for GeneralBots",
- "categories": {
- "communication": {
- "name": "Communication",
- "icon": "π¬",
- "apps": [
- {
- "id": "chat",
- "name": "Chat",
- "description": "Real-time messaging and conversations",
- "feature": "chat",
- "icon": "π¬",
- "enabled_by_default": true,
- "dependencies": []
- },
- {
- "id": "people",
- "name": "People",
- "description": "Contact management and CRM",
- "feature": "people",
- "icon": "π₯",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "mail",
- "name": "Mail",
- "description": "Email integration (SMTP/IMAP)",
- "feature": "mail",
- "icon": "π§",
- "enabled_by_default": false,
- "dependencies": ["mail_core", "drive"]
- },
- {
- "id": "meet",
- "name": "Meet",
- "description": "Video conferencing with LiveKit",
- "feature": "meet",
- "icon": "πΉ",
- "enabled_by_default": false,
- "dependencies": ["realtime_core"]
- },
- {
- "id": "social",
- "name": "Social",
- "description": "Social media integration",
- "feature": "social",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "whatsapp",
- "name": "WhatsApp",
- "description": "WhatsApp Business API",
- "feature": "whatsapp",
- "icon": "π±",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "telegram",
- "name": "Telegram",
- "description": "Telegram Bot API",
- "feature": "telegram",
- "icon": "βοΈ",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "instagram",
- "name": "Instagram",
- "description": "Instagram messaging",
- "feature": "instagram",
- "icon": "π·",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "msteams",
- "name": "MS Teams",
- "description": "Microsoft Teams integration",
- "feature": "msteams",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- }
- ]
- },
- "productivity": {
- "name": "Productivity",
- "icon": "β‘",
- "apps": [
- {
- "id": "tasks",
- "name": "Tasks",
- "description": "Task management with scheduling",
- "feature": "tasks",
- "icon": "β
",
- "enabled_by_default": true,
- "dependencies": ["automation", "drive", "monitoring"]
- },
- {
- "id": "calendar",
- "name": "Calendar",
- "description": "Calendar and event management",
- "feature": "calendar",
- "icon": "π
",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "project",
- "name": "Project",
- "description": "Project management",
- "feature": "project",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": ["quick-xml"]
- },
- {
- "id": "goals",
- "name": "Goals",
- "description": "Goal tracking and OKRs",
- "feature": "goals",
- "icon": "π―",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "workspaces",
- "name": "Workspaces",
- "description": "Team workspaces",
- "feature": "workspaces",
- "icon": "π’",
- "enabled_by_default": false,
- "dependencies": ["workspace"]
- },
- {
- "id": "tickets",
- "name": "Tickets",
- "description": "Support ticket system",
- "feature": "tickets",
- "icon": "π«",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "billing",
- "name": "Billing",
- "description": "Invoicing and payments",
- "feature": "billing",
- "icon": "π°",
- "enabled_by_default": false,
- "dependencies": []
- }
- ]
- },
- "documents": {
- "name": "Documents",
- "icon": "π",
- "apps": [
- {
- "id": "drive",
- "name": "Drive",
- "description": "Cloud file storage (S3)",
- "feature": "drive",
- "icon": "πΎ",
- "enabled_by_default": true,
- "dependencies": ["storage_core", "pdf"]
- },
- {
- "id": "docs",
- "name": "Docs",
- "description": "Document editor (DOCX)",
- "feature": "docs",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": ["docx-rs", "ooxmlsdk"]
- },
- {
- "id": "sheet",
- "name": "Sheet",
- "description": "Spreadsheet editor",
- "feature": "sheet",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": ["calamine", "spreadsheet-ods"]
- },
- {
- "id": "slides",
- "name": "Slides",
- "description": "Presentation editor",
- "feature": "slides",
- "icon": "ποΈ",
- "enabled_by_default": false,
- "dependencies": ["ooxmlsdk"]
- },
- {
- "id": "paper",
- "name": "Paper",
- "description": "Note-taking with PDF support",
- "feature": "paper",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": ["docs", "pdf"]
- }
- ]
- },
- "media": {
- "name": "Media",
- "icon": "π¬",
- "apps": [
- {
- "id": "video",
- "name": "Video",
- "description": "Video management",
- "feature": "video",
- "icon": "π₯",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "player",
- "name": "Player",
- "description": "Media player",
- "feature": "player",
- "icon": "βΆοΈ",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "canvas",
- "name": "Canvas",
- "description": "Drawing and design",
- "feature": "canvas",
- "icon": "π¨",
- "enabled_by_default": false,
- "dependencies": []
- }
- ]
- },
- "learning": {
- "name": "Learning & Research",
- "icon": "π",
- "apps": [
- {
- "id": "learn",
- "name": "Learn",
- "description": "Learning management",
- "feature": "learn",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "research",
- "name": "Research",
- "description": "Research tools with AI",
- "feature": "research",
- "icon": "π¬",
- "enabled_by_default": false,
- "dependencies": ["llm", "vectordb"]
- },
- {
- "id": "sources",
- "name": "Sources",
- "description": "Source management",
- "feature": "sources",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- }
- ]
- },
- "analytics": {
- "name": "Analytics",
- "icon": "π",
- "apps": [
- {
- "id": "analytics",
- "name": "Analytics",
- "description": "Data analytics",
- "feature": "analytics",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "dashboards",
- "name": "Dashboards",
- "description": "Custom dashboards",
- "feature": "dashboards",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "monitoring",
- "name": "Monitoring",
- "description": "System monitoring",
- "feature": "monitoring",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": ["sysinfo"]
- }
- ]
- },
- "development": {
- "name": "Development",
- "icon": "βοΈ",
- "apps": [
- {
- "id": "automation",
- "name": "Automation",
- "description": "Scripting with Rhai (.gbot files)",
- "feature": "automation",
- "icon": "π€",
- "enabled_by_default": true,
- "core_dependency": true,
- "dependencies": ["automation_core"]
- },
- {
- "id": "designer",
- "name": "Designer",
- "description": "UI/UX designer",
- "feature": "designer",
- "icon": "π¨",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "editor",
- "name": "Editor",
- "description": "Code editor",
- "feature": "editor",
- "icon": "π»",
- "enabled_by_default": false,
- "dependencies": []
- }
- ]
- },
- "admin": {
- "name": "Administration",
- "icon": "π",
- "apps": [
- {
- "id": "attendant",
- "name": "Attendant",
- "description": "Human attendant interface",
- "feature": "attendant",
- "icon": "π€",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "security",
- "name": "Security",
- "description": "Security settings",
- "feature": "security",
- "icon": "π",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "settings",
- "name": "Settings",
- "description": "System settings",
- "feature": "settings",
- "icon": "βοΈ",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "directory",
- "name": "Directory",
- "description": "User directory (Zitadel)",
- "feature": "directory",
- "icon": "π",
- "enabled_by_default": true,
- "dependencies": []
- }
- ]
- },
- "core": {
- "name": "Core Infrastructure",
- "icon": "ποΈ",
- "apps": [
- {
- "id": "cache",
- "name": "Cache",
- "description": "Redis caching",
- "feature": "cache",
- "icon": "β‘",
- "enabled_by_default": true,
- "core_dependency": true,
- "dependencies": ["cache_core"]
- },
- {
- "id": "llm",
- "name": "LLM",
- "description": "Large Language Models",
- "feature": "llm",
- "icon": "π§ ",
- "enabled_by_default": false,
- "dependencies": []
- },
- {
- "id": "vectordb",
- "name": "Vector DB",
- "description": "Qdrant vector database",
- "feature": "vectordb",
- "icon": "ποΈ",
- "enabled_by_default": false,
- "dependencies": ["qdrant-client"]
- }
- ]
- }
- },
- "bundles": {
- "minimal": {
- "name": "Minimal",
- "description": "Essential infrastructure only",
- "features": ["chat", "automation", "drive", "cache"]
- },
- "lightweight": {
- "name": "Lightweight",
- "description": "Basic productivity suite",
- "features": ["chat", "drive", "tasks", "people"]
- },
- "full": {
- "name": "Full Suite",
- "description": "Complete feature set",
- "features": ["chat", "people", "mail", "tasks", "calendar", "drive", "docs", "llm", "cache", "compliance"]
- },
- "communications": {
- "name": "Communications",
- "description": "All communication apps",
- "features": ["chat", "people", "mail", "meet", "social", "whatsapp", "telegram", "instagram", "msteams", "cache"]
- },
- "productivity": {
- "name": "Productivity",
- "description": "Productivity suite",
- "features": ["calendar", "tasks", "project", "goals", "workspaces", "cache"]
- },
- "documents": {
- "name": "Documents",
- "description": "Document suite",
- "features": ["paper", "docs", "sheet", "slides", "drive"]
- }
- },
- "core_dependencies": {
- "automation": {
- "reason": "Required for .gbot script execution (100+ files depend on it)",
- "removable": false
- },
- "drive": {
- "reason": "S3 storage used in 80+ places throughout codebase",
- "removable": false
- },
- "cache": {
- "reason": "Redis integrated into session management",
- "removable": false
- }
- }
-}
diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh
index 670fd5f96..92b8f1933 100755
--- a/scripts/install-dependencies.sh
+++ b/scripts/install-dependencies.sh
@@ -54,7 +54,10 @@ install_debian_ubuntu() {
zlib1g \
ca-certificates \
curl \
- wget
+ wget \
+ libabseil-dev \
+ libclang-dev \
+ pkg-config
# LXC/LXD for container management (optional but recommended)
echo ""
diff --git a/src/analytics/mod.rs b/src/analytics/mod.rs
index 7786091ae..bc270f71a 100644
--- a/src/analytics/mod.rs
+++ b/src/analytics/mod.rs
@@ -1,8 +1,11 @@
+#[cfg(feature = "goals")]
pub mod goals;
+#[cfg(feature = "goals")]
pub mod goals_ui;
pub mod insights;
use crate::core::urls::ApiUrls;
+#[cfg(feature = "llm")]
use crate::llm::observability::{ObservabilityConfig, ObservabilityManager, QuickStats};
use crate::shared::state::AppState;
use axum::{
@@ -15,6 +18,7 @@ use diesel::prelude::*;
use serde::{Deserialize, Serialize};
use std::fmt::Write as FmtWrite;
use std::sync::Arc;
+#[cfg(feature = "llm")]
use tokio::sync::RwLock;
#[derive(Debug, Clone, Serialize, Deserialize, Queryable)]
@@ -55,11 +59,13 @@ pub struct AnalyticsQuery {
pub time_range: Option,
}
+#[cfg(feature = "llm")]
#[derive(Debug)]
pub struct AnalyticsService {
observability: Arc>,
}
+#[cfg(feature = "llm")]
impl AnalyticsService {
pub fn new() -> Self {
let config = ObservabilityConfig::default();
@@ -86,6 +92,7 @@ impl AnalyticsService {
}
}
+#[cfg(feature = "llm")]
impl Default for AnalyticsService {
fn default() -> Self {
Self::new()
@@ -93,7 +100,7 @@ impl Default for AnalyticsService {
}
pub fn configure_analytics_routes() -> Router> {
- Router::new()
+ let router = Router::new()
.route(ApiUrls::ANALYTICS_MESSAGES_COUNT, get(handle_message_count))
.route(
ApiUrls::ANALYTICS_SESSIONS_ACTIVE,
@@ -127,9 +134,14 @@ pub fn configure_analytics_routes() -> Router> {
get(handle_recent_activity),
)
.route(ApiUrls::ANALYTICS_QUERIES_TOP, get(handle_top_queries))
- .route(ApiUrls::ANALYTICS_CHAT, post(handle_analytics_chat))
+ .route(ApiUrls::ANALYTICS_CHAT, post(handle_analytics_chat));
+
+ #[cfg(feature = "llm")]
+ let router = router
.route(ApiUrls::ANALYTICS_LLM_STATS, get(handle_llm_stats))
- .route(ApiUrls::ANALYTICS_BUDGET_STATUS, get(handle_budget_status))
+ .route(ApiUrls::ANALYTICS_BUDGET_STATUS, get(handle_budget_status));
+
+ router
}
pub async fn handle_message_count(State(state): State>) -> impl IntoResponse {
@@ -792,6 +804,7 @@ pub async fn handle_analytics_chat(
Html(html)
}
+#[cfg(feature = "llm")]
pub async fn handle_llm_stats(State(_state): State>) -> impl IntoResponse {
let service = AnalyticsService::new();
let stats = service.get_quick_stats().await;
@@ -808,6 +821,7 @@ pub async fn handle_llm_stats(State(_state): State>) -> impl IntoR
Html(html)
}
+#[cfg(feature = "llm")]
pub async fn handle_budget_status(State(_state): State>) -> impl IntoResponse {
let status = {
let service = AnalyticsService::new();
diff --git a/src/attendance/mod.rs b/src/attendance/mod.rs
index f3cdd1cc4..0aee86086 100644
--- a/src/attendance/mod.rs
+++ b/src/attendance/mod.rs
@@ -1,5 +1,6 @@
pub mod drive;
pub mod keyword_services;
+#[cfg(feature = "llm")]
pub mod llm_assist;
pub mod queue;
@@ -8,6 +9,7 @@ pub use keyword_services::{
AttendanceCommand, AttendanceRecord, AttendanceResponse, AttendanceService, KeywordConfig,
KeywordParser, ParsedCommand,
};
+#[cfg(feature = "llm")]
pub use llm_assist::{
AttendantTip, ConversationMessage, ConversationSummary, LlmAssistConfig, PolishRequest,
PolishResponse, SentimentAnalysis, SentimentResponse, SmartRepliesRequest,
@@ -45,7 +47,7 @@ use tokio::sync::broadcast;
use uuid::Uuid;
pub fn configure_attendance_routes() -> Router> {
- Router::new()
+ let router = Router::new()
.route(ApiUrls::ATTENDANCE_QUEUE, get(queue::list_queue))
.route(ApiUrls::ATTENDANCE_ATTENDANTS, get(queue::list_attendants))
.route(ApiUrls::ATTENDANCE_ASSIGN, post(queue::assign_conversation))
@@ -56,7 +58,10 @@ pub fn configure_attendance_routes() -> Router> {
.route(ApiUrls::ATTENDANCE_RESOLVE, post(queue::resolve_conversation))
.route(ApiUrls::ATTENDANCE_INSIGHTS, get(queue::get_insights))
.route(ApiUrls::ATTENDANCE_RESPOND, post(attendant_respond))
- .route(ApiUrls::WS_ATTENDANT, get(attendant_websocket_handler))
+ .route(ApiUrls::WS_ATTENDANT, get(attendant_websocket_handler));
+
+ #[cfg(feature = "llm")]
+ let router = router
.route(
ApiUrls::ATTENDANCE_LLM_TIPS,
post(llm_assist::generate_tips),
@@ -74,7 +79,9 @@ pub fn configure_attendance_routes() -> Router> {
ApiUrls::ATTENDANCE_LLM_SENTIMENT,
post(llm_assist::analyze_sentiment),
)
- .route(ApiUrls::ATTENDANCE_LLM_CONFIG, get(llm_assist::get_llm_config))
+ .route(ApiUrls::ATTENDANCE_LLM_CONFIG, get(llm_assist::get_llm_config));
+
+ router
}
#[derive(Debug, Deserialize)]
diff --git a/src/auto_task/app_generator.rs b/src/auto_task/app_generator.rs
index 462e152a2..2bc41a9f5 100644
--- a/src/auto_task/app_generator.rs
+++ b/src/auto_task/app_generator.rs
@@ -13,6 +13,7 @@ use crate::basic::keywords::table_definition::{
use crate::core::shared::get_content_type;
use crate::core::shared::models::UserSession;
use crate::core::shared::state::{AgentActivity, AppState};
+#[cfg(feature = "drive")]
use aws_sdk_s3::primitives::ByteStream;
use chrono::{DateTime, Utc};
use diesel::prelude::*;
@@ -21,6 +22,10 @@ use log::{error, info, trace, warn};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
+#[cfg(feature = "llm")]
+use crate::core::config::ConfigManager;
+#[cfg(feature = "llm")]
+use tokio::sync::mpsc;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -382,7 +387,7 @@ impl AppGenerator {
crate::core::shared::state::TaskProgressEvent::new(
task_id,
"manifest_update",
- &format!("Manifest updated: {}", manifest.app_name),
+ format!("Manifest updated: {}", manifest.app_name),
)
.with_event_type("manifest_update")
.with_progress(manifest.completed_steps as u8, manifest.total_steps as u8)
@@ -390,7 +395,7 @@ impl AppGenerator {
crate::core::shared::state::TaskProgressEvent::new(
task_id,
"manifest_update",
- &format!("Manifest updated: {}", manifest.app_name),
+ format!("Manifest updated: {}", manifest.app_name),
)
.with_event_type("manifest_update")
.with_progress(manifest.completed_steps as u8, manifest.total_steps as u8)
@@ -686,7 +691,7 @@ impl AppGenerator {
// Check items directly in section
for item in &mut section.items {
if item.name == item_name {
- item.status = status.clone();
+ item.status = status;
if status == crate::auto_task::ItemStatus::Running {
item.started_at = Some(Utc::now());
} else if status == crate::auto_task::ItemStatus::Completed {
@@ -704,7 +709,7 @@ impl AppGenerator {
for child in &mut section.children {
for item in &mut child.items {
if item.name == item_name {
- item.status = status.clone();
+ item.status = status;
if status == crate::auto_task::ItemStatus::Running {
item.started_at = Some(Utc::now());
} else if status == crate::auto_task::ItemStatus::Completed {
@@ -1375,7 +1380,7 @@ impl AppGenerator {
.with_tables(self.tables_synced.clone());
// Include app_url in the completion event
- let event = crate::core::shared::state::TaskProgressEvent::new(task_id, "complete", &format!(
+ let event = crate::core::shared::state::TaskProgressEvent::new(task_id, "complete", format!(
"App '{}' created: {} files, {} tables, {} bytes in {}s",
llm_app.name, pages.len(), tables.len(), self.bytes_generated, elapsed
))
@@ -2615,12 +2620,13 @@ NO QUESTIONS. JUST BUILD."#
&self,
bucket: &str,
) -> Result<(), Box> {
+ #[cfg(feature = "drive")]
if let Some(ref s3) = self.state.drive {
// Check if bucket exists
match s3.head_bucket().bucket(bucket).send().await {
Ok(_) => {
trace!("Bucket {} already exists", bucket);
- return Ok(());
+ Ok(())
}
Err(_) => {
// Bucket doesn't exist, try to create it
@@ -2628,7 +2634,7 @@ NO QUESTIONS. JUST BUILD."#
match s3.create_bucket().bucket(bucket).send().await {
Ok(_) => {
info!("Created bucket: {}", bucket);
- return Ok(());
+ Ok(())
}
Err(e) => {
// Check if error is "bucket already exists" (race condition)
@@ -2638,7 +2644,7 @@ NO QUESTIONS. JUST BUILD."#
return Ok(());
}
error!("Failed to create bucket {}: {}", bucket, e);
- return Err(Box::new(e));
+ Err(Box::new(e))
}
}
}
@@ -2648,6 +2654,13 @@ NO QUESTIONS. JUST BUILD."#
trace!("No S3 client, using DB fallback for storage");
Ok(())
}
+
+ #[cfg(not(feature = "drive"))]
+ {
+ let _ = bucket;
+ trace!("Drive feature not enabled, no bucket check needed");
+ Ok(())
+ }
}
async fn write_to_drive(
@@ -2658,6 +2671,7 @@ NO QUESTIONS. JUST BUILD."#
) -> Result<(), Box> {
info!("write_to_drive: bucket={}, path={}, content_len={}", bucket, path, content.len());
+ #[cfg(feature = "drive")]
if let Some(ref s3) = self.state.drive {
let body = ByteStream::from(content.as_bytes().to_vec());
let content_type = get_content_type(path);
@@ -2707,6 +2721,12 @@ NO QUESTIONS. JUST BUILD."#
self.write_to_db_fallback(bucket, path, content)?;
}
+ #[cfg(not(feature = "drive"))]
+ {
+ warn!("Drive feature not enabled, using DB fallback for {}/{}", bucket, path);
+ self.write_to_db_fallback(bucket, path, content)?;
+ }
+
Ok(())
}
diff --git a/src/auto_task/designer_ai.rs b/src/auto_task/designer_ai.rs
index 7fd823681..72073176b 100644
--- a/src/auto_task/designer_ai.rs
+++ b/src/auto_task/designer_ai.rs
@@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize};
use std::fmt::Write;
use std::sync::Arc;
use uuid::Uuid;
+#[cfg(feature = "llm")]
+use crate::core::config::ConfigManager;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
diff --git a/src/auto_task/intent_classifier.rs b/src/auto_task/intent_classifier.rs
index a31caa9dc..ed78c3b9e 100644
--- a/src/auto_task/intent_classifier.rs
+++ b/src/auto_task/intent_classifier.rs
@@ -4,6 +4,8 @@ use crate::basic::ScriptService;
use crate::shared::models::UserSession;
use crate::shared::state::AppState;
+#[cfg(feature = "llm")]
+use crate::core::config::ConfigManager;
use chrono::{DateTime, Utc};
use diesel::prelude::*;
use diesel::sql_query;
diff --git a/src/auto_task/intent_compiler.rs b/src/auto_task/intent_compiler.rs
index 3a055f4cc..37ebadb7a 100644
--- a/src/auto_task/intent_compiler.rs
+++ b/src/auto_task/intent_compiler.rs
@@ -1,6 +1,8 @@
use crate::shared::models::UserSession;
use crate::shared::state::AppState;
+#[cfg(feature = "llm")]
+use crate::core::config::ConfigManager;
use chrono::{DateTime, Utc};
use diesel::prelude::*;
use log::{error, info, trace, warn};
@@ -91,34 +93,28 @@ pub struct PlanStep {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum StepPriority {
Critical,
High,
+ #[default]
Medium,
Low,
Optional,
}
-impl Default for StepPriority {
- fn default() -> Self {
- Self::Medium
- }
-}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Default)]
pub enum RiskLevel {
None,
+ #[default]
Low,
Medium,
High,
Critical,
}
-impl Default for RiskLevel {
- fn default() -> Self {
- Self::Low
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiCallSpec {
@@ -132,7 +128,9 @@ pub struct ApiCallSpec {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Default)]
pub enum AuthType {
+ #[default]
None,
ApiKey {
header: String,
@@ -151,11 +149,6 @@ pub enum AuthType {
},
}
-impl Default for AuthType {
- fn default() -> Self {
- Self::None
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryConfig {
@@ -184,18 +177,15 @@ pub struct ApprovalLevel {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Default)]
pub enum DefaultApprovalAction {
Approve,
Reject,
Escalate,
+ #[default]
Pause,
}
-impl Default for DefaultApprovalAction {
- fn default() -> Self {
- Self::Pause
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AlternativeInterpretation {
diff --git a/src/auto_task/safety_layer.rs b/src/auto_task/safety_layer.rs
index 8ae6b1a82..6bd4f86f2 100644
--- a/src/auto_task/safety_layer.rs
+++ b/src/auto_task/safety_layer.rs
@@ -82,18 +82,15 @@ impl std::fmt::Display for ConstraintType {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
+#[derive(Default)]
pub enum ConstraintSeverity {
Info = 0,
+ #[default]
Warning = 1,
Error = 2,
Critical = 3,
}
-impl Default for ConstraintSeverity {
- fn default() -> Self {
- Self::Warning
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Constraint {
@@ -187,19 +184,16 @@ impl Default for ImpactAssessment {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
+#[derive(Default)]
pub enum RiskLevel {
None = 0,
+ #[default]
Low = 1,
Medium = 2,
High = 3,
Critical = 4,
}
-impl Default for RiskLevel {
- fn default() -> Self {
- Self::Low
- }
-}
impl std::fmt::Display for RiskLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -264,6 +258,7 @@ impl Default for CostImpact {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Default)]
pub struct TimeImpact {
pub estimated_duration_seconds: i32,
pub blocking: bool,
@@ -271,16 +266,6 @@ pub struct TimeImpact {
pub affects_deadline: bool,
}
-impl Default for TimeImpact {
- fn default() -> Self {
- Self {
- estimated_duration_seconds: 0,
- blocking: false,
- delayed_tasks: Vec::new(),
- affects_deadline: false,
- }
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityImpact {
diff --git a/src/auto_task/task_manifest.rs b/src/auto_task/task_manifest.rs
index e96ff6473..c4fb21236 100644
--- a/src/auto_task/task_manifest.rs
+++ b/src/auto_task/task_manifest.rs
@@ -36,7 +36,9 @@ pub struct DecisionPoint {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum ManifestStatus {
+ #[default]
Planning,
Ready,
Running,
@@ -45,11 +47,6 @@ pub enum ManifestStatus {
Failed,
}
-impl Default for ManifestStatus {
- fn default() -> Self {
- Self::Planning
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManifestSection {
@@ -100,7 +97,9 @@ impl std::fmt::Display for SectionType {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum SectionStatus {
+ #[default]
Pending,
Running,
Completed,
@@ -108,11 +107,6 @@ pub enum SectionStatus {
Skipped,
}
-impl Default for SectionStatus {
- fn default() -> Self {
- Self::Pending
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManifestItem {
@@ -182,7 +176,9 @@ pub enum ItemType {
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum ItemStatus {
+ #[default]
Pending,
Running,
Completed,
@@ -190,11 +186,6 @@ pub enum ItemStatus {
Skipped,
}
-impl Default for ItemStatus {
- fn default() -> Self {
- Self::Pending
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerminalLine {
@@ -476,7 +467,7 @@ impl TaskManifest {
"total": self.total_steps,
"percentage": self.progress_percentage()
},
- "sections": self.sections.iter().map(|s| section_to_web_json(s)).collect::>(),
+ "sections": self.sections.iter().map(section_to_web_json).collect::>(),
"terminal": {
"lines": self.terminal_output.iter().map(|l| serde_json::json!({
"content": l.content,
@@ -688,7 +679,7 @@ fn section_to_web_json(section: &ManifestSection) -> serde_json::Value {
"global_current": global_current,
"global_start": section.global_step_start
},
- "duration": section.duration_seconds.map(|d| format_duration(d)),
+ "duration": section.duration_seconds.map(format_duration),
"duration_seconds": section.duration_seconds,
"items": section.items.iter().map(|i| {
let item_checkbox = match i.status {
@@ -703,7 +694,7 @@ fn section_to_web_json(section: &ManifestSection) -> serde_json::Value {
"type": format!("{:?}", i.item_type),
"status": format!("{:?}", i.status),
"details": i.details,
- "duration": i.duration_seconds.map(|d| format_duration(d)),
+ "duration": i.duration_seconds.map(format_duration),
"duration_seconds": i.duration_seconds
})
}).collect::>(),
@@ -719,11 +710,11 @@ fn section_to_web_json(section: &ManifestSection) -> serde_json::Value {
"items": g.items,
"checkbox": group_checkbox,
"status": format!("{:?}", g.status),
- "duration": g.duration_seconds.map(|d| format_duration(d)),
+ "duration": g.duration_seconds.map(format_duration),
"duration_seconds": g.duration_seconds
})
}).collect::>(),
- "children": section.children.iter().map(|c| section_to_web_json(c)).collect::>()
+ "children": section.children.iter().map(section_to_web_json).collect::>()
})
}
diff --git a/src/auto_task/task_types.rs b/src/auto_task/task_types.rs
index e80198e21..f6da17936 100644
--- a/src/auto_task/task_types.rs
+++ b/src/auto_task/task_types.rs
@@ -73,7 +73,9 @@ pub struct AutoTask {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum AutoTaskStatus {
+ #[default]
Draft,
Compiling,
@@ -103,11 +105,6 @@ pub enum AutoTaskStatus {
RolledBack,
}
-impl Default for AutoTaskStatus {
- fn default() -> Self {
- Self::Draft
- }
-}
impl std::fmt::Display for AutoTaskStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -131,9 +128,11 @@ impl std::fmt::Display for AutoTaskStatus {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum ExecutionMode {
FullyAutomatic,
+ #[default]
SemiAutomatic,
Supervised,
@@ -143,26 +142,18 @@ pub enum ExecutionMode {
DryRun,
}
-impl Default for ExecutionMode {
- fn default() -> Self {
- Self::SemiAutomatic
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Ord, PartialOrd, Eq)]
+#[derive(Default)]
pub enum TaskPriority {
Critical = 4,
High = 3,
+ #[default]
Medium = 2,
Low = 1,
Background = 0,
}
-impl Default for TaskPriority {
- fn default() -> Self {
- Self::Medium
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StepExecutionResult {
@@ -258,18 +249,15 @@ pub struct ImpactEstimate {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Default)]
pub enum TimeoutAction {
UseDefault,
+ #[default]
Pause,
Cancel,
Escalate,
}
-impl Default for TimeoutAction {
- fn default() -> Self {
- Self::Pause
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PendingApproval {
@@ -300,33 +288,27 @@ pub enum ApprovalType {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Default)]
pub enum ApprovalDefault {
Approve,
Reject,
+ #[default]
Pause,
Escalate,
}
-impl Default for ApprovalDefault {
- fn default() -> Self {
- Self::Pause
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Ord, PartialOrd, Eq)]
+#[derive(Default)]
pub enum RiskLevel {
None = 0,
+ #[default]
Low = 1,
Medium = 2,
High = 3,
Critical = 4,
}
-impl Default for RiskLevel {
- fn default() -> Self {
- Self::Low
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiskSummary {
@@ -396,6 +378,7 @@ pub struct TaskError {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Default)]
pub struct RollbackState {
pub available: bool,
pub steps_rolled_back: Vec,
@@ -404,17 +387,6 @@ pub struct RollbackState {
pub completed_at: Option>,
}
-impl Default for RollbackState {
- fn default() -> Self {
- Self {
- available: false,
- steps_rolled_back: Vec::new(),
- rollback_data: HashMap::new(),
- started_at: None,
- completed_at: None,
- }
- }
-}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaskSchedule {
diff --git a/src/basic/compiler/mod.rs b/src/basic/compiler/mod.rs
index 9b2c2a9f7..84ce2c25a 100644
--- a/src/basic/compiler/mod.rs
+++ b/src/basic/compiler/mod.rs
@@ -354,18 +354,22 @@ impl BasicCompiler {
has_schedule = true;
let parts: Vec<&str> = normalized.split('"').collect();
if parts.len() >= 3 {
- let cron = parts[1];
- let mut conn = self
- .state
- .conn
- .get()
- .map_err(|e| format!("Failed to get database connection: {e}"))?;
#[cfg(feature = "tasks")]
- if let Err(e) = execute_set_schedule(&mut conn, cron, &script_name, bot_id) {
- log::error!(
- "Failed to schedule SET SCHEDULE during preprocessing: {}",
- e
- );
+ {
+ #[allow(unused_variables, unused_mut)]
+ let cron = parts[1];
+ #[allow(unused_variables, unused_mut)]
+ let mut conn = self
+ .state
+ .conn
+ .get()
+ .map_err(|e| format!("Failed to get database connection: {e}"))?;
+ if let Err(e) = execute_set_schedule(&mut conn, cron, &script_name, bot_id) {
+ log::error!(
+ "Failed to schedule SET SCHEDULE during preprocessing: {}",
+ e
+ );
+ }
}
#[cfg(not(feature = "tasks"))]
log::warn!("SET SCHEDULE requires 'tasks' feature - ignoring");
diff --git a/src/basic/keywords/add_bot.rs b/src/basic/keywords/add_bot.rs
index e369df751..4c21d2c75 100644
--- a/src/basic/keywords/add_bot.rs
+++ b/src/basic/keywords/add_bot.rs
@@ -594,7 +594,7 @@ fn add_bot_to_session(
.map_err(|e| format!("Failed to get bot ID: {e}"))?
} else {
let new_bot_id = Uuid::new_v4();
- let db_name = format!("bot_{}", bot_name.replace('-', "_").replace(' ', "_").to_lowercase());
+ let db_name = format!("bot_{}", bot_name.replace(['-', ' '], "_").to_lowercase());
diesel::sql_query(
"INSERT INTO bots (id, name, description, is_active, database_name, created_at)
VALUES ($1, $2, $3, true, $4, NOW())
@@ -608,7 +608,7 @@ fn add_bot_to_session(
.execute(&mut *conn)
.map_err(|e| format!("Failed to create bot: {e}"))?;
- if let Err(e) = create_bot_database(&mut *conn, &db_name) {
+ if let Err(e) = create_bot_database(&mut conn, &db_name) {
log::warn!("Failed to create database for bot {bot_name}: {e}");
}
diff --git a/src/basic/keywords/agent_reflection.rs b/src/basic/keywords/agent_reflection.rs
index 2ba061a61..8c81c57b9 100644
--- a/src/basic/keywords/agent_reflection.rs
+++ b/src/basic/keywords/agent_reflection.rs
@@ -9,7 +9,9 @@ use std::sync::Arc;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum ReflectionType {
+ #[default]
ConversationQuality,
ResponseAccuracy,
ToolUsage,
@@ -18,11 +20,6 @@ pub enum ReflectionType {
Custom(String),
}
-impl Default for ReflectionType {
- fn default() -> Self {
- Self::ConversationQuality
- }
-}
impl From<&str> for ReflectionType {
fn from(s: &str) -> Self {
diff --git a/src/basic/keywords/api_tool_generator.rs b/src/basic/keywords/api_tool_generator.rs
index 828f78b98..046243704 100644
--- a/src/basic/keywords/api_tool_generator.rs
+++ b/src/basic/keywords/api_tool_generator.rs
@@ -182,7 +182,7 @@ impl ApiToolGenerator {
let mut generated_count = 0;
for endpoint in &endpoints {
- let bas_content = Self::generate_bas_file(&api_name, endpoint)?;
+ let bas_content = Self::generate_bas_file(api_name, endpoint)?;
let file_path = format!("{}/{}.bas", api_folder, endpoint.operation_id);
std::fs::write(&file_path, &bas_content)
diff --git a/src/basic/keywords/app_server.rs b/src/basic/keywords/app_server.rs
index 46371ebbf..270941dfb 100644
--- a/src/basic/keywords/app_server.rs
+++ b/src/basic/keywords/app_server.rs
@@ -103,7 +103,7 @@ pub async fn serve_vendor_file(
let bot_name = state.bucket_name
.trim_end_matches(".gbai")
.to_string();
- let sanitized_bot_name = bot_name.to_lowercase().replace(' ', "-").replace('_', "-");
+ let sanitized_bot_name = bot_name.to_lowercase().replace([' ', '_'], "-");
let bucket = format!("{}.gbai", sanitized_bot_name);
let key = format!("{}.gblib/vendor/{}", sanitized_bot_name, file_path);
@@ -243,7 +243,7 @@ async fn serve_app_file_internal(state: &AppState, app_name: &str, file_path: &s
let bot_name = state.bucket_name
.trim_end_matches(".gbai")
.to_string();
- let sanitized_bot_name = bot_name.to_lowercase().replace(' ', "-").replace('_', "-");
+ let sanitized_bot_name = bot_name.to_lowercase().replace([' ', '_'], "-");
// MinIO bucket and path: botname.gbai / botname.gbapp/appname/file
let bucket = format!("{}.gbai", sanitized_bot_name);
diff --git a/src/basic/keywords/code_sandbox.rs b/src/basic/keywords/code_sandbox.rs
index 5063834b7..ee5f4890c 100644
--- a/src/basic/keywords/code_sandbox.rs
+++ b/src/basic/keywords/code_sandbox.rs
@@ -12,6 +12,7 @@ use tokio::time::timeout;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Default)]
pub enum SandboxRuntime {
LXC,
@@ -19,14 +20,10 @@ pub enum SandboxRuntime {
Firecracker,
+ #[default]
Process,
}
-impl Default for SandboxRuntime {
- fn default() -> Self {
- Self::Process
- }
-}
impl From<&str> for SandboxRuntime {
fn from(s: &str) -> Self {
@@ -340,8 +337,8 @@ impl CodeSandbox {
.and_then(|c| c.arg(&code_file));
match cmd_result {
- Ok(cmd) => cmd.execute_async().await.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
- Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
+ Ok(cmd) => cmd.execute_async().await.map_err(|e| std::io::Error::other(e.to_string())),
+ Err(e) => Err(std::io::Error::other(e.to_string())),
}
})
.await;
@@ -409,8 +406,8 @@ impl CodeSandbox {
.and_then(|c| c.args(&args.iter().map(|s| s.as_str()).collect::>()));
match cmd_result {
- Ok(cmd) => cmd.execute_async().await.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
- Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
+ Ok(cmd) => cmd.execute_async().await.map_err(|e| std::io::Error::other(e.to_string())),
+ Err(e) => Err(std::io::Error::other(e.to_string())),
}
})
.await;
@@ -471,8 +468,8 @@ impl CodeSandbox {
.and_then(|c| c.working_dir(std::path::Path::new(&temp_dir)));
match cmd_result {
- Ok(cmd) => cmd.execute_async().await.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
- Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
+ Ok(cmd) => cmd.execute_async().await.map_err(|e| std::io::Error::other(e.to_string())),
+ Err(e) => Err(std::io::Error::other(e.to_string())),
}
})
.await;
diff --git a/src/basic/keywords/create_site.rs b/src/basic/keywords/create_site.rs
index d058be537..ebbdcb147 100644
--- a/src/basic/keywords/create_site.rs
+++ b/src/basic/keywords/create_site.rs
@@ -3,6 +3,8 @@ use crate::llm::LLMProvider;
use crate::shared::models::UserSession;
use crate::shared::state::AppState;
use log::{debug, info};
+#[cfg(feature = "llm")]
+use log::warn;
use rhai::Dynamic;
use rhai::Engine;
#[cfg(feature = "llm")]
diff --git a/src/basic/keywords/create_task.rs b/src/basic/keywords/create_task.rs
index a4a530da3..cf154fa3c 100644
--- a/src/basic/keywords/create_task.rs
+++ b/src/basic/keywords/create_task.rs
@@ -368,7 +368,7 @@ fn parse_due_date(due_date: &str) -> Result