diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d2f8fbb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,149 @@ +name: CI + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + lint: + name: Lint & Format Check + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: desktop/pnpm-lock.yaml + + - name: Cache Cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + - name: Check Rust formatting + working-directory: . + run: cargo fmt --check --all + + - name: Rust Clippy + working-directory: . + run: cargo clippy --workspace -- -D warnings + + - name: Install frontend dependencies + working-directory: desktop + run: pnpm install --frozen-lockfile + + - name: TypeScript type check + working-directory: desktop + run: pnpm tsc --noEmit + + test: + name: Test + runs-on: windows-latest + needs: lint + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: desktop/pnpm-lock.yaml + + - name: Cache Cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + - name: Run Rust tests + working-directory: . + run: cargo test --workspace + + - name: Install frontend dependencies + working-directory: desktop + run: pnpm install --frozen-lockfile + + - name: Run frontend unit tests + working-directory: desktop + run: pnpm vitest run + + build: + name: Build + runs-on: windows-latest + needs: test + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: desktop/pnpm-lock.yaml + + - name: Cache Cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + - name: Rust release build + working-directory: . + run: cargo build --release --workspace + + - name: Install frontend dependencies + working-directory: desktop + run: pnpm install --frozen-lockfile + + - name: Frontend production build + working-directory: desktop + run: pnpm build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..db5d545 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,74 @@ +name: Release + +on: + push: + tags: + - 'v*' + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + release: + name: Build & Release + runs-on: windows-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: desktop/pnpm-lock.yaml + + - name: Cache Cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + - name: Run Rust tests + working-directory: . + run: cargo test --workspace + + - name: Install frontend dependencies + working-directory: desktop + run: pnpm install --frozen-lockfile + + - name: Run frontend tests + working-directory: desktop + run: pnpm vitest run + + - name: Build Tauri application + uses: tauri-apps/tauri-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + projectPath: desktop + tagName: ${{ github.ref_name }} + releaseName: 'ZCLAW ${{ github.ref_name }}' + releaseBody: 'See the assets to download and install this version.' + releaseDraft: true + prerelease: false + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: windows-installer + path: desktop/src-tauri/target/release/bundle/nsis/*.exe diff --git a/.gitignore b/.gitignore index 965793b..2d8faef 100644 --- a/.gitignore +++ b/.gitignore @@ -40,9 +40,21 @@ desktop/src-tauri/binaries/ *.exe *.pdb -#test +# Test desktop/test-results/ +desktop/tests/e2e/test-results/ +desktop/coverage/ .gstack/ .trae/ target/debug/ target/release/ + +# Coverage +coverage/ +*.lcov + +# Session plans +plans/ + +# Build artifacts +desktop/msi-smoke/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fbf15dc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,65 @@ +# Changelog + +All notable changes to ZCLAW will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] - 2026-03-26 + +### Added + +#### 核心功能 +- 多模型 AI 对话,支持流式响应(Anthropic、OpenAI 兼容) +- Agent 分身管理(创建、配置、切换) +- Hands 自主能力(Browser、Collector、Researcher、Predictor、Lead、Clip、Twitter、Whiteboard、Slideshow、Speech、Quiz) +- 可视化工作流编辑器(React Flow) +- 技能系统(SKILL.md 定义) +- Agent Growth 记忆系统(语义提取、检索、注入) +- Pipeline 执行引擎(条件分支、并行执行) +- MCP 协议支持 +- A2A 进程内通信 +- OS Keyring 安全存储 +- 加密聊天存储 +- 离线消息队列 +- 浏览器自动化 + +#### 安全 +- Content Security Policy 启用 +- Web fetch SSRF 防护 +- 路径验证(default-deny 策略) +- Shell 命令白名单和危险命令黑名单 +- API Key 通过 secrecy crate 保护 + +#### 基础设施 +- GitHub Actions CI 流水线(lint、test、build) +- GitHub Actions Release 流水线(tag 触发、NSIS 安装包) +- Workspace 统一版本管理 + +### Removed +- Valtio/XState 双轨状态管理层(未完成的迁移) +- Stub Channel 适配器(Telegram、Discord、Slack) +- 未使用的 Store(meshStore、personaStore) +- 不完整的 ActiveLearningPanel 和 skillMarketStore +- 调试日志清理(~310 处 console/println 语句) + +--- + +## 版本说明 + +### 版本号格式 + +- **主版本号**: 重大架构变更或不兼容的 API 修改 +- **次版本号**: 向后兼容的功能新增 +- **修订号**: 向后兼容的问题修复 + +### 变更类型 + +- `Added`: 新增功能 +- `Changed`: 功能变更 +- `Deprecated`: 即将废弃的功能 +- `Removed`: 已移除的功能 +- `Fixed`: 问题修复 +- `Security`: 安全相关修复 diff --git a/CLAUDE.md b/CLAUDE.md index ac50af9..959d57d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -175,13 +175,13 @@ Client → 负责网络通信和``` | 分身管理 | ✅ 完成 | 创建、配置、切换 Agent | | 自动化面板 | ✅ 完成 | Hands 触发、参数配置 | | 技能市场 | 🚧 进行中 | 技能浏览和安装 | -| 工作流编辑 | 📋 计划中 | 多步骤任务编排 | +| 工作流编辑 | 🚧 进行中 | Pipeline 工作流编辑器 | --- ## 6. 自主能力系统 (Hands) -ZCLAW 提供 8 个自主能力包: +ZCLAW 提供 11 个自主能力包: | Hand | 功能 | 状态 | |------|------|------| @@ -190,9 +190,12 @@ ZCLAW 提供 8 个自主能力包: | Researcher | 深度研究 | ✅ 可用 | | Predictor | 预测分析 | ✅ 可用 | | Lead | 销售线索发现 | ✅ 可用 | -| Trader | 交易分析 | ✅ 可用 | | Clip | 视频处理 | ⚠️ 需 FFmpeg | | Twitter | Twitter 自动化 | ⚠️ 需 API Key | +| Whiteboard | 白板演示 | ✅ 可用 | +| Slideshow | 幻灯片生成 | ✅ 可用 | +| Speech | 语音合成 | ✅ 可用 | +| Quiz | 测验生成 | ✅ 可用 | **触发 Hand 时:** 1. 检查依赖是否满足 diff --git a/Cargo.lock b/Cargo.lock index a642e7f..3ce1342 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7105,6 +7105,7 @@ dependencies = [ "regex", "serde", "serde_json", + "shlex", "thiserror 2.0.18", "tokio", "tracing", diff --git a/crates/zclaw-channels/src/adapters/discord.rs b/crates/zclaw-channels/src/adapters/discord.rs deleted file mode 100644 index 30ff421..0000000 --- a/crates/zclaw-channels/src/adapters/discord.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Discord channel adapter - -use async_trait::async_trait; -use std::sync::Arc; -use tokio::sync::mpsc; -use zclaw_types::Result; - -use crate::{Channel, ChannelConfig, ChannelStatus, IncomingMessage, OutgoingMessage}; - -/// Discord channel adapter -pub struct DiscordChannel { - config: ChannelConfig, - status: Arc>, -} - -impl DiscordChannel { - pub fn new(config: ChannelConfig) -> Self { - Self { - config, - status: Arc::new(tokio::sync::RwLock::new(ChannelStatus::Disconnected)), - } - } -} - -#[async_trait] -impl Channel for DiscordChannel { - fn config(&self) -> &ChannelConfig { - &self.config - } - - async fn connect(&self) -> Result<()> { - let mut status = self.status.write().await; - *status = ChannelStatus::Connected; - Ok(()) - } - - async fn disconnect(&self) -> Result<()> { - let mut status = self.status.write().await; - *status = ChannelStatus::Disconnected; - Ok(()) - } - - async fn status(&self) -> ChannelStatus { - self.status.read().await.clone() - } - - async fn send(&self, _message: OutgoingMessage) -> Result { - // TODO: Implement Discord API send - Ok("discord_msg_id".to_string()) - } - - async fn receive(&self) -> Result> { - let (_tx, rx) = mpsc::channel(100); - // TODO: Implement Discord gateway - Ok(rx) - } -} diff --git a/crates/zclaw-channels/src/adapters/mod.rs b/crates/zclaw-channels/src/adapters/mod.rs index ccbc718..3fc8260 100644 --- a/crates/zclaw-channels/src/adapters/mod.rs +++ b/crates/zclaw-channels/src/adapters/mod.rs @@ -1,11 +1,5 @@ //! Channel adapters -mod telegram; -mod discord; -mod slack; mod console; -pub use telegram::TelegramChannel; -pub use discord::DiscordChannel; -pub use slack::SlackChannel; pub use console::ConsoleChannel; diff --git a/crates/zclaw-channels/src/adapters/slack.rs b/crates/zclaw-channels/src/adapters/slack.rs deleted file mode 100644 index 6dd8323..0000000 --- a/crates/zclaw-channels/src/adapters/slack.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Slack channel adapter - -use async_trait::async_trait; -use std::sync::Arc; -use tokio::sync::mpsc; -use zclaw_types::Result; - -use crate::{Channel, ChannelConfig, ChannelStatus, IncomingMessage, OutgoingMessage}; - -/// Slack channel adapter -pub struct SlackChannel { - config: ChannelConfig, - status: Arc>, -} - -impl SlackChannel { - pub fn new(config: ChannelConfig) -> Self { - Self { - config, - status: Arc::new(tokio::sync::RwLock::new(ChannelStatus::Disconnected)), - } - } -} - -#[async_trait] -impl Channel for SlackChannel { - fn config(&self) -> &ChannelConfig { - &self.config - } - - async fn connect(&self) -> Result<()> { - let mut status = self.status.write().await; - *status = ChannelStatus::Connected; - Ok(()) - } - - async fn disconnect(&self) -> Result<()> { - let mut status = self.status.write().await; - *status = ChannelStatus::Disconnected; - Ok(()) - } - - async fn status(&self) -> ChannelStatus { - self.status.read().await.clone() - } - - async fn send(&self, _message: OutgoingMessage) -> Result { - // TODO: Implement Slack API send - Ok("slack_msg_ts".to_string()) - } - - async fn receive(&self) -> Result> { - let (_tx, rx) = mpsc::channel(100); - // TODO: Implement Slack RTM/events API - Ok(rx) - } -} diff --git a/crates/zclaw-channels/src/adapters/telegram.rs b/crates/zclaw-channels/src/adapters/telegram.rs deleted file mode 100644 index 3771f1c..0000000 --- a/crates/zclaw-channels/src/adapters/telegram.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Telegram channel adapter - -use async_trait::async_trait; -use std::sync::Arc; -use tokio::sync::mpsc; -use zclaw_types::Result; - -use crate::{Channel, ChannelConfig, ChannelStatus, IncomingMessage, OutgoingMessage}; - -/// Telegram channel adapter -pub struct TelegramChannel { - config: ChannelConfig, - #[allow(dead_code)] // TODO: Implement Telegram API client - client: Option, - status: Arc>, -} - -impl TelegramChannel { - pub fn new(config: ChannelConfig) -> Self { - Self { - config, - client: None, - status: Arc::new(tokio::sync::RwLock::new(ChannelStatus::Disconnected)), - } - } -} - -#[async_trait] -impl Channel for TelegramChannel { - fn config(&self) -> &ChannelConfig { - &self.config - } - - async fn connect(&self) -> Result<()> { - let mut status = self.status.write().await; - *status = ChannelStatus::Connected; - Ok(()) - } - - async fn disconnect(&self) -> Result<()> { - let mut status = self.status.write().await; - *status = ChannelStatus::Disconnected; - Ok(()) - } - - async fn status(&self) -> ChannelStatus { - self.status.read().await.clone() - } - - async fn send(&self, _message: OutgoingMessage) -> Result { - // TODO: Implement Telegram API send - Ok("telegram_msg_id".to_string()) - } - - async fn receive(&self) -> Result> { - let (_tx, rx) = mpsc::channel(100); - // TODO: Implement Telegram webhook/polling - Ok(rx) - } -} diff --git a/crates/zclaw-growth/src/retrieval/semantic.rs b/crates/zclaw-growth/src/retrieval/semantic.rs index 8d951da..951aaf9 100644 --- a/crates/zclaw-growth/src/retrieval/semantic.rs +++ b/crates/zclaw-growth/src/retrieval/semantic.rs @@ -3,11 +3,35 @@ //! Provides TF-IDF based semantic similarity computation for memory retrieval. //! This is a lightweight, dependency-free implementation suitable for //! medium-scale memory systems. +//! +//! Supports optional embedding API integration for improved semantic search. use std::collections::{HashMap, HashSet}; +use std::sync::Arc; use crate::types::MemoryEntry; -/// Semantic similarity scorer using TF-IDF +/// Embedding client trait for API integration +#[async_trait::async_trait] +pub trait EmbeddingClient: Send + Sync { + async fn embed(&self, text: &str) -> Result, String>; + fn is_available(&self) -> bool; +} + +/// No-op embedding client (uses TF-IDF only) +pub struct NoOpEmbeddingClient; + +#[async_trait::async_trait] +impl EmbeddingClient for NoOpEmbeddingClient { + async fn embed(&self, _text: &str) -> Result, String> { + Err("Embedding not configured".to_string()) + } + + fn is_available(&self) -> bool { + false + } +} + +/// Semantic similarity scorer using TF-IDF with optional embedding support pub struct SemanticScorer { /// Document frequency for IDF computation document_frequencies: HashMap, @@ -15,8 +39,14 @@ pub struct SemanticScorer { total_documents: usize, /// Precomputed TF-IDF vectors for entries entry_vectors: HashMap>, + /// Precomputed embedding vectors for entries + entry_embeddings: HashMap>, /// Stop words to ignore stop_words: HashSet, + /// Optional embedding client + embedding_client: Arc, + /// Whether to use embedding for similarity + use_embedding: bool, } impl SemanticScorer { @@ -26,10 +56,41 @@ impl SemanticScorer { document_frequencies: HashMap::new(), total_documents: 0, entry_vectors: HashMap::new(), + entry_embeddings: HashMap::new(), stop_words: Self::default_stop_words(), + embedding_client: Arc::new(NoOpEmbeddingClient), + use_embedding: false, } } + /// Create a new semantic scorer with embedding client + pub fn with_embedding(client: Arc) -> Self { + Self { + document_frequencies: HashMap::new(), + total_documents: 0, + entry_vectors: HashMap::new(), + entry_embeddings: HashMap::new(), + stop_words: Self::default_stop_words(), + embedding_client: client, + use_embedding: true, + } + } + + /// Set whether to use embedding for similarity + pub fn set_use_embedding(&mut self, use_embedding: bool) { + self.use_embedding = use_embedding && self.embedding_client.is_available(); + } + + /// Check if embedding is available + pub fn is_embedding_available(&self) -> bool { + self.embedding_client.is_available() + } + + /// Get the embedding client + pub fn get_embedding_client(&self) -> Arc { + self.embedding_client.clone() + } + /// Get default stop words fn default_stop_words() -> HashSet { [ @@ -132,9 +193,34 @@ impl SemanticScorer { self.entry_vectors.insert(entry.uri.clone(), tfidf); } + /// Index an entry with embedding (async) + pub async fn index_entry_with_embedding(&mut self, entry: &MemoryEntry) { + // First do TF-IDF indexing + self.index_entry(entry); + + // Then compute embedding if available + if self.use_embedding && self.embedding_client.is_available() { + let text_to_embed = if !entry.keywords.is_empty() { + format!("{} {}", entry.content, entry.keywords.join(" ")) + } else { + entry.content.clone() + }; + + match self.embedding_client.embed(&text_to_embed).await { + Ok(embedding) => { + self.entry_embeddings.insert(entry.uri.clone(), embedding); + } + Err(e) => { + tracing::warn!("[SemanticScorer] Failed to compute embedding for {}: {}", entry.uri, e); + } + } + } + } + /// Remove an entry from the index pub fn remove_entry(&mut self, uri: &str) { self.entry_vectors.remove(uri); + self.entry_embeddings.remove(uri); } /// Compute cosine similarity between two vectors @@ -167,6 +253,57 @@ impl SemanticScorer { } } + /// Compute cosine similarity between two embedding vectors + fn cosine_similarity_embedding(v1: &[f32], v2: &[f32]) -> f32 { + if v1.is_empty() || v2.is_empty() || v1.len() != v2.len() { + return 0.0; + } + + let mut dot_product = 0.0; + let mut norm1 = 0.0; + let mut norm2 = 0.0; + + for i in 0..v1.len() { + dot_product += v1[i] * v2[i]; + norm1 += v1[i] * v1[i]; + norm2 += v2[i] * v2[i]; + } + + let denom = (norm1 * norm2).sqrt(); + if denom == 0.0 { + 0.0 + } else { + (dot_product / denom).clamp(0.0, 1.0) + } + } + + /// Score similarity between query and entry using embedding (async) + pub async fn score_similarity_with_embedding(&self, query: &str, entry: &MemoryEntry) -> f32 { + // If we have precomputed embedding for this entry and embedding is enabled + if self.use_embedding && self.embedding_client.is_available() { + if let Some(entry_embedding) = self.entry_embeddings.get(&entry.uri) { + // Compute query embedding + match self.embedding_client.embed(query).await { + Ok(query_embedding) => { + let embedding_score = Self::cosine_similarity_embedding(&query_embedding, entry_embedding); + + // Also compute TF-IDF score for hybrid approach + let tfidf_score = self.score_similarity(query, entry); + + // Weighted combination: 70% embedding, 30% TF-IDF + return embedding_score * 0.7 + tfidf_score * 0.3; + } + Err(e) => { + tracing::debug!("[SemanticScorer] Failed to embed query: {}", e); + } + } + } + } + + // Fall back to TF-IDF + self.score_similarity(query, entry) + } + /// Score similarity between query and entry pub fn score_similarity(&self, query: &str, entry: &MemoryEntry) -> f32 { // Tokenize query @@ -246,6 +383,7 @@ impl SemanticScorer { self.document_frequencies.clear(); self.total_documents = 0; self.entry_vectors.clear(); + self.entry_embeddings.clear(); } /// Get statistics about the index @@ -254,6 +392,8 @@ impl SemanticScorer { total_documents: self.total_documents, unique_terms: self.document_frequencies.len(), indexed_entries: self.entry_vectors.len(), + embedding_entries: self.entry_embeddings.len(), + use_embedding: self.use_embedding && self.embedding_client.is_available(), } } } @@ -270,6 +410,8 @@ pub struct IndexStats { pub total_documents: usize, pub unique_terms: usize, pub indexed_entries: usize, + pub embedding_entries: usize, + pub use_embedding: bool, } #[cfg(test)] diff --git a/crates/zclaw-kernel/src/config.rs b/crates/zclaw-kernel/src/config.rs index fa9f761..4d4308f 100644 --- a/crates/zclaw-kernel/src/config.rs +++ b/crates/zclaw-kernel/src/config.rs @@ -168,7 +168,7 @@ fn default_skills_dir() -> Option { // 1. Check environment variable override if let Ok(dir) = std::env::var("ZCLAW_SKILLS_DIR") { let path = std::path::PathBuf::from(&dir); - eprintln!("[default_skills_dir] ZCLAW_SKILLS_DIR env: {} (exists: {})", path.display(), path.exists()); + tracing::debug!(target: "kernel_config", "ZCLAW_SKILLS_DIR env: {} (exists: {})", path.display(), path.exists()); if path.exists() { return Some(path); } @@ -180,12 +180,12 @@ fn default_skills_dir() -> Option { // CARGO_MANIFEST_DIR is the crate directory (crates/zclaw-kernel) // We need to go up to find the workspace root let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - eprintln!("[default_skills_dir] CARGO_MANIFEST_DIR: {}", manifest_dir.display()); + tracing::debug!(target: "kernel_config", "CARGO_MANIFEST_DIR: {}", manifest_dir.display()); // Go up from crates/zclaw-kernel to workspace root if let Some(workspace_root) = manifest_dir.parent().and_then(|p| p.parent()) { let workspace_skills = workspace_root.join("skills"); - eprintln!("[default_skills_dir] Workspace skills: {} (exists: {})", workspace_skills.display(), workspace_skills.exists()); + tracing::debug!(target: "kernel_config", "Workspace skills: {} (exists: {})", workspace_skills.display(), workspace_skills.exists()); if workspace_skills.exists() { return Some(workspace_skills); } @@ -194,7 +194,7 @@ fn default_skills_dir() -> Option { // 3. Try current working directory first (for development) if let Ok(cwd) = std::env::current_dir() { let cwd_skills = cwd.join("skills"); - eprintln!("[default_skills_dir] Checking cwd: {} (exists: {})", cwd_skills.display(), cwd_skills.exists()); + tracing::debug!(target: "kernel_config", "Checking cwd: {} (exists: {})", cwd_skills.display(), cwd_skills.exists()); if cwd_skills.exists() { return Some(cwd_skills); } @@ -204,7 +204,7 @@ fn default_skills_dir() -> Option { for i in 0..6 { if let Some(parent) = current.parent() { let parent_skills = parent.join("skills"); - eprintln!("[default_skills_dir] CWD Level {}: {} (exists: {})", i, parent_skills.display(), parent_skills.exists()); + tracing::debug!(target: "kernel_config", "CWD Level {}: {} (exists: {})", i, parent_skills.display(), parent_skills.exists()); if parent_skills.exists() { return Some(parent_skills); } @@ -217,11 +217,11 @@ fn default_skills_dir() -> Option { // 4. Try executable's directory and multiple levels up if let Ok(exe) = std::env::current_exe() { - eprintln!("[default_skills_dir] Current exe: {}", exe.display()); + tracing::debug!(target: "kernel_config", "Current exe: {}", exe.display()); if let Some(exe_dir) = exe.parent().map(|p| p.to_path_buf()) { // Same directory as exe let exe_skills = exe_dir.join("skills"); - eprintln!("[default_skills_dir] Checking exe dir: {} (exists: {})", exe_skills.display(), exe_skills.exists()); + tracing::debug!(target: "kernel_config", "Checking exe dir: {} (exists: {})", exe_skills.display(), exe_skills.exists()); if exe_skills.exists() { return Some(exe_skills); } @@ -231,7 +231,7 @@ fn default_skills_dir() -> Option { for i in 0..6 { if let Some(parent) = current.parent() { let parent_skills = parent.join("skills"); - eprintln!("[default_skills_dir] EXE Level {}: {} (exists: {})", i, parent_skills.display(), parent_skills.exists()); + tracing::debug!(target: "kernel_config", "EXE Level {}: {} (exists: {})", i, parent_skills.display(), parent_skills.exists()); if parent_skills.exists() { return Some(parent_skills); } @@ -247,7 +247,7 @@ fn default_skills_dir() -> Option { let fallback = std::env::current_dir() .ok() .map(|cwd| cwd.join("skills")); - eprintln!("[default_skills_dir] Fallback to: {:?}", fallback); + tracing::debug!(target: "kernel_config", "Fallback to: {:?}", fallback); fallback } diff --git a/crates/zclaw-kernel/src/kernel.rs b/crates/zclaw-kernel/src/kernel.rs index 7598c33..e2e503f 100644 --- a/crates/zclaw-kernel/src/kernel.rs +++ b/crates/zclaw-kernel/src/kernel.rs @@ -129,9 +129,9 @@ impl Kernel { } /// Build a system prompt with skill information injected - fn build_system_prompt_with_skills(&self, base_prompt: Option<&String>) -> String { - // Get skill list synchronously (we're in sync context) - let skills = futures::executor::block_on(self.skills.list()); + async fn build_system_prompt_with_skills(&self, base_prompt: Option<&String>) -> String { + // Get skill list asynchronously + let skills = self.skills.list().await; let mut prompt = base_prompt .map(|p| p.clone()) @@ -309,7 +309,7 @@ impl Kernel { .with_temperature(agent_config.temperature.unwrap_or_else(|| self.config.temperature())); // Build system prompt with skill information injected - let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref()); + let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref()).await; let loop_runner = loop_runner.with_system_prompt(&system_prompt); // Run the loop @@ -352,7 +352,7 @@ impl Kernel { .with_temperature(agent_config.temperature.unwrap_or_else(|| self.config.temperature())); // Build system prompt with skill information injected - let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref()); + let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref()).await; let loop_runner = loop_runner.with_system_prompt(&system_prompt); // Run with streaming diff --git a/crates/zclaw-memory/src/store.rs b/crates/zclaw-memory/src/store.rs index 5f1a97b..5e920e3 100644 --- a/crates/zclaw-memory/src/store.rs +++ b/crates/zclaw-memory/src/store.rs @@ -26,7 +26,10 @@ impl MemoryStore { // Parse SQLite URL to extract file path // Format: sqlite:/path/to/db or sqlite://path/to/db if database_url.starts_with("sqlite:") { - let path_part = database_url.strip_prefix("sqlite:").unwrap(); + let path_part = database_url.strip_prefix("sqlite:") + .ok_or_else(|| ZclawError::StorageError( + format!("Invalid database URL format: {}", database_url) + ))?; // Skip in-memory databases if path_part == ":memory:" { @@ -34,7 +37,10 @@ impl MemoryStore { } // Remove query parameters (e.g., ?mode=rwc) - let path_without_query = path_part.split('?').next().unwrap(); + let path_without_query = path_part.split('?').next() + .ok_or_else(|| ZclawError::StorageError( + format!("Invalid database URL path: {}", path_part) + ))?; // Handle both absolute and relative paths let path = std::path::Path::new(path_without_query); diff --git a/crates/zclaw-pipeline/src/actions/export.rs b/crates/zclaw-pipeline/src/actions/export.rs index 7fb168e..02d6842 100644 --- a/crates/zclaw-pipeline/src/actions/export.rs +++ b/crates/zclaw-pipeline/src/actions/export.rs @@ -103,6 +103,22 @@ fn render_markdown(data: &Value) -> String { md } +/// Escape HTML special characters to prevent XSS +fn escape_html(s: &str) -> String { + let mut escaped = String::with_capacity(s.len()); + for ch in s.chars() { + match ch { + '<' => escaped.push_str("<"), + '>' => escaped.push_str(">"), + '&' => escaped.push_str("&"), + '"' => escaped.push_str("""), + '\'' => escaped.push_str("'"), + _ => escaped.push(ch), + } + } + escaped +} + /// Render data to HTML fn render_html(data: &Value) -> String { let mut html = String::from(r#" @@ -123,11 +139,11 @@ fn render_html(data: &Value) -> String { "#); if let Some(title) = data.get("title").and_then(|v| v.as_str()) { - html.push_str(&format!("

{}

", title)); + html.push_str(&format!("

{}

", escape_html(title))); } if let Some(description) = data.get("description").and_then(|v| v.as_str()) { - html.push_str(&format!("

{}

", description)); + html.push_str(&format!("

{}

", escape_html(description))); } if let Some(outline) = data.get("outline") { @@ -135,7 +151,7 @@ fn render_html(data: &Value) -> String { if let Some(items) = outline.get("items").and_then(|v| v.as_array()) { for item in items { if let Some(text) = item.get("title").and_then(|v| v.as_str()) { - html.push_str(&format!("
  • {}
  • ", text)); + html.push_str(&format!("
  • {}
  • ", escape_html(text))); } } } @@ -147,10 +163,10 @@ fn render_html(data: &Value) -> String { for scene in scenes { html.push_str("
    "); if let Some(title) = scene.get("title").and_then(|v| v.as_str()) { - html.push_str(&format!("

    {}

    ", title)); + html.push_str(&format!("

    {}

    ", escape_html(title))); } if let Some(content) = scene.get("content").and_then(|v| v.as_str()) { - html.push_str(&format!("

    {}

    ", content)); + html.push_str(&format!("

    {}

    ", escape_html(content))); } html.push_str("
    "); } diff --git a/crates/zclaw-pipeline/src/actions/mod.rs b/crates/zclaw-pipeline/src/actions/mod.rs index ae44e10..63de029 100644 --- a/crates/zclaw-pipeline/src/actions/mod.rs +++ b/crates/zclaw-pipeline/src/actions/mod.rs @@ -134,10 +134,10 @@ impl ActionRegistry { max_tokens: Option, json_mode: bool, ) -> Result { - println!("[DEBUG execute_llm] Called with template length: {}", template.len()); - println!("[DEBUG execute_llm] Input HashMap contents:"); + tracing::debug!(target: "pipeline_actions", "execute_llm: Called with template length: {}", template.len()); + tracing::debug!(target: "pipeline_actions", "execute_llm: Input HashMap contents:"); for (k, v) in &input { - println!(" {} => {:?}", k, v); + tracing::debug!(target: "pipeline_actions", " {} => {:?}", k, v); } if let Some(driver) = &self.llm_driver { @@ -148,7 +148,7 @@ impl ActionRegistry { template.to_string() }; - println!("[DEBUG execute_llm] Calling driver.generate with prompt length: {}", prompt.len()); + tracing::debug!(target: "pipeline_actions", "execute_llm: Calling driver.generate with prompt length: {}", prompt.len()); driver.generate(prompt, input, model, temperature, max_tokens, json_mode) .await @@ -346,14 +346,14 @@ impl ActionRegistry { let mut html = String::from("Export"); if let Some(title) = data.get("title").and_then(|v| v.as_str()) { - html.push_str(&format!("

    {}

    ", title)); + html.push_str(&format!("

    {}

    ", escape_html(title))); } if let Some(items) = data.get("items").and_then(|v| v.as_array()) { html.push_str("
      "); for item in items { if let Some(text) = item.as_str() { - html.push_str(&format!("
    • {}
    • ", text)); + html.push_str(&format!("
    • {}
    • ", escape_html(text))); } } html.push_str("
    "); @@ -364,6 +364,22 @@ impl ActionRegistry { } } +/// Escape HTML special characters to prevent XSS +fn escape_html(s: &str) -> String { + let mut escaped = String::with_capacity(s.len()); + for ch in s.chars() { + match ch { + '<' => escaped.push_str("<"), + '>' => escaped.push_str(">"), + '&' => escaped.push_str("&"), + '"' => escaped.push_str("""), + '\'' => escaped.push_str("'"), + _ => escaped.push(ch), + } + } + escaped +} + impl ExportFormat { fn extension(&self) -> &'static str { match self { diff --git a/crates/zclaw-pipeline/src/executor.rs b/crates/zclaw-pipeline/src/executor.rs index 4331c0d..08d373c 100644 --- a/crates/zclaw-pipeline/src/executor.rs +++ b/crates/zclaw-pipeline/src/executor.rs @@ -185,22 +185,22 @@ impl PipelineExecutor { async move { match action { Action::LlmGenerate { template, input, model, temperature, max_tokens, json_mode } => { - println!("[DEBUG executor] LlmGenerate action called"); - println!("[DEBUG executor] Raw input map:"); + tracing::debug!(target: "pipeline_executor", "LlmGenerate action called"); + tracing::debug!(target: "pipeline_executor", "Raw input map:"); for (k, v) in input { - println!(" {} => {}", k, v); + tracing::debug!(target: "pipeline_executor", " {} => {}", k, v); } // First resolve the template itself (handles ${inputs.xxx}, ${item.xxx}, etc.) let resolved_template = context.resolve(template)?; let resolved_template_str = resolved_template.as_str().unwrap_or(template).to_string(); - println!("[DEBUG executor] Resolved template (first 300 chars): {}", + tracing::debug!(target: "pipeline_executor", "Resolved template (first 300 chars): {}", &resolved_template_str[..resolved_template_str.len().min(300)]); let resolved_input = context.resolve_map(input)?; - println!("[DEBUG executor] Resolved input map:"); + tracing::debug!(target: "pipeline_executor", "Resolved input map:"); for (k, v) in &resolved_input { - println!(" {} => {:?}", k, v); + tracing::debug!(target: "pipeline_executor", " {} => {:?}", k, v); } self.action_registry.execute_llm( &resolved_template_str, diff --git a/crates/zclaw-runtime/src/driver/openai.rs b/crates/zclaw-runtime/src/driver/openai.rs index 29f530c..a251c5e 100644 --- a/crates/zclaw-runtime/src/driver/openai.rs +++ b/crates/zclaw-runtime/src/driver/openai.rs @@ -65,8 +65,8 @@ impl LlmDriver for OpenAiDriver { // Debug: log the request details let url = format!("{}/chat/completions", self.base_url); let request_body = serde_json::to_string(&api_request).unwrap_or_default(); - eprintln!("[OpenAiDriver] Sending request to: {}", url); - eprintln!("[OpenAiDriver] Request body: {}", request_body); + tracing::debug!(target: "openai_driver", "Sending request to: {}", url); + tracing::trace!(target: "openai_driver", "Request body: {}", request_body); let response = self.client .post(&url) @@ -80,11 +80,11 @@ impl LlmDriver for OpenAiDriver { if !response.status().is_success() { let status = response.status(); let body = response.text().await.unwrap_or_default(); - eprintln!("[OpenAiDriver] API error {}: {}", status, body); + tracing::warn!(target: "openai_driver", "API error {}: {}", status, body); return Err(ZclawError::LlmError(format!("API error {}: {}", status, body))); } - eprintln!("[OpenAiDriver] Response status: {}", response.status()); + tracing::debug!(target: "openai_driver", "Response status: {}", response.status()); let api_response: OpenAiResponse = response .json() @@ -107,11 +107,11 @@ impl LlmDriver for OpenAiDriver { self.base_url.contains("aliyuncs") || self.base_url.contains("bigmodel.cn"); - eprintln!("[OpenAiDriver:stream] base_url={}, has_tools={}, needs_non_streaming={}", + tracing::debug!(target: "openai_driver", "stream config: base_url={}, has_tools={}, needs_non_streaming={}", self.base_url, has_tools, needs_non_streaming); if has_tools && needs_non_streaming { - eprintln!("[OpenAiDriver:stream] Provider detected that may not support streaming with tools, using non-streaming mode. URL: {}", self.base_url); + tracing::info!(target: "openai_driver", "Provider detected that may not support streaming with tools, using non-streaming mode. URL: {}", self.base_url); // Use non-streaming mode and convert to stream return self.stream_from_complete(request); } @@ -458,11 +458,11 @@ impl OpenAiDriver { let api_key = self.api_key.expose_secret().to_string(); let model = request.model.clone(); - eprintln!("[OpenAiDriver:stream_from_complete] Starting non-streaming request to: {}/chat/completions", base_url); + tracing::debug!(target: "openai_driver", "stream_from_complete: Starting non-streaming request to: {}/chat/completions", base_url); Box::pin(stream! { let url = format!("{}/chat/completions", base_url); - eprintln!("[OpenAiDriver:stream_from_complete] Sending non-streaming request to: {}", url); + tracing::debug!(target: "openai_driver", "stream_from_complete: Sending non-streaming request to: {}", url); let response = match self.client .post(&url) @@ -490,15 +490,15 @@ impl OpenAiDriver { let api_response: OpenAiResponse = match response.json().await { Ok(r) => r, Err(e) => { - eprintln!("[OpenAiDriver:stream_from_complete] Failed to parse response: {}", e); + tracing::warn!(target: "openai_driver", "stream_from_complete: Failed to parse response: {}", e); yield Err(ZclawError::LlmError(format!("Failed to parse response: {}", e))); return; } }; - eprintln!("[OpenAiDriver:stream_from_complete] Got response with {} choices", api_response.choices.len()); + tracing::debug!(target: "openai_driver", "stream_from_complete: Got response with {} choices", api_response.choices.len()); if let Some(choice) = api_response.choices.first() { - eprintln!("[OpenAiDriver:stream_from_complete] First choice: content={:?}, tool_calls={:?}, finish_reason={:?}", + tracing::debug!(target: "openai_driver", "stream_from_complete: First choice: content={:?}, tool_calls={:?}, finish_reason={:?}", choice.message.content.as_ref().map(|c| { if c.len() > 100 { // 使用 floor_char_boundary 确保不在多字节字符中间截断 @@ -514,15 +514,15 @@ impl OpenAiDriver { // Convert response to stream chunks let completion = self.convert_response(api_response, model.clone()); - eprintln!("[OpenAiDriver:stream_from_complete] Converted to {} content blocks, stop_reason: {:?}", completion.content.len(), completion.stop_reason); + tracing::debug!(target: "openai_driver", "stream_from_complete: Converted to {} content blocks, stop_reason: {:?}", completion.content.len(), completion.stop_reason); // Emit content blocks as stream chunks for block in &completion.content { - eprintln!("[OpenAiDriver:stream_from_complete] Emitting block: {:?}", block); + tracing::debug!(target: "openai_driver", "stream_from_complete: Emitting block: {:?}", block); match block { ContentBlock::Text { text } => { if !text.is_empty() { - eprintln!("[OpenAiDriver:stream_from_complete] Emitting TextDelta: {} chars", text.len()); + tracing::debug!(target: "openai_driver", "stream_from_complete: Emitting TextDelta: {} chars", text.len()); yield Ok(StreamChunk::TextDelta { delta: text.clone() }); } } @@ -530,7 +530,7 @@ impl OpenAiDriver { yield Ok(StreamChunk::ThinkingDelta { delta: thinking.clone() }); } ContentBlock::ToolUse { id, name, input } => { - eprintln!("[OpenAiDriver:stream_from_complete] Emitting ToolUse: id={}, name={}", id, name); + tracing::debug!(target: "openai_driver", "stream_from_complete: Emitting ToolUse: id={}, name={}", id, name); // Emit tool use start yield Ok(StreamChunk::ToolUseStart { id: id.clone(), diff --git a/crates/zclaw-runtime/src/lib.rs b/crates/zclaw-runtime/src/lib.rs index 3148ce2..e43e615 100644 --- a/crates/zclaw-runtime/src/lib.rs +++ b/crates/zclaw-runtime/src/lib.rs @@ -4,7 +4,7 @@ /// Default User-Agent header sent with all outgoing HTTP requests. /// Some LLM providers (e.g. Moonshot, Qwen, DashScope Coding Plan) reject requests without one. -pub const USER_AGENT: &str = "ZCLAW/0.2.0"; +pub const USER_AGENT: &str = "ZCLAW/0.1.0"; pub mod driver; pub mod tool; diff --git a/crates/zclaw-skills/Cargo.toml b/crates/zclaw-skills/Cargo.toml index d00847c..9748cf8 100644 --- a/crates/zclaw-skills/Cargo.toml +++ b/crates/zclaw-skills/Cargo.toml @@ -18,3 +18,4 @@ tracing = { workspace = true } async-trait = { workspace = true } regex = { workspace = true } uuid = { workspace = true } +shlex = { workspace = true } diff --git a/crates/zclaw-skills/src/orchestration/auto_compose.rs b/crates/zclaw-skills/src/orchestration/auto_compose.rs index 165fe83..794a468 100644 --- a/crates/zclaw-skills/src/orchestration/auto_compose.rs +++ b/crates/zclaw-skills/src/orchestration/auto_compose.rs @@ -360,8 +360,9 @@ mod tests { #[test] fn test_extract_types() { + let registry: &'static SkillRegistry = Box::leak(Box::new(SkillRegistry::new())); let composer = AutoComposer { - registry: unsafe { &*(&SkillRegistry::new() as *const _) }, + registry, }; let schema = serde_json::json!({ diff --git a/crates/zclaw-skills/src/runner.rs b/crates/zclaw-skills/src/runner.rs index 97e82b0..1211cd7 100644 --- a/crates/zclaw-skills/src/runner.rs +++ b/crates/zclaw-skills/src/runner.rs @@ -118,7 +118,12 @@ impl Skill for ShellSkill { let mut cmd = self.command.clone(); if let Value::String(s) = input { - cmd = cmd.replace("{{input}}", &s); + // Shell-quote the input to prevent command injection + let quoted = shlex::try_quote(&s) + .map_err(|_| zclaw_types::ZclawError::ToolError( + "Input contains null bytes and cannot be safely quoted".to_string() + ))?; + cmd = cmd.replace("{{input}}", "ed); } #[cfg(target_os = "windows")] diff --git a/desktop/package.json b/desktop/package.json index 50209d4..60aad62 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -37,40 +37,35 @@ }, "dependencies": { "@dagrejs/dagre": "^3.0.0", - "@tauri-apps/api": "^2", - "@tauri-apps/plugin-opener": "^2", - "@xstate/react": "^6.1.0", + "@tauri-apps/api": "^2.10.1", + "@tauri-apps/plugin-opener": "^2.5.3", "@xyflow/react": "^12.10.1", "clsx": "^2.1.1", - "dagre": "^0.8.5", - "date-fns": "^4.1.0", - "framer-motion": "^12.36.0", + "framer-motion": "^12.38.0", "lucide-react": "^0.577.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", "react-window": "^2.2.7", - "smol-toml": "^1.6.0", + "smol-toml": "^1.6.1", "tailwind-merge": "^3.5.0", "tweetnacl": "^1.0.3", - "uuid": "^11.0.0", - "valtio": "^2.3.1", - "xstate": "^5.28.0", - "zustand": "^5.0.11" + "uuid": "^11.1.0", + "zustand": "^5.0.12" }, "devDependencies": { "@eslint/js": "^10.0.1", "@playwright/test": "^1.58.2", - "@tailwindcss/vite": "^4.2.1", - "@tauri-apps/cli": "^2", + "@tailwindcss/vite": "^4.2.2", + "@tauri-apps/cli": "^2.10.1", "@testing-library/jest-dom": "6.6.3", "@testing-library/react": "16.1.0", "@types/js-yaml": "^4.0.9", - "@types/react": "^19.1.8", - "@types/react-dom": "^19.1.6", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", "@types/react-window": "^2.0.0", "@types/uuid": "^10.0.0", - "@vitejs/plugin-react": "^4.6.0", - "@vitest/coverage-v8": "2.1.8", + "@vitejs/plugin-react": "^4.7.0", + "@vitest/coverage-v8": "2.1.9", "autoprefixer": "^10.4.27", "eslint": "^10.1.0", "eslint-plugin-react": "^7.37.5", @@ -80,10 +75,10 @@ "postcss": "^8.5.8", "prettier": "^3.8.1", "prettier-plugin-tailwindcss": "^0.7.2", - "tailwindcss": "^4.2.1", + "tailwindcss": "^4.2.2", "typescript": "~5.8.3", "typescript-eslint": "^8.57.2", - "vite": "^7.0.4", - "vitest": "2.1.8" + "vite": "^8.0.0", + "vitest": "2.1.9" } } diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml index fdc303a..22a9e7a 100644 --- a/desktop/pnpm-lock.yaml +++ b/desktop/pnpm-lock.yaml @@ -12,14 +12,14 @@ importers: specifier: ^3.0.0 version: 3.0.0 '@tauri-apps/api': - specifier: ^2 + specifier: ^2.10.1 version: 2.10.1 '@tauri-apps/plugin-opener': - specifier: ^2 + specifier: ^2.5.3 version: 2.5.3 '@xstate/react': specifier: ^6.1.0 - version: 6.1.0(@types/react@19.2.14)(react@19.2.4)(xstate@5.28.0) + version: 6.1.0(@types/react@19.2.14)(react@19.2.4)(xstate@5.29.0) '@xyflow/react': specifier: ^12.10.1 version: 12.10.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -33,23 +33,23 @@ importers: specifier: ^4.1.0 version: 4.1.0 framer-motion: - specifier: ^12.36.0 - version: 12.36.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^12.38.0 + version: 12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) lucide-react: specifier: ^0.577.0 version: 0.577.0(react@19.2.4) react: - specifier: ^19.1.0 + specifier: ^19.2.4 version: 19.2.4 react-dom: - specifier: ^19.1.0 + specifier: ^19.2.4 version: 19.2.4(react@19.2.4) react-window: specifier: ^2.2.7 version: 2.2.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) smol-toml: - specifier: ^1.6.0 - version: 1.6.0 + specifier: ^1.6.1 + version: 1.6.1 tailwind-merge: specifier: ^3.5.0 version: 3.5.0 @@ -57,17 +57,17 @@ importers: specifier: ^1.0.3 version: 1.0.3 uuid: - specifier: ^11.0.0 + specifier: ^11.1.0 version: 11.1.0 valtio: specifier: ^2.3.1 version: 2.3.1(@types/react@19.2.14)(react@19.2.4) xstate: - specifier: ^5.28.0 - version: 5.28.0 + specifier: ^5.29.0 + version: 5.29.0 zustand: - specifier: ^5.0.11 - version: 5.0.11(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) + specifier: ^5.0.12 + version: 5.0.12(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) devDependencies: '@eslint/js': specifier: ^10.0.1 @@ -76,10 +76,10 @@ importers: specifier: ^1.58.2 version: 1.58.2 '@tailwindcss/vite': - specifier: ^4.2.1 - version: 4.2.1(vite@7.3.1(jiti@2.6.1)(lightningcss@1.31.1)) + specifier: ^4.2.2 + version: 4.2.2(vite@8.0.3(esbuild@0.27.4)(jiti@2.6.1)) '@tauri-apps/cli': - specifier: ^2 + specifier: ^2.10.1 version: 2.10.1 '@testing-library/jest-dom': specifier: 6.6.3 @@ -91,10 +91,10 @@ importers: specifier: ^4.0.9 version: 4.0.9 '@types/react': - specifier: ^19.1.8 + specifier: ^19.2.14 version: 19.2.14 '@types/react-dom': - specifier: ^19.1.6 + specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.14) '@types/react-window': specifier: ^2.0.0 @@ -103,11 +103,11 @@ importers: specifier: ^10.0.0 version: 10.0.0 '@vitejs/plugin-react': - specifier: ^4.6.0 - version: 4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.31.1)) + specifier: ^4.7.0 + version: 4.7.0(vite@8.0.3(esbuild@0.27.4)(jiti@2.6.1)) '@vitest/coverage-v8': - specifier: 2.1.8 - version: 2.1.8(vitest@2.1.8(jsdom@25.0.1)(lightningcss@1.31.1)) + specifier: 2.1.9 + version: 2.1.9(vitest@2.1.9(jsdom@25.0.1)(lightningcss@1.32.0)) autoprefixer: specifier: ^10.4.27 version: 10.4.27(postcss@8.5.8) @@ -136,8 +136,8 @@ importers: specifier: ^0.7.2 version: 0.7.2(prettier@3.8.1) tailwindcss: - specifier: ^4.2.1 - version: 4.2.1 + specifier: ^4.2.2 + version: 4.2.2 typescript: specifier: ~5.8.3 version: 5.8.3 @@ -145,11 +145,11 @@ importers: specifier: ^8.57.2 version: 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.8.3) vite: - specifier: ^7.0.4 - version: 7.3.1(jiti@2.6.1)(lightningcss@1.31.1) + specifier: ^8.0.0 + version: 8.0.3(esbuild@0.27.4)(jiti@2.6.1) vitest: - specifier: 2.1.8 - version: 2.1.8(jsdom@25.0.1)(lightningcss@1.31.1) + specifier: 2.1.9 + version: 2.1.9(jsdom@25.0.1)(lightningcss@1.32.0) packages: @@ -213,12 +213,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} hasBin: true @@ -287,14 +287,23 @@ packages: '@dagrejs/graphlib@4.0.1': resolution: {integrity: sha512-IvcV6FduIIAmLwnH+yun+QtV36SC7mERqa86aClNqmMN09WhmPPYU8ckHrZBozErf+UvHPWOTJYaGYiIcs0DgA==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -305,8 +314,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -317,8 +326,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -329,8 +338,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -341,8 +350,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -353,8 +362,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -365,8 +374,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -377,8 +386,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -389,8 +398,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -401,8 +410,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -413,8 +422,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -425,8 +434,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -437,8 +446,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -449,8 +458,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -461,8 +470,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -473,8 +482,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -485,14 +494,14 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -503,14 +512,14 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -521,14 +530,14 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -539,8 +548,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -551,8 +560,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -563,8 +572,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -575,8 +584,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -660,6 +669,12 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + + '@oxc-project/types@0.122.0': + resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -669,210 +684,308 @@ packages: engines: {node: '>=18'} hasBin: true - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + '@rolldown/binding-android-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': + resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rolldown/pluginutils@1.0.0-rc.12': + resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} + + '@rollup/rollup-android-arm-eabi@4.60.0': + resolution: {integrity: sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.0': + resolution: {integrity: sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.0': + resolution: {integrity: sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.0': + resolution: {integrity: sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.0': + resolution: {integrity: sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.0': + resolution: {integrity: sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.0': + resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.60.0': + resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.60.0': + resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.60.0': + resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.60.0': + resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.60.0': + resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.0': + resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.60.0': + resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.60.0': + resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.60.0': + resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.60.0': + resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.60.0': + resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.60.0': + resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.60.0': + resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.0': + resolution: {integrity: sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.0': + resolution: {integrity: sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.0': + resolution: {integrity: sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + '@rollup/rollup-win32-x64-gnu@4.60.0': + resolution: {integrity: sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + '@rollup/rollup-win32-x64-msvc@4.60.0': + resolution: {integrity: sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==} cpu: [x64] os: [win32] - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -883,26 +996,26 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.2.1': - resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + '@tailwindcss/vite@4.2.2': + resolution: {integrity: sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^5.2.0 || ^6 || ^7 || ^8 '@tauri-apps/api@2.10.1': resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} @@ -1009,6 +1122,9 @@ packages: '@types/react-dom': optional: true + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -1134,20 +1250,20 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - '@vitest/coverage-v8@2.1.8': - resolution: {integrity: sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==} + '@vitest/coverage-v8@2.1.9': + resolution: {integrity: sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==} peerDependencies: - '@vitest/browser': 2.1.8 - vitest: 2.1.8 + '@vitest/browser': 2.1.9 + vitest: 2.1.9 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@2.1.8': - resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} - '@vitest/mocker@2.1.8': - resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} peerDependencies: msw: ^2.4.9 vite: ^5.0.0 @@ -1157,23 +1273,20 @@ packages: vite: optional: true - '@vitest/pretty-format@2.1.8': - resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} - '@vitest/pretty-format@2.1.9': resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} - '@vitest/runner@2.1.8': - resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} + '@vitest/runner@2.1.9': + resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} - '@vitest/snapshot@2.1.8': - resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} - '@vitest/spy@2.1.8': - resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} - '@vitest/utils@2.1.8': - resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + '@vitest/utils@2.1.9': + resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} '@xstate/react@6.1.0': resolution: {integrity: sha512-ep9F0jGTI63B/jE8GHdMpUqtuz7yRebNaKv8EMUaiSi29NOglywc2X2YSOV/ygbIK+LtmgZ0q9anoEA2iBSEOw==} @@ -1294,8 +1407,8 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.0: - resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + baseline-browser-mapping@2.10.10: + resolution: {integrity: sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -1305,8 +1418,8 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} browserslist@4.28.1: @@ -1330,8 +1443,8 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - caniuse-lite@1.0.30001777: - resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + caniuse-lite@1.0.30001781: + resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} @@ -1499,8 +1612,8 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.307: - resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + electron-to-chromium@1.5.325: + resolution: {integrity: sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1508,8 +1621,8 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enhanced-resolve@5.20.0: - resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} entities@6.0.1: @@ -1556,8 +1669,8 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} engines: {node: '>=18'} hasBin: true @@ -1678,8 +1791,8 @@ packages: fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - framer-motion@12.36.0: - resolution: {integrity: sha512-4PqYHAT7gev0ke0wos+PyrcFxI0HScjm3asgU8nSYa8YzJFuwgIvdj3/s3ZaxLq0bUSboIn19A2WS/MHwLCvfw==} + framer-motion@12.38.0: + resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -2005,78 +2118,78 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} locate-path@6.0.0: @@ -2149,8 +2262,8 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - motion-dom@12.36.0: - resolution: {integrity: sha512-Ep1pq8P88rGJ75om8lTCA13zqd7ywPGwCqwuWwin6BKc0hMLkVfcS6qKlRqEo2+t0DwoUcgGJfXwaiFn4AOcQA==} + motion-dom@12.38.0: + resolution: {integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==} motion-utils@12.36.0: resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==} @@ -2251,8 +2364,8 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} playwright-core@1.58.2: @@ -2396,8 +2509,13 @@ packages: engines: {node: '>= 0.4'} hasBin: true - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + rolldown@1.0.0-rc.12: + resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup@4.60.0: + resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2481,8 +2599,8 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - smol-toml@1.6.0: - resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} + smol-toml@1.6.1: + resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} engines: {node: '>= 18'} source-map-js@1.2.1: @@ -2552,11 +2670,11 @@ packages: tailwind-merge@3.5.0: resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} test-exclude@7.0.2: @@ -2687,8 +2805,8 @@ packages: react: optional: true - vite-node@2.1.8: - resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -2723,15 +2841,16 @@ packages: terser: optional: true - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@8.0.3: + resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -2742,12 +2861,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -2763,15 +2884,15 @@ packages: yaml: optional: true - vitest@2.1.8: - resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.8 - '@vitest/ui': 2.1.8 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2847,8 +2968,8 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -2866,8 +2987,8 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xstate@5.28.0: - resolution: {integrity: sha512-Iaqq6ZrUzqeUtA3hC5LQKZfR8ZLzEFTImMHJM3jWEdVvXWdKvvVLXZEiNQWm3SCA9ZbEou/n5rcsna1wb9t28A==} + xstate@5.29.0: + resolution: {integrity: sha512-p0hiOPhhBgXn29t18zDScaN95+y1MAu1Pz5Z2IduCuOUh+d3RqJO7fmexbuQ6rlwFNgYFeXvFsFeiuiAiH3mhg==} yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -2900,8 +3021,8 @@ packages: react: optional: true - zustand@5.0.11: - resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} + zustand@5.0.12: + resolution: {integrity: sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=18.0.0' @@ -2949,8 +3070,8 @@ snapshots: '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 @@ -2965,7 +3086,7 @@ snapshots: '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 @@ -3005,12 +3126,12 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.6': + '@babel/helpers@7.29.2': dependencies: '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@babel/parser@7.29.0': + '@babel/parser@7.29.2': dependencies: '@babel/types': 7.29.0 @@ -3029,7 +3150,7 @@ snapshots: '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@babel/traverse@7.29.0': @@ -3037,7 +3158,7 @@ snapshots: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/types': 7.29.0 debug: 4.4.3 @@ -3077,151 +3198,167 @@ snapshots: '@dagrejs/graphlib@4.0.1': {} + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.27.4': optional: true '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/android-arm64@0.27.4': optional: true '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm@0.27.4': optional: true '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-x64@0.27.4': optional: true '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/darwin-arm64@0.27.4': optional: true '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-x64@0.27.4': optional: true '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.27.4': optional: true '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.27.4': optional: true '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.27.4': optional: true '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.27.4': optional: true '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-ia32@0.27.4': optional: true '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-loong64@0.27.4': optional: true '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-mips64el@0.27.4': optional: true '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-ppc64@0.27.4': optional: true '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-riscv64@0.27.4': optional: true '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-s390x@0.27.4': optional: true '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-x64@0.27.4': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/netbsd-arm64@0.27.4': optional: true '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-x64@0.27.4': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.27.4': optional: true '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-x64@0.27.4': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openharmony-arm64@0.27.4': optional: true '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/sunos-x64@0.27.4': optional: true '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-arm64@0.27.4': optional: true '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-ia32@0.27.4': optional: true '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-x64@0.27.4': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@10.1.0(jiti@2.6.1))': @@ -3299,6 +3436,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@oxc-project/types@0.122.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -3306,150 +3452,199 @@ snapshots: dependencies: playwright: 1.58.2 + '@rolldown/binding-android-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + optional: true + '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/rollup-android-arm-eabi@4.59.0': + '@rolldown/pluginutils@1.0.0-rc.12': {} + + '@rollup/rollup-android-arm-eabi@4.60.0': optional: true - '@rollup/rollup-android-arm64@4.59.0': + '@rollup/rollup-android-arm64@4.60.0': optional: true - '@rollup/rollup-darwin-arm64@4.59.0': + '@rollup/rollup-darwin-arm64@4.60.0': optional: true - '@rollup/rollup-darwin-x64@4.59.0': + '@rollup/rollup-darwin-x64@4.60.0': optional: true - '@rollup/rollup-freebsd-arm64@4.59.0': + '@rollup/rollup-freebsd-arm64@4.60.0': optional: true - '@rollup/rollup-freebsd-x64@4.59.0': + '@rollup/rollup-freebsd-x64@4.60.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + '@rollup/rollup-linux-arm-gnueabihf@4.60.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.59.0': + '@rollup/rollup-linux-arm-musleabihf@4.60.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.59.0': + '@rollup/rollup-linux-arm64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.59.0': + '@rollup/rollup-linux-arm64-musl@4.60.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.59.0': + '@rollup/rollup-linux-loong64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.59.0': + '@rollup/rollup-linux-loong64-musl@4.60.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.59.0': + '@rollup/rollup-linux-ppc64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.59.0': + '@rollup/rollup-linux-ppc64-musl@4.60.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.59.0': + '@rollup/rollup-linux-riscv64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.59.0': + '@rollup/rollup-linux-riscv64-musl@4.60.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.59.0': + '@rollup/rollup-linux-s390x-gnu@4.60.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.59.0': + '@rollup/rollup-linux-x64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-x64-musl@4.59.0': + '@rollup/rollup-linux-x64-musl@4.60.0': optional: true - '@rollup/rollup-openbsd-x64@4.59.0': + '@rollup/rollup-openbsd-x64@4.60.0': optional: true - '@rollup/rollup-openharmony-arm64@4.59.0': + '@rollup/rollup-openharmony-arm64@4.60.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.59.0': + '@rollup/rollup-win32-arm64-msvc@4.60.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.59.0': + '@rollup/rollup-win32-ia32-msvc@4.60.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.59.0': + '@rollup/rollup-win32-x64-gnu@4.60.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.59.0': + '@rollup/rollup-win32-x64-msvc@4.60.0': optional: true - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.2.2': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.0 + enhanced-resolve: 5.20.1 jiti: 2.6.1 - lightningcss: 1.31.1 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.1 + tailwindcss: 4.2.2 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.2.2': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.2.2': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.2.2': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.2.2': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - '@tailwindcss/vite@4.2.1(vite@7.3.1(jiti@2.6.1)(lightningcss@1.31.1))': + '@tailwindcss/vite@4.2.2(vite@8.0.3(esbuild@0.27.4)(jiti@2.6.1))': dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: 7.3.1(jiti@2.6.1)(lightningcss@1.31.1) + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + tailwindcss: 4.2.2 + vite: 8.0.3(esbuild@0.27.4)(jiti@2.6.1) '@tauri-apps/api@2.10.1': {} @@ -3535,11 +3730,16 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 @@ -3551,7 +3751,7 @@ snapshots: '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': @@ -3695,7 +3895,7 @@ snapshots: '@typescript-eslint/types': 8.57.2 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.31.1))': + '@vitejs/plugin-react@4.7.0(vite@8.0.3(esbuild@0.27.4)(jiti@2.6.1))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -3703,11 +3903,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.3.1(jiti@2.6.1)(lightningcss@1.31.1) + vite: 8.0.3(esbuild@0.27.4)(jiti@2.6.1) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@2.1.8(vitest@2.1.8(jsdom@25.0.1)(lightningcss@1.31.1))': + '@vitest/coverage-v8@2.1.9(vitest@2.1.9(jsdom@25.0.1)(lightningcss@1.32.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -3721,61 +3921,57 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 1.2.0 - vitest: 2.1.8(jsdom@25.0.1)(lightningcss@1.31.1) + vitest: 2.1.9(jsdom@25.0.1)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@vitest/expect@2.1.8': + '@vitest/expect@2.1.9': dependencies: - '@vitest/spy': 2.1.8 - '@vitest/utils': 2.1.8 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 chai: 5.3.3 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.8(vite@5.4.21(lightningcss@1.31.1))': + '@vitest/mocker@2.1.9(vite@5.4.21(lightningcss@1.32.0))': dependencies: - '@vitest/spy': 2.1.8 + '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 5.4.21(lightningcss@1.31.1) - - '@vitest/pretty-format@2.1.8': - dependencies: - tinyrainbow: 1.2.0 + vite: 5.4.21(lightningcss@1.32.0) '@vitest/pretty-format@2.1.9': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.1.8': + '@vitest/runner@2.1.9': dependencies: - '@vitest/utils': 2.1.8 + '@vitest/utils': 2.1.9 pathe: 1.1.2 - '@vitest/snapshot@2.1.8': + '@vitest/snapshot@2.1.9': dependencies: - '@vitest/pretty-format': 2.1.8 + '@vitest/pretty-format': 2.1.9 magic-string: 0.30.21 pathe: 1.1.2 - '@vitest/spy@2.1.8': + '@vitest/spy@2.1.9': dependencies: tinyspy: 3.0.2 - '@vitest/utils@2.1.8': + '@vitest/utils@2.1.9': dependencies: - '@vitest/pretty-format': 2.1.8 + '@vitest/pretty-format': 2.1.9 loupe: 3.2.1 tinyrainbow: 1.2.0 - '@xstate/react@6.1.0(@types/react@19.2.14)(react@19.2.4)(xstate@5.28.0)': + '@xstate/react@6.1.0(@types/react@19.2.14)(react@19.2.4)(xstate@5.29.0)': dependencies: react: 19.2.4 use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.14)(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: - xstate: 5.28.0 + xstate: 5.29.0 transitivePeerDependencies: - '@types/react' @@ -3901,7 +4097,7 @@ snapshots: autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001777 + caniuse-lite: 1.0.30001781 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 @@ -3915,7 +4111,7 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.0: {} + baseline-browser-mapping@2.10.10: {} brace-expansion@1.1.12: dependencies: @@ -3926,15 +4122,15 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.4: + brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001777 - electron-to-chromium: 1.5.307 + baseline-browser-mapping: 2.10.10 + caniuse-lite: 1.0.30001781 + electron-to-chromium: 1.5.325 node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -3957,7 +4153,7 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - caniuse-lite@1.0.30001777: {} + caniuse-lite@1.0.30001781: {} chai@5.3.3: dependencies: @@ -4117,16 +4313,16 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.307: {} + electron-to-chromium@1.5.325: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} - enhanced-resolve@5.20.0: + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.2 entities@6.0.1: {} @@ -4260,34 +4456,35 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.27.3: + esbuild@0.27.4: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 + '@esbuild/aix-ppc64': 0.27.4 + '@esbuild/android-arm': 0.27.4 + '@esbuild/android-arm64': 0.27.4 + '@esbuild/android-x64': 0.27.4 + '@esbuild/darwin-arm64': 0.27.4 + '@esbuild/darwin-x64': 0.27.4 + '@esbuild/freebsd-arm64': 0.27.4 + '@esbuild/freebsd-x64': 0.27.4 + '@esbuild/linux-arm': 0.27.4 + '@esbuild/linux-arm64': 0.27.4 + '@esbuild/linux-ia32': 0.27.4 + '@esbuild/linux-loong64': 0.27.4 + '@esbuild/linux-mips64el': 0.27.4 + '@esbuild/linux-ppc64': 0.27.4 + '@esbuild/linux-riscv64': 0.27.4 + '@esbuild/linux-s390x': 0.27.4 + '@esbuild/linux-x64': 0.27.4 + '@esbuild/netbsd-arm64': 0.27.4 + '@esbuild/netbsd-x64': 0.27.4 + '@esbuild/openbsd-arm64': 0.27.4 + '@esbuild/openbsd-x64': 0.27.4 + '@esbuild/openharmony-arm64': 0.27.4 + '@esbuild/sunos-x64': 0.27.4 + '@esbuild/win32-arm64': 0.27.4 + '@esbuild/win32-ia32': 0.27.4 + '@esbuild/win32-x64': 0.27.4 + optional: true escalade@3.2.0: {} @@ -4296,7 +4493,7 @@ snapshots: eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@2.6.1)): dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 eslint: 10.1.0(jiti@2.6.1) hermes-parser: 0.25.1 zod: 4.3.6 @@ -4404,9 +4601,9 @@ snapshots: fast-levenshtein@2.0.6: {} - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 file-entry-cache@8.0.0: dependencies: @@ -4443,9 +4640,9 @@ snapshots: fraction.js@5.3.4: {} - framer-motion@12.36.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + framer-motion@12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - motion-dom: 12.36.0 + motion-dom: 12.38.0 motion-utils: 12.36.0 tslib: 2.8.1 optionalDependencies: @@ -4766,7 +4963,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.19.0 + ws: 8.20.0 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -4799,54 +4996,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.31.1: + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.31.1: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.31.1: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.31.1: + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 locate-path@6.0.0: dependencies: @@ -4878,7 +5075,7 @@ snapshots: magicast@0.3.5: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 source-map-js: 1.2.1 @@ -4898,7 +5095,7 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.5 minimatch@3.1.5: dependencies: @@ -4910,7 +5107,7 @@ snapshots: minipass@7.1.3: {} - motion-dom@12.36.0: + motion-dom@12.38.0: dependencies: motion-utils: 12.36.0 @@ -5015,7 +5212,7 @@ snapshots: picocolors@1.1.1: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} playwright-core@1.58.2: {} @@ -5111,35 +5308,56 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rollup@4.59.0: + rolldown@1.0.0-rc.12: + dependencies: + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.12 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-x64': 1.0.0-rc.12 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 + + rollup@4.60.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 + '@rollup/rollup-android-arm-eabi': 4.60.0 + '@rollup/rollup-android-arm64': 4.60.0 + '@rollup/rollup-darwin-arm64': 4.60.0 + '@rollup/rollup-darwin-x64': 4.60.0 + '@rollup/rollup-freebsd-arm64': 4.60.0 + '@rollup/rollup-freebsd-x64': 4.60.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.0 + '@rollup/rollup-linux-arm-musleabihf': 4.60.0 + '@rollup/rollup-linux-arm64-gnu': 4.60.0 + '@rollup/rollup-linux-arm64-musl': 4.60.0 + '@rollup/rollup-linux-loong64-gnu': 4.60.0 + '@rollup/rollup-linux-loong64-musl': 4.60.0 + '@rollup/rollup-linux-ppc64-gnu': 4.60.0 + '@rollup/rollup-linux-ppc64-musl': 4.60.0 + '@rollup/rollup-linux-riscv64-gnu': 4.60.0 + '@rollup/rollup-linux-riscv64-musl': 4.60.0 + '@rollup/rollup-linux-s390x-gnu': 4.60.0 + '@rollup/rollup-linux-x64-gnu': 4.60.0 + '@rollup/rollup-linux-x64-musl': 4.60.0 + '@rollup/rollup-openbsd-x64': 4.60.0 + '@rollup/rollup-openharmony-arm64': 4.60.0 + '@rollup/rollup-win32-arm64-msvc': 4.60.0 + '@rollup/rollup-win32-ia32-msvc': 4.60.0 + '@rollup/rollup-win32-x64-gnu': 4.60.0 + '@rollup/rollup-win32-x64-msvc': 4.60.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -5237,7 +5455,7 @@ snapshots: signal-exit@4.1.0: {} - smol-toml@1.6.0: {} + smol-toml@1.6.1: {} source-map-js@1.2.1: {} @@ -5328,9 +5546,9 @@ snapshots: tailwind-merge@3.5.0: {} - tailwindcss@4.2.1: {} + tailwindcss@4.2.2: {} - tapable@2.3.0: {} + tapable@2.3.2: {} test-exclude@7.0.2: dependencies: @@ -5344,8 +5562,8 @@ snapshots: tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 tinypool@1.1.1: {} @@ -5461,13 +5679,13 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - vite-node@2.1.8(lightningcss@1.31.1): + vite-node@2.1.9(lightningcss@1.32.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 1.1.2 - vite: 5.4.21(lightningcss@1.31.1) + vite: 5.4.21(lightningcss@1.32.0) transitivePeerDependencies: - '@types/node' - less @@ -5479,37 +5697,36 @@ snapshots: - supports-color - terser - vite@5.4.21(lightningcss@1.31.1): + vite@5.4.21(lightningcss@1.32.0): dependencies: esbuild: 0.21.5 postcss: 8.5.8 - rollup: 4.59.0 + rollup: 4.60.0 optionalDependencies: fsevents: 2.3.3 - lightningcss: 1.31.1 + lightningcss: 1.32.0 - vite@7.3.1(jiti@2.6.1)(lightningcss@1.31.1): + vite@8.0.3(esbuild@0.27.4)(jiti@2.6.1): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + lightningcss: 1.32.0 + picomatch: 4.0.4 postcss: 8.5.8 - rollup: 4.59.0 + rolldown: 1.0.0-rc.12 tinyglobby: 0.2.15 optionalDependencies: + esbuild: 0.27.4 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.31.1 - vitest@2.1.8(jsdom@25.0.1)(lightningcss@1.31.1): + vitest@2.1.9(jsdom@25.0.1)(lightningcss@1.32.0): dependencies: - '@vitest/expect': 2.1.8 - '@vitest/mocker': 2.1.8(vite@5.4.21(lightningcss@1.31.1)) + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21(lightningcss@1.32.0)) '@vitest/pretty-format': 2.1.9 - '@vitest/runner': 2.1.8 - '@vitest/snapshot': 2.1.8 - '@vitest/spy': 2.1.8 - '@vitest/utils': 2.1.8 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 chai: 5.3.3 debug: 4.4.3 expect-type: 1.3.0 @@ -5520,8 +5737,8 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.1.1 tinyrainbow: 1.2.0 - vite: 5.4.21(lightningcss@1.31.1) - vite-node: 2.1.8(lightningcss@1.31.1) + vite: 5.4.21(lightningcss@1.32.0) + vite-node: 2.1.9(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: jsdom: 25.0.1 @@ -5617,13 +5834,13 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.2.0 - ws@8.19.0: {} + ws@8.20.0: {} xml-name-validator@5.0.0: {} xmlchars@2.2.0: {} - xstate@5.28.0: {} + xstate@5.29.0: {} yallist@3.1.1: {} @@ -5642,7 +5859,7 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - zustand@5.0.11(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): + zustand@5.0.12(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): optionalDependencies: '@types/react': 19.2.14 react: 19.2.4 diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index 293aade..e0f03d5 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -1327,7 +1327,13 @@ pub fn run() { } // Initialize Viking storage (async, in background) - let runtime = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime"); + let runtime = match tokio::runtime::Runtime::new() { + Ok(rt) => rt, + Err(e) => { + tracing::error!("[VikingCommands] Failed to create tokio runtime: {}", e); + return; + } + }; runtime.block_on(async { if let Err(e) = crate::viking_commands::init_storage().await { tracing::error!("[VikingCommands] Failed to initialize storage: {}", e); @@ -1433,6 +1439,8 @@ pub fn run() { memory::context_builder::estimate_content_tokens, // LLM commands (for extraction) llm::llm_complete, + llm::embedding_create, + llm::embedding_providers, // Browser automation commands (Fantoccini-based Browser Hand) browser::commands::browser_create_session, browser::commands::browser_close_session, diff --git a/desktop/src-tauri/src/llm/mod.rs b/desktop/src-tauri/src/llm/mod.rs index 5a58e1b..122f804 100644 --- a/desktop/src-tauri/src/llm/mod.rs +++ b/desktop/src-tauri/src/llm/mod.rs @@ -52,6 +52,47 @@ pub struct LlmUsage { pub total_tokens: u32, } +// === Embedding Types === + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingRequest { + pub input: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub model: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingResponse { + pub embedding: Vec, + pub model: String, + pub usage: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingUsage { + pub prompt_tokens: u32, + pub total_tokens: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingConfig { + pub provider: String, + pub api_key: String, + pub endpoint: Option, + pub model: Option, +} + +impl Default for EmbeddingConfig { + fn default() -> Self { + Self { + provider: "openai".to_string(), + api_key: String::new(), + endpoint: None, + model: Some("text-embedding-3-small".to_string()), + } + } +} + // === Provider Configuration === #[derive(Debug, Clone)] @@ -98,6 +139,82 @@ pub fn get_provider_configs() -> HashMap { configs } +// === Embedding Provider Configuration === + +#[derive(Debug, Clone)] +pub struct EmbeddingProviderConfig { + pub name: String, + pub endpoint: String, + pub default_model: String, + pub dimensions: usize, +} + +pub fn get_embedding_provider_configs() -> HashMap { + let mut configs = HashMap::new(); + + configs.insert( + "openai".to_string(), + EmbeddingProviderConfig { + name: "OpenAI".to_string(), + endpoint: "https://api.openai.com/v1".to_string(), + default_model: "text-embedding-3-small".to_string(), + dimensions: 1536, + }, + ); + + configs.insert( + "zhipu".to_string(), + EmbeddingProviderConfig { + name: "智谱 AI".to_string(), + endpoint: "https://open.bigmodel.cn/api/paas/v4".to_string(), + default_model: "embedding-3".to_string(), + dimensions: 1024, + }, + ); + + configs.insert( + "doubao".to_string(), + EmbeddingProviderConfig { + name: "火山引擎 (Doubao)".to_string(), + endpoint: "https://ark.cn-beijing.volces.com/api/v3".to_string(), + default_model: "doubao-embedding".to_string(), + dimensions: 1024, + }, + ); + + configs.insert( + "qwen".to_string(), + EmbeddingProviderConfig { + name: "百炼/通义千问".to_string(), + endpoint: "https://dashscope.aliyuncs.com/compatible-mode/v1".to_string(), + default_model: "text-embedding-v3".to_string(), + dimensions: 1024, + }, + ); + + configs.insert( + "deepseek".to_string(), + EmbeddingProviderConfig { + name: "DeepSeek".to_string(), + endpoint: "https://api.deepseek.com/v1".to_string(), + default_model: "deepseek-embedding".to_string(), + dimensions: 1536, + }, + ); + + configs.insert( + "local".to_string(), + EmbeddingProviderConfig { + name: "本地模型 (TF-IDF)".to_string(), + endpoint: String::new(), + default_model: "tfidf".to_string(), + dimensions: 0, + }, + ); + + configs +} + // === LLM Client === pub struct LlmClient { @@ -221,6 +338,135 @@ pub async fn llm_complete( client.complete(messages).await } +// === Embedding Client === + +pub struct EmbeddingClient { + config: EmbeddingConfig, + provider_config: Option, +} + +impl EmbeddingClient { + pub fn new(config: EmbeddingConfig) -> Self { + let provider_config = get_embedding_provider_configs() + .get(&config.provider) + .cloned(); + + Self { + config, + provider_config, + } + } + + pub async fn embed(&self, text: &str) -> Result { + if self.config.provider == "local" || self.config.api_key.is_empty() { + return Err("Local TF-IDF mode does not support API embedding".to_string()); + } + + let endpoint = self.config.endpoint.clone() + .or_else(|| { + self.provider_config + .as_ref() + .map(|c| c.endpoint.clone()) + }) + .unwrap_or_else(|| "https://api.openai.com/v1".to_string()); + + let model = self.config.model.clone() + .or_else(|| { + self.provider_config + .as_ref() + .map(|c| c.default_model.clone()) + }) + .unwrap_or_else(|| "text-embedding-3-small".to_string()); + + self.call_embedding_api(&endpoint, text, &model).await + } + + async fn call_embedding_api(&self, endpoint: &str, text: &str, model: &str) -> Result { + let client = reqwest::Client::new(); + + let request_body = serde_json::json!({ + "input": text, + "model": model, + }); + + let response = client + .post(format!("{}/embeddings", endpoint)) + .header("Authorization", format!("Bearer {}", self.config.api_key)) + .header("Content-Type", "application/json") + .json(&request_body) + .send() + .await + .map_err(|e| format!("Embedding API request failed: {}", e))?; + + if !response.status().is_success() { + let status = response.status(); + let body = response.text().await.unwrap_or_default(); + return Err(format!("Embedding API error {}: {}", status, body)); + } + + let json: serde_json::Value = response + .json() + .await + .map_err(|e| format!("Failed to parse embedding response: {}", e))?; + + let embedding = json + .get("data") + .and_then(|d| d.get(0)) + .and_then(|d| d.get("embedding")) + .and_then(|e| e.as_array()) + .ok_or("Invalid embedding response format")? + .iter() + .filter_map(|v| v.as_f64().map(|f| f as f32)) + .collect::>(); + + let usage = json.get("usage").map(|u| EmbeddingUsage { + prompt_tokens: u.get("prompt_tokens").and_then(|v| v.as_u64()).unwrap_or(0) as u32, + total_tokens: u.get("total_tokens").and_then(|v| v.as_u64()).unwrap_or(0) as u32, + }); + + Ok(EmbeddingResponse { + embedding, + model: model.to_string(), + usage, + }) + } + + pub fn get_dimensions(&self) -> usize { + self.provider_config + .as_ref() + .map(|c| c.dimensions) + .unwrap_or(1536) + } +} + +#[tauri::command] +pub async fn embedding_create( + provider: String, + api_key: String, + text: String, + model: Option, + endpoint: Option, +) -> Result { + let config = EmbeddingConfig { + provider, + api_key, + endpoint, + model, + }; + + let client = EmbeddingClient::new(config); + client.embed(&text).await +} + +#[tauri::command] +pub async fn embedding_providers() -> Result, String> { + let configs = get_embedding_provider_configs(); + Ok(configs + .into_iter() + .map(|(id, c)| (id, c.name, c.default_model, c.dimensions)) + .collect()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/desktop/src-tauri/src/viking_commands.rs b/desktop/src-tauri/src/viking_commands.rs index b1b5830..5ed8230 100644 --- a/desktop/src-tauri/src/viking_commands.rs +++ b/desktop/src-tauri/src/viking_commands.rs @@ -128,7 +128,7 @@ pub async fn viking_status() -> Result { Ok(VikingStatus { available: true, - version: Some("0.2.0-native".to_string()), + version: Some("0.1.0-native".to_string()), data_dir: get_data_dir_string(), error: None, }) diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json index f808316..91b65d2 100644 --- a/desktop/src-tauri/tauri.conf.json +++ b/desktop/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "ZClaw", - "version": "0.2.0", + "productName": "ZCLAW", + "version": "0.1.0", "identifier": "com.zclaw.desktop", "build": { "beforeDevCommand": "pnpm dev", @@ -12,16 +12,16 @@ "app": { "windows": [ { - "title": "ZClaw - OpenFang Desktop", + "title": "ZCLAW", "width": 1200, "height": 800, "minWidth": 900, "minHeight": 600, - "devtools": true + "devtools": false } ], "security": { - "csp": null + "csp": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' asset: https://asset.localhost data: blob:; connect-src ipc: http://ipc.localhost http://* https://*" } }, "bundle": { diff --git a/desktop/src/components/ActiveLearningPanel.tsx b/desktop/src/components/ActiveLearningPanel.tsx deleted file mode 100644 index ac76c57..0000000 --- a/desktop/src/components/ActiveLearningPanel.tsx +++ /dev/null @@ -1,423 +0,0 @@ -/** - * ActiveLearningPanel - 主动学习状态面板 - * - * 展示学习事件、模式和系统建议。 - */ - -import { useCallback, useState } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { - Brain, - TrendingUp, - Lightbulb, - Check, - X, - Download, - Clock, - BarChart3, -} from 'lucide-react'; -import { Button, EmptyState, Badge } from './ui'; -import { useActiveLearningStore } from '../store/activeLearningStore'; -import { - type LearningEvent, - type LearningSuggestion, - type LearningEventType, -} from '../types/active-learning'; -import { useChatStore } from '../store/chatStore'; -import { cardHover, defaultTransition } from '../lib/animations'; - -// === Constants === - -const EVENT_TYPE_LABELS: Record = { - preference: { label: '偏好', color: 'text-amber-400' }, - correction: { label: '纠正', color: 'text-red-400' }, - context: { label: '上下文', color: 'text-purple-400' }, - feedback: { label: '反馈', color: 'text-blue-400' }, - behavior: { label: '行为', color: 'text-green-400' }, - implicit: { label: '隐式', color: 'text-gray-400' }, -}; - -const PATTERN_TYPE_LABELS: Record = { - preference: { label: '偏好模式', icon: '🎯' }, - rule: { label: '规则模式', icon: '📋' }, - context: { label: '上下文模式', icon: '🔗' }, - behavior: { label: '行为模式', icon: '⚡' }, -}; - -// === Sub-Components === - -interface EventItemProps { - event: LearningEvent; - onAcknowledge: () => void; -} - -function EventItem({ event, onAcknowledge }: EventItemProps) { - const typeInfo = EVENT_TYPE_LABELS[event.type]; - const timeAgo = getTimeAgo(event.timestamp); - - return ( - -
    -
    -
    - - {typeInfo.label} - - {timeAgo} -
    -

    {event.observation}

    - {event.inferredPreference && ( -

    → {event.inferredPreference}

    - )} -
    - - {!event.acknowledged && ( - - )} -
    - -
    - 置信度: {(event.confidence * 100).toFixed(0)}% - {event.appliedCount > 0 && ( - • 应用 {event.appliedCount} 次 - )} -
    -
    - ); -} - -interface SuggestionCardProps { - suggestion: LearningSuggestion; - onApply: () => void; - onDismiss: () => void; -} - -function SuggestionCard({ suggestion, onApply, onDismiss }: SuggestionCardProps) { - const daysLeft = Math.ceil( - (suggestion.expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24) - ); - - return ( - -
    - -
    -

    {suggestion.suggestion}

    -
    - 置信度: {(suggestion.confidence * 100).toFixed(0)}% - {daysLeft > 0 && • {daysLeft} 天后过期} -
    -
    -
    - -
    - - -
    -
    - ); -} - -// === Main Component === - -interface ActiveLearningPanelProps { - className?: string; -} - -export function ActiveLearningPanel({ className = '' }: ActiveLearningPanelProps) { - const { currentAgent } = useChatStore(); - const agentId = currentAgent?.id || 'default'; - - const [activeTab, setActiveTab] = useState<'events' | 'patterns' | 'suggestions'>('suggestions'); - - const { - events, - config, - acknowledgeEvent, - getPatterns, - getSuggestions, - applySuggestion, - dismissSuggestion, - getStats, - setConfig, - exportLearningData, - clearEvents, - } = useActiveLearningStore(); - - const stats = getStats(agentId); - const agentEvents = events.filter(e => e.agentId === agentId).slice(0, 20); - const agentPatterns = getPatterns(agentId); - const agentSuggestions = getSuggestions(agentId); - - // 处理确认事件 - const handleAcknowledge = useCallback((eventId: string) => { - acknowledgeEvent(eventId); - }, [acknowledgeEvent]); - - // 处理应用建议 - const handleApplySuggestion = useCallback((suggestionId: string) => { - applySuggestion(suggestionId); - }, [applySuggestion]); - - // 处理忽略建议 - const handleDismissSuggestion = useCallback((suggestionId: string) => { - dismissSuggestion(suggestionId); - }, [dismissSuggestion]); - - // 导出学习数据 - const handleExport = useCallback(async () => { - const data = await exportLearningData(agentId); - const blob = new Blob([data], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `zclaw-learning-${agentId}-${new Date().toISOString().slice(0, 10)}.json`; - a.click(); - URL.revokeObjectURL(url); - }, [agentId, exportLearningData]); - - // 清除学习数据 - const handleClear = useCallback(() => { - if (confirm('确定要清除所有学习数据吗?此操作不可撤销。')) { - clearEvents(agentId); - } - }, [agentId, clearEvents]); - - return ( -
    - {/* 启用开关和导出 */} - -
    - -
    - setConfig({ enabled: e.target.checked })} - className="rounded border-gray-300 dark:border-gray-600" - /> - -
    -
    -
    - - {/* 统计概览 */} - -

    - - 学习统计 -

    -
    -
    -
    {stats.totalEvents}
    -
    事件
    -
    -
    -
    {stats.totalPatterns}
    -
    模式
    -
    -
    -
    {agentSuggestions.length}
    -
    建议
    -
    -
    -
    - {(stats.avgConfidence * 100).toFixed(0)}% -
    -
    置信度
    -
    -
    -
    - - {/* Tab 切换 */} -
    - {(['suggestions', 'events', 'patterns'] as const).map(tab => ( - - ))} -
    - - {/* 内容区域 */} -
    - - {activeTab === 'suggestions' && ( - - {agentSuggestions.length === 0 ? ( - } - title="暂无学习建议" - description="系统会根据您的反馈自动生成改进建议" - className="py-4" - /> - ) : ( - agentSuggestions.map(suggestion => ( - handleApplySuggestion(suggestion.id)} - onDismiss={() => handleDismissSuggestion(suggestion.id)} - /> - )) - )} - - )} - - {activeTab === 'events' && ( - - {agentEvents.length === 0 ? ( - } - title="暂无学习事件" - description="开始对话后,系统会自动记录学习事件" - className="py-4" - /> - ) : ( - agentEvents.map(event => ( - handleAcknowledge(event.id)} - /> - )) - )} - - )} - - {activeTab === 'patterns' && ( - - {agentPatterns.length === 0 ? ( - } - title="暂无学习模式" - description="积累更多反馈后,系统会识别出行为模式" - className="py-4" - /> - ) : ( - agentPatterns.map(pattern => { - const typeInfo = PATTERN_TYPE_LABELS[pattern.type] || { label: pattern.type, icon: '📊' }; - return ( - -
    -
    - {typeInfo.icon} - {typeInfo.label} -
    - - {(pattern.confidence * 100).toFixed(0)}% - -
    -

    {pattern.description}

    -
    - {pattern.examples.length} 个示例 -
    -
    - ); - }) - )} -
    - )} -
    -
    - - {/* 底部操作栏 */} -
    -
    - 上次更新: {agentEvents[0] ? getTimeAgo(agentEvents[0].timestamp) : '无'} -
    - -
    -
    - ); -} - -// === Helpers === - -function getTimeAgo(timestamp: number): string { - const seconds = Math.floor((Date.now() - timestamp) / 1000); - - if (seconds < 60) return '刚刚'; - if (seconds < 3600) return `${Math.floor(seconds / 60)} 分钟前`; - if (seconds < 86400) return `${Math.floor(seconds / 3600)} 小时前`; - return `${Math.floor(seconds / 86400)} 天前`; -} - -export default ActiveLearningPanel; diff --git a/desktop/src/components/Feedback/FeedbackButton.tsx b/desktop/src/components/Feedback/FeedbackButton.tsx deleted file mode 100644 index 687868e..0000000 --- a/desktop/src/components/Feedback/FeedbackButton.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { MessageCircle } from 'lucide-react'; -import { motion } from 'framer-motion'; -import { useFeedbackStore } from './feedbackStore'; -import { Button } from '../ui'; - -interface FeedbackButtonProps { - onClick: () => void; - showCount?: boolean; -} - -export function FeedbackButton({ onClick, showCount = true }: FeedbackButtonProps) { - const feedbackItems = useFeedbackStore((state) => state.feedbackItems); - const pendingCount = feedbackItems.filter((f) => f.status === 'pending' || f.status === 'submitted').length; - - return ( - - - - ); -} diff --git a/desktop/src/components/Feedback/FeedbackHistory.tsx b/desktop/src/components/Feedback/FeedbackHistory.tsx deleted file mode 100644 index e92fc96..0000000 --- a/desktop/src/components/Feedback/FeedbackHistory.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import { useState } from 'react'; -import { format } from 'date-fns'; -import { motion, AnimatePresence } from 'framer-motion'; -import { Clock, CheckCircle, AlertCircle, Hourglass, Trash2, ChevronDown, ChevronUp } from 'lucide-react'; -import { useFeedbackStore, type FeedbackSubmission, type FeedbackStatus } from './feedbackStore'; -import { Button, Badge } from '../ui'; - -const statusConfig: Record = { - pending: { label: 'Pending', color: 'text-gray-500', icon: }, - submitted: { label: 'Submitted', color: 'text-blue-500', icon: }, - acknowledged: { label: 'Acknowledged', color: 'text-purple-500', icon: }, - in_progress: { label: 'In Progress', color: 'text-yellow-500', icon: }, - resolved: { label: 'Resolved', color: 'text-green-500', icon: }, -}; - -const typeLabels: Record = { - bug: 'Bug Report', - feature: 'Feature Request', - general: 'General Feedback', -}; -const priorityLabels: Record = { - low: 'Low', - medium: 'Medium', - high: 'High', -}; - -interface FeedbackHistoryProps { - onViewDetails?: (feedback: FeedbackSubmission) => void; -} - -export function FeedbackHistory({ onViewDetails: _onViewDetails }: FeedbackHistoryProps) { - const { feedbackItems, deleteFeedback, updateFeedbackStatus } = useFeedbackStore(); - const [expandedId, setExpandedId] = useState(null); - - const formatDate = (timestamp: number) => { - return format(new Date(timestamp), 'yyyy-MM-dd HH:mm'); - }; - - const handleDelete = (id: string) => { - if (confirm('Are you sure you want to delete this feedback?')) { - deleteFeedback(id); - } - }; - - const handleStatusChange = (id: string, newStatus: FeedbackStatus) => { - updateFeedbackStatus(id, newStatus); - }; - - if (feedbackItems.length === 0) { - return ( -
    -

    No feedback submissions yet.

    -

    Click the feedback button to submit your first feedback.

    -
    - ); - } - - return ( -
    - {feedbackItems.map((feedback) => { - const isExpanded = expandedId === feedback.id; - const statusInfo = statusConfig[feedback.status]; - - return ( - - {/* Header */} -
    setExpandedId(isExpanded ? null : feedback.id)} - > -
    -
    - {feedback.type === 'bug' && } - {feedback.type === 'feature' && } - {feedback.type === 'general' && } -
    -
    -

    - {feedback.title} -

    -

    - {typeLabels[feedback.type]} - {formatDate(feedback.createdAt)} -

    -
    - - {priorityLabels[feedback.priority]} - -
    -
    - -
    -
    - - {/* Expandable Content */} - - {isExpanded && ( - -
    - {/* Description */} -
    -
    Description
    -

    - {feedback.description} -

    -
    - - {/* Attachments */} - {feedback.attachments.length > 0 && ( -
    -
    - Attachments ({feedback.attachments.length}) -
    -
    - {feedback.attachments.map((att, idx) => ( - - {att.name} - - ))} -
    -
    - )} - - {/* Metadata */} -
    -
    System Info
    -
    -

    App Version: {feedback.metadata.appVersion}

    -

    OS: {feedback.metadata.os}

    -

    Submitted: {formatDate(feedback.createdAt)}

    -
    -
    - - {/* Status and Actions */} -
    -
    - - {statusInfo.icon} - {statusInfo.label} - -
    -
    - - -
    -
    -
    -
    - )} -
    -
    - ); - })} -
    - ); -} diff --git a/desktop/src/components/Feedback/FeedbackModal.tsx b/desktop/src/components/Feedback/FeedbackModal.tsx deleted file mode 100644 index a90e8e6..0000000 --- a/desktop/src/components/Feedback/FeedbackModal.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import { useState, useRef } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { X, Send, Bug, Lightbulb, MessageSquare, AlertCircle, Upload, Trash2 } from 'lucide-react'; -import { useFeedbackStore, type FeedbackType, type FeedbackPriority, type FeedbackAttachment } from './feedbackStore'; -import { Button } from '../ui'; -import { useToast } from '../ui/Toast'; -import { silentErrorHandler } from '../../lib/error-utils'; - -interface FeedbackModalProps { - onClose: () => void; -} - -const typeOptions: { value: FeedbackType; label: string; icon: React.ReactNode }[] = [ - { value: 'bug', label: 'Bug Report', icon: }, - { value: 'feature', label: 'Feature Request', icon: }, - { value: 'general', label: 'General Feedback', icon: }, -]; - -const priorityOptions: { value: FeedbackPriority; label: string; color: string }[] = [ - { value: 'low', label: 'Low', color: 'text-gray-500' }, - { value: 'medium', label: 'Medium', color: 'text-yellow-600' }, - { value: 'high', label: 'High', color: 'text-red-500' }, -]; - -export function FeedbackModal({ onClose }: FeedbackModalProps) { - const { submitFeedback, isLoading, error } = useFeedbackStore(); - const { toast } = useToast(); - const fileInputRef = useRef(null); - - const [type, setType] = useState('bug'); - const [title, setTitle] = useState(''); - const [description, setDescription] = useState(''); - const [priority, setPriority] = useState('medium'); - const [attachments, setAttachments] = useState([]); - - const handleSubmit = async () => { - if (!title.trim() || !description.trim()) { - toast('Please fill in title and description', 'warning'); - return; - } - - // Convert files to base64 for storage - const processedAttachments: FeedbackAttachment[] = await Promise.all( - attachments.map(async (file) => { - return new Promise((resolve) => { - const reader = new FileReader(); - reader.onload = () => { - resolve({ - name: file.name, - type: file.type, - size: file.size, - data: reader.result as string, - }); - }; - reader.readAsDataURL(file); - }); - }) - ); - - try { - await submitFeedback({ - type, - title: title.trim(), - description: description.trim(), - priority, - attachments: processedAttachments, - metadata: { - appVersion: '0.0.0', - os: navigator.platform, - timestamp: Date.now(), - }, - }); - - toast('Feedback submitted successfully!', 'success'); - // Reset form - setTitle(''); - setDescription(''); - setAttachments([]); - setType('bug'); - setPriority('medium'); - onClose(); - } catch (err) { - toast('Failed to submit feedback. Please try again.', 'error'); - } - }; - - const handleFileSelect = (e: React.ChangeEvent) => { - const files = Array.from(e.target.files || []); - // Limit to 5 attachments - const newFiles = [...attachments, ...files].slice(0, 5); - setAttachments(newFiles); - }; - - const removeAttachment = (index: number) => { - setAttachments(attachments.filter((_, i) => i !== index)); - }; - - const formatFileSize = (bytes: number): string => { - if (bytes < 1024) return `${bytes} B`; - if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; - return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; - }; - - return ( - - { - if (e.target === e.currentTarget) onClose(); - }} - > - - {/* Header */} -
    -

    - Submit Feedback -

    - -
    - - {/* Content */} -
    - {/* Type Selection */} -
    - -
    - {typeOptions.map((opt) => ( - - ))} -
    -
    - - {/* Title */} -
    - - setTitle(e.target.value)} - placeholder="Brief summary of your feedback" - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-orange-400 dark:bg-gray-700 dark:text-gray-100" - maxLength={100} - /> -
    - - {/* Description */} -
    - -