diff --git a/Cargo.lock b/Cargo.lock index 08dcc63cb..aaa52bd5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -845,9 +845,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.47" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ "find-msvc-tools", "jobserver", @@ -950,7 +950,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "codex-app-server-protocol" version = "0.63.0" -source = "git+https://github.com/namastexlabs/codex?branch=main#885fa3a11c439c82a577a02c2bccb81464aa11d4" +source = "git+https://github.com/namastexlabs/codex?branch=main#27dd137e257b3e2b1857ebb02113178e064722c7" dependencies = [ "anyhow", "clap", @@ -968,7 +968,7 @@ dependencies = [ [[package]] name = "codex-git" version = "0.63.0" -source = "git+https://github.com/namastexlabs/codex?branch=main#885fa3a11c439c82a577a02c2bccb81464aa11d4" +source = "git+https://github.com/namastexlabs/codex?branch=main#27dd137e257b3e2b1857ebb02113178e064722c7" dependencies = [ "once_cell", "regex", @@ -983,7 +983,7 @@ dependencies = [ [[package]] name = "codex-protocol" version = "0.63.0" -source = "git+https://github.com/namastexlabs/codex?branch=main#885fa3a11c439c82a577a02c2bccb81464aa11d4" +source = "git+https://github.com/namastexlabs/codex?branch=main#27dd137e257b3e2b1857ebb02113178e064722c7" dependencies = [ "base64 0.22.1", "codex-git", @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "codex-utils-cache" version = "0.63.0" -source = "git+https://github.com/namastexlabs/codex?branch=main#885fa3a11c439c82a577a02c2bccb81464aa11d4" +source = "git+https://github.com/namastexlabs/codex?branch=main#27dd137e257b3e2b1857ebb02113178e064722c7" dependencies = [ "lru", "sha1", @@ -1018,7 +1018,7 @@ dependencies = [ [[package]] name = "codex-utils-image" version = "0.63.0" -source = "git+https://github.com/namastexlabs/codex?branch=main#885fa3a11c439c82a577a02c2bccb81464aa11d4" +source = "git+https://github.com/namastexlabs/codex?branch=main#27dd137e257b3e2b1857ebb02113178e064722c7" dependencies = [ "base64 0.22.1", "codex-utils-cache", @@ -2830,9 +2830,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -3163,7 +3163,7 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mcp-types" version = "0.63.0" -source = "git+https://github.com/namastexlabs/codex?branch=main#885fa3a11c439c82a577a02c2bccb81464aa11d4" +source = "git+https://github.com/namastexlabs/codex?branch=main#27dd137e257b3e2b1857ebb02113178e064722c7" dependencies = [ "schemars 1.1.0", "serde", @@ -3275,9 +3275,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" +checksum = "80986bbbcf925ebd3be54c26613d861255284584501595cf418320c078945608" dependencies = [ "num-traits", "pxfm", @@ -4103,9 +4103,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" +checksum = "b3502d6155304a4173a5f2c34b52b7ed0dd085890326cb50fd625fdf39e86b3b" dependencies = [ "num-traits", ] @@ -4487,9 +4487,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" dependencies = [ "zeroize", ] @@ -4888,9 +4888,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.16.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64 0.22.1", "chrono", @@ -4907,9 +4907,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.16.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", @@ -5962,9 +5962,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "log", "pin-project-lite", @@ -6006,9 +6006,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", @@ -6365,9 +6365,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -6378,9 +6378,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.55" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -6391,9 +6391,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6401,9 +6401,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ "bumpalo", "proc-macro2", @@ -6414,18 +6414,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.82" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/forge-app/Cargo.toml b/forge-app/Cargo.toml index 213702706..4009838b9 100644 --- a/forge-app/Cargo.toml +++ b/forge-app/Cargo.toml @@ -12,6 +12,10 @@ path = "src/main.rs" name = "generate-forge-types" path = "src/bin/generate_forge_types.rs" +[[bin]] +name = "forge-cleanup" +path = "src/bin/cleanup.rs" + [lib] name = "forge_app" crate-type = ["cdylib", "rlib"] diff --git a/forge-app/build.rs b/forge-app/build.rs index 3c82cc4c1..66bc0b623 100644 --- a/forge-app/build.rs +++ b/forge-app/build.rs @@ -1,6 +1,23 @@ +use std::{fs, path::Path}; + fn main() { + // macOS framework linking if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("macos") { println!("cargo:rustc-link-lib=framework=AppKit"); println!("cargo:rustc-link-lib=framework=Foundation"); } + + // Create frontend/dist directory if it doesn't exist + let dist_path = Path::new("../frontend/dist"); + if !dist_path.exists() { + println!("cargo:warning=Creating dummy frontend/dist directory for compilation"); + fs::create_dir_all(dist_path).unwrap(); + + // Create a dummy index.html + let dummy_html = r#" +Build frontend first +

Please build the frontend

"#; + + fs::write(dist_path.join("index.html"), dummy_html).unwrap(); + } } diff --git a/forge-app/openapi.yaml b/forge-app/openapi.yaml index 0eb3b055e..ea775bba4 100644 --- a/forge-app/openapi.yaml +++ b/forge-app/openapi.yaml @@ -344,6 +344,12 @@ paths: base_branch: type: string example: main + github_issue_id: + type: integer + format: int64 + nullable: true + description: GitHub issue ID linking this task to its originating issue (enforces "No Wish Without Issue" rule) + example: 123 required: [task, executor_profile_id, base_branch] responses: '200': @@ -899,6 +905,11 @@ components: type: string format: uuid nullable: true + github_issue_id: + type: integer + format: int64 + nullable: true + description: GitHub issue ID linking this task to its originating issue (enforces "No Wish Without Issue" rule) created_at: type: string format: date-time @@ -926,6 +937,12 @@ components: type: string format: uuid nullable: true + github_issue_id: + type: integer + format: int64 + nullable: true + description: GitHub issue ID linking this task to its originating issue (enforces "No Wish Without Issue" rule) + example: 123 required: [project_id, title] UpdateTask: diff --git a/forge-app/src/bin/cleanup.rs b/forge-app/src/bin/cleanup.rs new file mode 100644 index 000000000..6b5e3dc3a --- /dev/null +++ b/forge-app/src/bin/cleanup.rs @@ -0,0 +1,348 @@ +//! Forge Cleanup - Cleanup stale worktrees +//! +//! Scans the worktree temp directory, compares with active task_attempts +//! in the database, and identifies/removes orphaned worktrees. + +use std::collections::HashSet; +use std::path::PathBuf; + +use anyhow::{Context, Result}; +use sqlx::{Row, SqlitePool}; + +/// Get the worktree base directory +fn get_worktree_base_dir() -> PathBuf { + utils::path::get_automagik_forge_temp_dir().join("worktrees") +} + +/// Get database URL +/// +/// TODO: This logic is duplicated from the db crate (db::DBService::get_database_url). +/// Consider exposing it from a shared utility crate to avoid maintenance issues. +fn get_database_url() -> String { + if let Ok(db_url) = std::env::var("DATABASE_URL") { + if db_url.starts_with("sqlite://") { + let path_part = db_url.strip_prefix("sqlite://").unwrap(); + if PathBuf::from(path_part).is_absolute() { + db_url + } else { + let abs_path = std::env::current_dir() + .unwrap_or_else(|_| PathBuf::from(".")) + .join(path_part); + format!("sqlite://{}", abs_path.to_string_lossy()) + } + } else { + db_url + } + } else { + format!( + "sqlite://{}", + utils::assets::asset_dir().join("db.sqlite").to_string_lossy() + ) + } +} + +/// Worktree info with size +#[derive(Debug)] +struct WorktreeInfo { + path: PathBuf, + name: String, + size_bytes: u64, +} + +impl WorktreeInfo { + /// Format a byte size as human-readable string + fn format_size(size_bytes: u64) -> String { + const KB: u64 = 1024; + const MB: u64 = 1024 * KB; + const GB: u64 = 1024 * MB; + + if size_bytes >= GB { + format!("{:.2} GB", size_bytes as f64 / GB as f64) + } else if size_bytes >= MB { + format!("{:.2} MB", size_bytes as f64 / MB as f64) + } else if size_bytes >= KB { + format!("{:.2} KB", size_bytes as f64 / KB as f64) + } else { + format!("{} bytes", size_bytes) + } + } + + /// Get human-readable size for this worktree + fn size_human(&self) -> String { + Self::format_size(self.size_bytes) + } +} + +/// Calculate directory size recursively +fn dir_size(path: &PathBuf) -> u64 { + let mut size = 0u64; + if let Ok(entries) = std::fs::read_dir(path) { + for entry_result in entries { + match entry_result { + Ok(entry) => { + let entry_path = entry.path(); + if entry_path.is_dir() { + size += dir_size(&entry_path); + } else if let Ok(metadata) = entry_path.metadata() { + size += metadata.len(); + } + } + Err(e) => { + eprintln!( + "Warning: Failed to read entry in {}: {}", + path.display(), + e + ); + } + } + } + } + size +} + +/// Scan worktree directory for all worktrees +fn scan_worktree_directory(base_dir: &PathBuf) -> Result> { + let mut worktrees = Vec::new(); + + if !base_dir.exists() { + return Ok(worktrees); + } + + let entries = std::fs::read_dir(base_dir) + .with_context(|| format!("Failed to read worktree directory: {}", base_dir.display()))?; + + for entry_result in entries { + match entry_result { + Ok(entry) => { + let path = entry.path(); + if path.is_dir() { + let name = path + .file_name() + .map(|n| n.to_string_lossy().into_owned()) + .unwrap_or_else(|| "unknown".to_string()); + let size_bytes = dir_size(&path); + worktrees.push(WorktreeInfo { + path, + name, + size_bytes, + }); + } + } + Err(e) => { + eprintln!( + "Warning: Failed to read worktree directory entry in {}: {}", + base_dir.display(), + e + ); + } + } + } + + Ok(worktrees) +} + +/// Get active worktree paths from database (where worktree_deleted = false) +async fn get_active_worktree_paths(pool: &SqlitePool) -> Result> { + let records = sqlx::query( + "SELECT container_ref FROM task_attempts WHERE worktree_deleted = FALSE AND container_ref IS NOT NULL", + ) + .fetch_all(pool) + .await + .context("Failed to query task_attempts")?; + + Ok(records + .into_iter() + .filter_map(|r| r.get::, _>("container_ref")) + .collect()) +} + +/// Find orphan worktrees (on disk but not in database) +fn find_orphans<'a>( + disk_worktrees: &'a [WorktreeInfo], + db_paths: &HashSet, +) -> Vec<&'a WorktreeInfo> { + disk_worktrees + .iter() + .filter(|wt| { + let path_str = wt.path.to_string_lossy().to_string(); + !db_paths.contains(&path_str) + }) + .collect() +} + +/// Delete a worktree directory +fn delete_worktree(path: &PathBuf) -> Result<()> { + std::fs::remove_dir_all(path) + .with_context(|| format!("Failed to delete worktree: {}", path.display()))?; + Ok(()) +} + +fn print_usage() { + eprintln!("Usage: forge cleanup [--force]"); + eprintln!(); + eprintln!("Cleanup stale worktrees that are no longer referenced by active tasks."); + eprintln!(); + eprintln!("Options:"); + eprintln!(" --force, -f Actually delete orphan worktrees (default: dry run)"); + eprintln!(" --help, -h Show this help message"); +} + +#[tokio::main] +async fn main() -> Result<()> { + // Parse arguments - search through all args for flags + let args: Vec = std::env::args().collect(); + let force = args.iter().any(|a| a == "--force" || a == "-f"); + let help = args.iter().any(|a| a == "--help" || a == "-h"); + + if help { + print_usage(); + return Ok(()); + } + + // Get paths + let worktree_base = get_worktree_base_dir(); + let db_url = get_database_url(); + + println!("Forge Cleanup - Stale Worktree Removal"); + println!("======================================"); + println!(); + println!("Worktree directory: {}", worktree_base.display()); + println!("Database: {}", db_url.replace("sqlite://", "")); + println!(); + + // Check if worktree directory exists + if !worktree_base.exists() { + println!("Worktree directory does not exist. Nothing to clean up."); + return Ok(()); + } + + // Scan disk for worktrees + println!("Scanning worktree directory..."); + let disk_worktrees = scan_worktree_directory(&worktree_base)?; + println!("Found {} worktrees on disk", disk_worktrees.len()); + println!(); + + if disk_worktrees.is_empty() { + println!("No worktrees found. Nothing to clean up."); + return Ok(()); + } + + // Connect to database + println!("Connecting to database..."); + let db_path = db_url.replace("sqlite://", ""); + if !PathBuf::from(&db_path).exists() { + println!("Database file does not exist: {}", db_path); + println!("All worktrees on disk are orphans (no database to reference)."); + println!(); + + // All worktrees are orphans + let total_size: u64 = disk_worktrees.iter().map(|w| w.size_bytes).sum(); + println!( + "Orphan worktrees: {} (total: {})", + disk_worktrees.len(), + WorktreeInfo::format_size(total_size) + ); + + if !force { + println!(); + println!("Run with --force to delete these worktrees."); + return Ok(()); + } + + // Delete all + let mut recovered = 0u64; + for wt in &disk_worktrees { + print!(" Deleting {}... ", wt.name); + match delete_worktree(&wt.path) { + Ok(()) => { + println!("done ({})", wt.size_human()); + recovered += wt.size_bytes; + } + Err(e) => println!("FAILED: {}", e), + } + } + + println!(); + println!("Space recovered: {}", WorktreeInfo::format_size(recovered)); + return Ok(()); + } + + let pool = SqlitePool::connect(&db_url) + .await + .context("Failed to connect to database")?; + + // Get active worktree paths from database + println!("Querying active task attempts..."); + let db_paths = get_active_worktree_paths(&pool).await?; + println!( + "Found {} active worktree references in database", + db_paths.len() + ); + println!(); + + // Find orphans + let orphans = find_orphans(&disk_worktrees, &db_paths); + + if orphans.is_empty() { + println!("No orphan worktrees found. All worktrees are referenced by active tasks."); + return Ok(()); + } + + // Calculate total orphan size + let total_orphan_size: u64 = orphans.iter().map(|w| w.size_bytes).sum(); + + println!( + "Found {} orphan worktrees (not referenced by any active task):", + orphans.len() + ); + println!(); + for wt in &orphans { + println!(" {} - {}", wt.name, wt.size_human()); + } + println!(); + println!( + "Total orphan size: {}", + WorktreeInfo::format_size(total_orphan_size) + ); + + if !force { + println!(); + println!("This is a dry run. Run with --force to delete these worktrees."); + return Ok(()); + } + + // Delete orphans + println!(); + println!("Deleting orphan worktrees..."); + let mut recovered = 0u64; + let mut deleted_count = 0; + let mut failed_count = 0; + + for wt in &orphans { + print!(" Deleting {}... ", wt.name); + match delete_worktree(&wt.path) { + Ok(()) => { + println!("done ({})", wt.size_human()); + recovered += wt.size_bytes; + deleted_count += 1; + } + Err(e) => { + println!("FAILED: {}", e); + failed_count += 1; + } + } + } + + println!(); + println!("Summary:"); + println!(" Deleted: {}", deleted_count); + if failed_count > 0 { + println!(" Failed: {}", failed_count); + } + println!( + " Space recovered: {}", + WorktreeInfo::format_size(recovered) + ); + + Ok(()) +} diff --git a/forge-app/src/lib.rs b/forge-app/src/lib.rs index aac116125..f7ff9df85 100644 --- a/forge-app/src/lib.rs +++ b/forge-app/src/lib.rs @@ -2,6 +2,7 @@ //! //! Provides reusable modules for forge binaries. +pub mod routes; pub mod router; pub mod services; pub mod version; diff --git a/forge-app/src/router.rs b/forge-app/src/router.rs index 927b510b8..0ee2d44c2 100644 --- a/forge-app/src/router.rs +++ b/forge-app/src/router.rs @@ -2,85 +2,31 @@ //! //! Routes forge-specific APIs under `/api/forge/*` and upstream APIs under `/api/*`. //! Serves single frontend (with overlay architecture) at `/`. +//! +//! This module acts as a thin composition layer that imports domain-specific +//! route handlers from the `routes/` module. use axum::{ - Json, Router, - extract::{ - FromRef, Path, Query, State, - ws::{WebSocket, WebSocketUpgrade}, - }, - http::{HeaderValue, Method, StatusCode, header}, - response::{Html, IntoResponse, Response}, + Router, + http::Method, routing::{get, post}, }; -use futures_util::{SinkExt, StreamExt, TryStreamExt}; -use rust_embed::RustEmbed; -use serde::{Deserialize, Serialize}; -use serde_json::{Value, json}; -use std::collections::HashSet; -use std::sync::Arc; -use std::time::Duration; -use tokio::sync::RwLock; use tower_http::cors::{Any, CorsLayer}; -use uuid::Uuid; -use crate::services::ForgeServices; -use db::models::{ - image::TaskImage, - task::{Task, TaskWithAttemptStatus}, - task_attempt::{CreateTaskAttempt, TaskAttempt}, +use crate::routes::{ + ForgeAppState, + agents, attempts, config, frontend, omni, projects, tasks, }; -use deployment::Deployment; -use executors::profile::ExecutorProfileId; -use forge_config::ForgeProjectSettings; -use server::routes::{ - self as upstream, approvals, auth, config as upstream_config, containers, drafts, events, - execution_processes, filesystem, images, projects, tags, task_attempts, tasks, +use crate::services::ForgeServices; +use server::{ + DeploymentImpl, + routes::{ + self as upstream, approvals, auth, containers, drafts, events, + execution_processes, filesystem, images, projects as upstream_projects, + }, }; -use server::{DeploymentImpl, error::ApiError, routes::tasks::CreateAndStartTaskRequest}; -use services::services::container::ContainerService; -use sqlx::{self, Error as SqlxError, Row}; -use utils::log_msg::LogMsg; -use utils::response::ApiResponse; -use utils::text::{git_branch_id, short_uuid}; - -#[derive(RustEmbed)] -#[folder = "../frontend/dist"] -struct Frontend; - -/// Type alias for TaskWithAttemptStatus which now includes attempt_count from upstream. -/// Kept for API compatibility during transition. -pub type ForgeTaskWithAttemptStatus = TaskWithAttemptStatus; - -#[derive(Clone)] -struct ForgeAppState { - services: ForgeServices, - deployment: DeploymentImpl, - auth_required: bool, -} - -impl ForgeAppState { - fn new(services: ForgeServices, deployment: DeploymentImpl, auth_required: bool) -> Self { - Self { - services, - deployment, - auth_required, - } - } -} - -impl FromRef for ForgeServices { - fn from_ref(state: &ForgeAppState) -> ForgeServices { - state.services.clone() - } -} - -impl FromRef for DeploymentImpl { - fn from_ref(state: &ForgeAppState) -> DeploymentImpl { - state.deployment.clone() - } -} +/// Create the main application router pub fn create_router(services: ForgeServices, auth_required: bool) -> Router { let deployment = services.deployment.as_ref().clone(); let state = ForgeAppState::new(services, deployment.clone(), auth_required); @@ -100,544 +46,84 @@ pub fn create_router(services: ForgeServices, auth_required: bool) -> Router { .allow_headers(Any); Router::new() - .route("/health", get(health_check)) - .route("/docs", get(serve_swagger_ui)) - .route("/api/openapi.json", get(serve_openapi_spec)) - .route("/api/routes", get(list_routes)) - // Public PWA manifest - must be accessible without authentication - .route("/site.webmanifest", get(serve_assets_public)) + .route("/health", get(frontend::health_check)) + .route("/docs", get(frontend::serve_swagger_ui)) + .route("/api/openapi.json", get(frontend::serve_openapi_spec)) + .route("/api/routes", get(frontend::list_routes)) .merge(forge_api_routes()) // Upstream API at /api .nest("/api", upstream_api) // Single frontend with overlay architecture - .fallback(frontend_handler) + .fallback(frontend::frontend_handler) .layer(cors) .with_state(state) } +/// Forge-specific API routes under /api/forge/* fn forge_api_routes() -> Router { Router::new() - .route("/api/forge/auth-required", get(get_auth_required)) + .route("/api/forge/auth-required", get(config::get_auth_required)) .route( "/api/forge/config", - get(get_forge_config).put(update_forge_config), + get(config::get_forge_config).put(config::update_forge_config), ) .route( "/api/forge/projects/{project_id}/settings", - get(get_project_settings).put(update_project_settings), + get(projects::get_project_settings).put(projects::update_project_settings), ) .route( "/api/forge/projects/{project_id}/profiles", - get(get_project_profiles), - ) - .route( - "/api/forge/projects/{project_id}/branch-status", - get(get_project_branch_status), + get(projects::get_project_profiles), ) - .route( - "/api/forge/projects/{project_id}/pull", - post(post_project_pull), - ) - .route("/api/forge/omni/status", get(get_omni_status)) - .route("/api/forge/omni/instances", get(list_omni_instances)) - .route("/api/forge/omni/validate", post(validate_omni_config)) + .route("/api/forge/omni/status", get(omni::get_omni_status)) + .route("/api/forge/omni/instances", get(omni::list_omni_instances)) + .route("/api/forge/omni/validate", post(omni::validate_omni_config)) .route( "/api/forge/omni/notifications", - get(list_omni_notifications), + get(omni::list_omni_notifications), ) - .route("/api/forge/releases", get(get_github_releases)) + .route("/api/forge/releases", get(frontend::get_github_releases)) .route( "/api/forge/master-genie/{attempt_id}/neurons", - get(get_master_genie_neurons), + get(agents::get_master_genie_neurons), ) .route( "/api/forge/neurons/{neuron_attempt_id}/subtasks", - get(get_neuron_subtasks), + get(agents::get_neuron_subtasks), ) .route( "/api/forge/agents", - get(get_forge_agents).post(create_forge_agent), + get(agents::get_forge_agents).post(agents::create_forge_agent), ) - // Branch-templates extension removed - using simple forge/ prefix -} - -/// Forge-specific CreateTask that includes is_agent field -#[derive(Debug, Serialize, Deserialize)] -struct ForgeCreateTask { - pub project_id: Uuid, - pub title: String, - pub description: Option, - pub parent_task_attempt: Option, - pub image_ids: Option>, - pub is_agent: Option, // Forge extension: mark as agent-managed task -} - -/// Forge override: create task (standard behavior, no special status handling) -/// The is_agent field is kept for future use but not currently used in task creation -async fn forge_create_task( - State(deployment): State, - Json(payload): Json, -) -> Result>, ApiError> { - let task_id = Uuid::new_v4(); - let task = Task::create( - &deployment.db().pool, - &db::models::task::CreateTask { - project_id: payload.project_id, - title: payload.title, - description: payload.description, - parent_task_attempt: payload.parent_task_attempt, - image_ids: payload.image_ids.clone(), - }, - task_id, - ) - .await?; - - if let Some(image_ids) = &payload.image_ids { - TaskImage::associate_many(&deployment.db().pool, task.id, image_ids).await?; - } - - deployment - .track_if_analytics_allowed( - "task_created", - serde_json::json!({ - "task_id": task.id.to_string(), - "project_id": task.project_id, - "has_description": task.description.is_some(), - "has_images": payload.image_ids.is_some(), - }), - ) - .await; - - Ok(Json(ApiResponse::success(task))) -} - -/// Forge-specific CreateTaskAttemptBody that includes use_worktree field -#[derive(Debug, Serialize, Deserialize)] -struct ForgeCreateTaskAttemptBody { - pub task_id: Uuid, - pub executor_profile_id: ExecutorProfileId, - pub base_branch: String, - pub use_worktree: Option, -} - -impl ForgeCreateTaskAttemptBody { - pub fn get_executor_profile_id(&self) -> ExecutorProfileId { - self.executor_profile_id.clone() - } -} - -/// Forge override: create task attempt with forge/ branch prefix (vk -> forge only) -async fn forge_create_task_attempt( - State(deployment): State, - State(forge_services): State, - Json(payload): Json, -) -> Result>, ApiError> { - let executor_profile_id = payload.get_executor_profile_id(); - let task = Task::find_by_id(&deployment.db().pool, payload.task_id) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - let attempt_id = Uuid::new_v4(); - let use_worktree = payload.use_worktree.unwrap_or(true); - - // If use_worktree is false, use the current branch (base_branch) directly - // Otherwise, generate a new branch name for the worktree with "forge" prefix - let git_branch_name = if use_worktree { - let task_title_id = git_branch_id(&task.title); - let short_id = short_uuid(&attempt_id); - format!("forge/{}-{}", short_id, task_title_id) - } else { - payload.base_branch.clone() - }; - - let mut task_attempt = TaskAttempt::create( - &deployment.db().pool, - &CreateTaskAttempt { - executor: executor_profile_id.executor, - base_branch: payload.base_branch.clone(), - branch: git_branch_name.clone(), - }, - attempt_id, - payload.task_id, - ) - .await?; - - // Insert use_worktree flag into forge_task_attempt_config - sqlx::query( - "INSERT INTO forge_task_attempt_config (task_attempt_id, use_worktree) VALUES (?, ?)", - ) - .bind(attempt_id) - .bind(use_worktree) - .execute(&deployment.db().pool) - .await?; - - // Store executor with variant for agent task filtering - if let Some(variant) = &executor_profile_id.variant { - let executor_with_variant = format!("{}:{}", executor_profile_id.executor, variant); - sqlx::query( - "UPDATE task_attempts SET executor = ?, updated_at = datetime('now') WHERE id = ?", - ) - .bind(&executor_with_variant) - .bind(attempt_id) - .execute(&deployment.db().pool) - .await?; - task_attempt.executor = executor_with_variant; - } - - // Get project to determine workspace root - let project = task - .parent_project(&deployment.db().pool) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - // Load workspace-specific .genie profiles and inject into global cache just-in-time - if let Ok(workspace_profiles) = forge_services - .load_profiles_for_workspace(&project.git_repo_path) - .await - { - // Log profile details for validation - let variant_count = workspace_profiles - .executors - .values() - .map(|config| config.configurations.len()) - .sum::(); - - let variant_list: Vec = workspace_profiles - .executors - .iter() - .flat_map(|(executor, config)| { - config - .configurations - .iter() - .map(move |(variant, coding_agent)| { - // Extract append_prompt from the CodingAgent enum - let prompt_preview = match coding_agent { - executors::executors::CodingAgent::ClaudeCode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Codex(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Amp(cfg) => cfg.append_prompt.get(), - executors::executors::CodingAgent::Gemini(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Opencode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::CursorAgent(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::QwenCode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Copilot(cfg) => { - cfg.append_prompt.get() - } - } - .map(|p| { - let trimmed = p.trim(); - if trimmed.len() > 60 { - format!("{}...", &trimmed[..60]) - } else { - trimmed.to_string() - } - }) - .unwrap_or_else(|| "".to_string()); - - format!("{}:{} ({})", executor, variant, prompt_preview) - }) - }) - .collect(); - - tracing::info!( - "🔧 Injected {} .genie profile variant(s) for workspace: {} | Profiles: [{}]", - variant_count, - project.git_repo_path.display(), - variant_list.join(", ") - ); - - executors::profile::ExecutorConfigs::set_cached(workspace_profiles); - - // Register project in profile cache for subsequent API lookups - forge_services - .profile_cache - .register_project(project.id, project.git_repo_path.clone()) - .await; - } else { - tracing::warn!( - "âš ī¸ Failed to load .genie profiles for workspace: {}, using defaults", - project.git_repo_path.display() - ); - } - - let _execution_process = deployment - .container() - .start_attempt(&task_attempt, executor_profile_id.clone()) - .await?; - - deployment - .track_if_analytics_allowed( - "task_attempt_started", - serde_json::json!({ - "task_id": task.id.to_string(), - "executor": &executor_profile_id.executor, - "attempt_id": task_attempt.id.to_string(), - }), - ) - .await; - - Ok(Json(ApiResponse::success(task_attempt))) -} - -/// Forge override: create task and start with forge/ branch prefix (vk -> forge only) -async fn forge_create_task_and_start( - State(deployment): State, - State(forge_services): State, - Json(payload): Json, -) -> Result>, ApiError> { - let task_id = Uuid::new_v4(); - let task = Task::create(&deployment.db().pool, &payload.task, task_id).await?; - - if let Some(image_ids) = &payload.task.image_ids { - TaskImage::associate_many(&deployment.db().pool, task.id, image_ids).await?; - } - - // If this is a non-worktree task (Genie chat), register in forge_agents to hide from kanban - let use_worktree = payload.use_worktree.unwrap_or(true); - if !use_worktree { - // Use transaction for atomicity (both succeed or both fail) - let mut tx = deployment.db().pool.begin().await?; - - sqlx::query( - r#"INSERT INTO forge_agents (id, project_id, agent_type, task_id, created_at, updated_at) - VALUES (?, ?, 'genie_chat', ?, datetime('now'), datetime('now'))"#, - ) - .bind(Uuid::new_v4()) - .bind(task.project_id) - .bind(task.id) - .execute(&mut *tx) - .await?; - - // Also set task status to 'agent' so it's filtered from kanban board - sqlx::query( - "UPDATE tasks SET status = 'agent', updated_at = datetime('now') WHERE id = ?", - ) - .bind(task.id) - .execute(&mut *tx) - .await?; - - tx.commit().await?; - } - - deployment - .track_if_analytics_allowed( - "task_created", - serde_json::json!({ - "task_id": task.id.to_string(), - "project_id": task.project_id, - "has_description": task.description.is_some(), - "has_images": payload.task.image_ids.is_some(), - }), - ) - .await; - - let task_attempt_id = Uuid::new_v4(); - - // Branch naming respects use_worktree: if false, run on base branch directly (no worktree isolation) - let branch_name = if use_worktree { - // Use same logic as upstream but replace "vk" with "forge" prefix - let task_title_id = git_branch_id(&task.title); - let short_id = short_uuid(&task_attempt_id); - format!("forge/{}-{}", short_id, task_title_id) - } else { - // Non-worktree mode: run directly on base branch (e.g., Genie chat) - payload.base_branch.clone() - }; - - let mut task_attempt = TaskAttempt::create( - &deployment.db().pool, - &CreateTaskAttempt { - executor: payload.executor_profile_id.executor, - base_branch: payload.base_branch.clone(), - branch: branch_name, - }, - task_attempt_id, - task.id, - ) - .await?; - - // Insert use_worktree flag into forge_task_attempt_config - sqlx::query( - "INSERT INTO forge_task_attempt_config (task_attempt_id, use_worktree) VALUES (?, ?)", - ) - .bind(task_attempt_id) - .bind(use_worktree) - .execute(&deployment.db().pool) - .await?; - - // Store executor with variant for agent task filtering - if let Some(variant) = &payload.executor_profile_id.variant { - let executor_with_variant = format!("{}:{}", payload.executor_profile_id.executor, variant); - sqlx::query( - "UPDATE task_attempts SET executor = ?, updated_at = datetime('now') WHERE id = ?", - ) - .bind(&executor_with_variant) - .bind(task_attempt_id) - .execute(&deployment.db().pool) - .await?; - task_attempt.executor = executor_with_variant; - } - - // Get project to determine workspace root - let project = task - .parent_project(&deployment.db().pool) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - // Load workspace-specific .genie profiles and inject into global cache just-in-time - if let Ok(workspace_profiles) = forge_services - .load_profiles_for_workspace(&project.git_repo_path) - .await - { - // Log profile details for validation - let variant_count = workspace_profiles - .executors - .values() - .map(|config| config.configurations.len()) - .sum::(); - - let variant_list: Vec = workspace_profiles - .executors - .iter() - .flat_map(|(executor, config)| { - config - .configurations - .iter() - .map(move |(variant, coding_agent)| { - // Extract append_prompt from the CodingAgent enum - let prompt_preview = match coding_agent { - executors::executors::CodingAgent::ClaudeCode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Codex(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Amp(cfg) => cfg.append_prompt.get(), - executors::executors::CodingAgent::Gemini(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Opencode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::CursorAgent(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::QwenCode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Copilot(cfg) => { - cfg.append_prompt.get() - } - } - .map(|p| { - let trimmed = p.trim(); - if trimmed.len() > 60 { - format!("{}...", &trimmed[..60]) - } else { - trimmed.to_string() - } - }) - .unwrap_or_else(|| "".to_string()); - - format!("{}:{} ({})", executor, variant, prompt_preview) - }) - }) - .collect(); - - tracing::info!( - "🔧 Injected {} .genie profile variant(s) for workspace: {} | Profiles: [{}]", - variant_count, - project.git_repo_path.display(), - variant_list.join(", ") - ); - - executors::profile::ExecutorConfigs::set_cached(workspace_profiles); - - // Register project in profile cache for subsequent API lookups - forge_services - .profile_cache - .register_project(project.id, project.git_repo_path.clone()) - .await; - } else { - tracing::warn!( - "âš ī¸ Failed to load .genie profiles for workspace: {}, using defaults", - project.git_repo_path.display() - ); - } - - let execution_process = deployment - .container() - .start_attempt(&task_attempt, payload.executor_profile_id.clone()) - .await?; - - deployment - .track_if_analytics_allowed( - "task_attempt_started", - serde_json::json!({ - "task_id": task.id.to_string(), - "executor": &payload.executor_profile_id.executor, - "variant": &payload.executor_profile_id.variant, - "attempt_id": task_attempt.id.to_string(), - }), - ) - .await; - - let task = Task::find_by_id(&deployment.db().pool, task.id) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - tracing::info!( - "Started execution process {} with forge/ branch", - execution_process.id - ); - Ok(Json(ApiResponse::success(TaskWithAttemptStatus { - task, - has_in_progress_attempt: true, - has_merged_attempt: false, - last_attempt_failed: false, - executor: task_attempt.executor, - attempt_count: 1, // First attempt just created - }))) } +/// Upstream API router - merges VK server routes with forge overrides fn upstream_api_router(deployment: &DeploymentImpl) -> Router { let mut router = Router::new().route("/health", get(upstream::health::health_check)); let dep_clone = deployment.clone(); // Forge override: config router with increased body limit for /profiles - router = router.merge(forge_config_router().with_state::(dep_clone.clone())); + router = router.merge(config::forge_config_router().with_state::(dep_clone.clone())); router = router.merge(containers::router(deployment).with_state::(dep_clone.clone())); router = - router.merge(projects::router(deployment).with_state::(dep_clone.clone())); + router.merge(upstream_projects::router(deployment).with_state::(dep_clone.clone())); router = router.merge(drafts::router(deployment).with_state::(dep_clone.clone())); - // Build custom tasks router with forge override (already typed as ForgeAppState) - let tasks_router_with_override = build_tasks_router_with_forge_override(deployment); + // Build custom tasks router with forge override + let tasks_router_with_override = tasks::build_tasks_router_with_forge_override(deployment); router = router.merge(tasks_router_with_override); - // Build custom task_attempts router with forge override (already typed as ForgeAppState) + // Build custom task_attempts router with forge override let task_attempts_router_with_override = - build_task_attempts_router_with_forge_override(deployment); + attempts::build_task_attempts_router_with_forge_override(deployment); router = router.merge(task_attempts_router_with_override); router = router.merge( execution_processes::router(deployment).with_state::(dep_clone.clone()), ); router = router.merge(auth::router(deployment).with_state::(dep_clone.clone())); - router = router.merge(tags::router(deployment).with_state::(dep_clone.clone())); router = router.merge(filesystem::router().with_state::(dep_clone.clone())); router = router.merge(events::router(deployment).with_state::(dep_clone.clone())); @@ -649,1830 +135,9 @@ fn upstream_api_router(deployment: &DeploymentImpl) -> Router { ) } -/// Build tasks router with forge override for create-and-start endpoint -fn build_tasks_router_with_forge_override(deployment: &DeploymentImpl) -> Router { - use axum::middleware::from_fn_with_state; - use server::middleware::load_task_middleware; - - let task_id_router = Router::new() - .route( - "/", - get(tasks::get_task) - .put(tasks::update_task) - .delete(tasks::delete_task), - ) - .layer(from_fn_with_state(deployment.clone(), load_task_middleware)); - - let inner = Router::new() - .route("/", get(forge_get_tasks).post(forge_create_task)) // Forge: override list to exclude agent tasks; creation only - .route("/stream/ws", get(forge_stream_tasks_ws)) // Forge: WebSocket stream with agent filtering - .route("/create-and-start", post(forge_create_task_and_start)) // Forge: create + start - .nest("/{task_id}", task_id_router); - - Router::new().nest("/tasks", inner) -} - -#[derive(Deserialize)] -struct GetTasksParams { - project_id: Uuid, -} - -/// Forge override for list tasks: Exclude agent tasks (those in forge_agents table) -/// Agent tasks are managed separately via /api/forge/agents -async fn forge_get_tasks( - State(deployment): State, - Query(params): Query, -) -> Result>>, ApiError> { - let pool = &deployment.db().pool; - - // Exclude tasks that are registered as agent tasks in forge_agents table - let query_str = r#"SELECT - t.id AS "id", - t.project_id AS "project_id", - t.title, - t.description, - t.status AS "status", - t.parent_task_attempt AS "parent_task_attempt", - t.created_at AS "created_at", - t.updated_at AS "updated_at", - - CASE WHEN EXISTS ( - SELECT 1 - FROM task_attempts ta - JOIN execution_processes ep - ON ep.task_attempt_id = ta.id - WHERE ta.task_id = t.id - AND ep.status = 'running' - AND ep.run_reason IN ('setupscript','cleanupscript','codingagent') - LIMIT 1 - ) THEN 1 ELSE 0 END AS has_in_progress_attempt, - - CASE WHEN ( - SELECT ep.status - FROM task_attempts ta - JOIN execution_processes ep - ON ep.task_attempt_id = ta.id - WHERE ta.task_id = t.id - AND ep.run_reason IN ('setupscript','cleanupscript','codingagent') - ORDER BY ep.created_at DESC - LIMIT 1 - ) IN ('failed','killed') THEN 1 ELSE 0 END - AS last_attempt_failed, - - ( SELECT ta.executor - FROM task_attempts ta - WHERE ta.task_id = t.id - ORDER BY ta.created_at DESC - LIMIT 1 - ) AS executor, - - ( SELECT COUNT(*) - FROM task_attempts ta - WHERE ta.task_id = t.id - ) AS attempt_count - -FROM tasks t -WHERE t.project_id = ? - AND t.id NOT IN (SELECT task_id FROM forge_agents) -ORDER BY t.created_at DESC"#; - - let rows = sqlx::query(query_str) - .bind(params.project_id) - .fetch_all(pool) - .await?; - - let mut items: Vec = Vec::with_capacity(rows.len()); - for row in rows { - let task_id: Uuid = row.try_get("id").map_err(ApiError::Database)?; - let task = db::models::task::Task::find_by_id(pool, task_id) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - let has_in_progress_attempt = row - .try_get::("has_in_progress_attempt") - .map(|v| v != 0) - .unwrap_or(false); - let last_attempt_failed = row - .try_get::("last_attempt_failed") - .map(|v| v != 0) - .unwrap_or(false); - let executor: String = row.try_get("executor").unwrap_or_else(|_| String::new()); - let attempt_count: i64 = row.try_get::("attempt_count").unwrap_or(0); - - items.push(TaskWithAttemptStatus { - task, - has_in_progress_attempt, - has_merged_attempt: false, - last_attempt_failed, - executor, - attempt_count, - }); - } - - Ok(Json(ApiResponse::success(items))) -} - -/// Forge WebSocket stream handler with agent task filtering -/// Streams tasks for a project via WebSocket, excluding agent tasks -#[derive(Deserialize)] -struct TaskQuery { - project_id: Uuid, -} - -async fn forge_stream_tasks_ws( - ws: WebSocketUpgrade, - State(deployment): State, - Query(query): Query, -) -> impl IntoResponse { - ws.on_upgrade(move |socket| async move { - if let Err(e) = handle_forge_tasks_ws(socket, deployment, query.project_id).await { - tracing::warn!("forge tasks WS closed: {}", e); - } - }) -} - -async fn handle_forge_tasks_ws( - socket: WebSocket, - deployment: DeploymentImpl, - project_id: Uuid, -) -> anyhow::Result<()> { - let pool = deployment.db().pool.clone(); - - // Batch query for all agent task IDs at initialization (fixes N+1 pattern) - let agent_task_ids: Arc>> = { - let agent_tasks: Vec = sqlx::query_scalar( - "SELECT task_id FROM forge_agents fa - INNER JOIN tasks t ON fa.task_id = t.id - WHERE t.project_id = ?", - ) - .bind(project_id) - .fetch_all(&pool) - .await - .unwrap_or_else(|e| { - tracing::warn!( - "Failed to fetch initial agent task IDs for project {}: {}", - project_id, - e - ); - Vec::new() - }); - - Arc::new(RwLock::new(agent_tasks.into_iter().collect())) - }; - - // Spawn background task to refresh agent task IDs periodically - // Store the handle so we can abort it when the WebSocket closes - let refresh_cache = agent_task_ids.clone(); - let refresh_pool = pool.clone(); - let refresh_project_id = project_id; - let refresh_task_handle = tokio::spawn(async move { - let mut interval = tokio::time::interval(Duration::from_secs(5)); - loop { - interval.tick().await; - - match sqlx::query_scalar::<_, Uuid>( - "SELECT task_id FROM forge_agents fa - INNER JOIN tasks t ON fa.task_id = t.id - WHERE t.project_id = ?", - ) - .bind(refresh_project_id) - .fetch_all(&refresh_pool) - .await - { - Ok(tasks) => { - let mut cache = refresh_cache.write().await; - cache.clear(); - cache.extend(tasks); - tracing::trace!( - "Refreshed agent task cache for project {}: {} tasks", - refresh_project_id, - cache.len() - ); - } - Err(e) => { - tracing::warn!( - "Failed to refresh agent task cache for project {}: {}", - refresh_project_id, - e - ); - } - } - } - }); - - // Get the raw stream from upstream (includes initial snapshot + live updates) - // Filter out agent tasks using cache with DB fallback for unknown tasks - let stream = deployment - .events() - .stream_tasks_raw(project_id) - .await? - .filter_map(move |msg_result| { - let agent_task_ids = agent_task_ids.clone(); - let pool = pool.clone(); - async move { - match msg_result { - Ok(LogMsg::JsonPatch(patch)) => { - // Check if this patch contains agent tasks we need to filter out - if let Some(patch_op) = patch.0.first() { - // Handle direct task patches (new format) - if patch_op.path().starts_with("/tasks/") { - match patch_op { - json_patch::PatchOperation::Add(op) => { - if let Ok(task_with_status) = - serde_json::from_value::( - op.value.clone(), - ) - { - let task_id = task_with_status.task.id; - - // First check cache (read lock, released before any await) - let in_cache = { - let cache = agent_task_ids.read().await; - cache.contains(&task_id) - }; - - let is_agent = if in_cache { - true - } else { - // Fallback: DB query for tasks not in cache - // This ensures newly created agent tasks are filtered immediately - let is_agent_db: bool = sqlx::query_scalar( - "SELECT EXISTS(SELECT 1 FROM forge_agents WHERE task_id = ?)", - ) - .bind(task_id) - .fetch_one(&pool) - .await - .unwrap_or_else(|e| { - tracing::warn!( - "Failed to check forge_agents for task {}: {}", - task_id, - e - ); - false - }); - - // If it's an agent, update cache so subsequent patches don't hit DB - if is_agent_db { - let mut cache = agent_task_ids.write().await; - cache.insert(task_id); - } - - is_agent_db - }; - - if !is_agent { - // Upstream patches now include attempt_count, pass through directly - let patch = json_patch::Patch(vec![ - json_patch::PatchOperation::Add( - json_patch::AddOperation { - path: op.path.clone(), - value: op.value.clone(), - }, - ), - ]); - return Some(Ok(LogMsg::JsonPatch(patch))); - } - // Filter out agent tasks - return None; - } - } - json_patch::PatchOperation::Replace(op) => { - if let Ok(task_with_status) = - serde_json::from_value::( - op.value.clone(), - ) - { - let task_id = task_with_status.task.id; - - // First check cache (read lock, released before any await) - let in_cache = { - let cache = agent_task_ids.read().await; - cache.contains(&task_id) - }; - - let is_agent = if in_cache { - true - } else { - // Fallback: DB query for tasks not in cache - // This ensures newly created agent tasks are filtered immediately - let is_agent_db: bool = sqlx::query_scalar( - "SELECT EXISTS(SELECT 1 FROM forge_agents WHERE task_id = ?)", - ) - .bind(task_id) - .fetch_one(&pool) - .await - .unwrap_or_else(|e| { - tracing::warn!( - "Failed to check forge_agents for task {}: {}", - task_id, - e - ); - false - }); - - // If it's an agent, update cache so subsequent patches don't hit DB - if is_agent_db { - let mut cache = agent_task_ids.write().await; - cache.insert(task_id); - } - - is_agent_db - }; - - if !is_agent { - // Upstream patches now include attempt_count, pass through directly - let patch = json_patch::Patch(vec![ - json_patch::PatchOperation::Replace( - json_patch::ReplaceOperation { - path: op.path.clone(), - value: op.value.clone(), - }, - ), - ]); - return Some(Ok(LogMsg::JsonPatch(patch))); - } - // Filter out agent tasks - return None; - } - } - json_patch::PatchOperation::Remove(_) => { - // Allow all remove operations - return Some(Ok(LogMsg::JsonPatch(patch))); - } - _ => {} - } - } - // Handle initial snapshot (replace /tasks with map) - else if patch_op.path() == "/tasks" - && let json_patch::PatchOperation::Replace(op) = patch_op - && let Some(tasks_obj) = op.value.as_object() - { - // Filter out agent tasks from the initial snapshot using hybrid approach - let mut filtered_tasks = serde_json::Map::new(); - for (task_id_str, task_value) in tasks_obj { - if let Ok(task_with_status) = - serde_json::from_value::( - task_value.clone(), - ) - { - let task_id = task_with_status.task.id; - - // First check cache (read lock, released before any await) - let in_cache = { - let cache = agent_task_ids.read().await; - cache.contains(&task_id) - }; - - let is_agent = if in_cache { - true - } else { - // Fallback: DB query for tasks not in cache - // This ensures newly created agent tasks are filtered immediately - let is_agent_db: bool = sqlx::query_scalar( - "SELECT EXISTS(SELECT 1 FROM forge_agents WHERE task_id = ?)", - ) - .bind(task_id) - .fetch_one(&pool) - .await - .unwrap_or_else(|e| { - tracing::warn!( - "Failed to check forge_agents for task {}: {}", - task_id, - e - ); - false - }); - - // If it's an agent, update cache so subsequent patches don't hit DB - if is_agent_db { - let mut cache = agent_task_ids.write().await; - cache.insert(task_id); - } - - is_agent_db - }; - - // Only include non-agent tasks in the filtered snapshot - // Upstream data now includes attempt_count, use directly - if !is_agent { - filtered_tasks.insert( - task_id_str.to_string(), - task_value.clone(), - ); - } - } - } - - // Return filtered snapshot - let filtered_patch = json!([{ - "op": "replace", - "path": "/tasks", - "value": filtered_tasks - }]); - return Some(Ok(LogMsg::JsonPatch( - serde_json::from_value(filtered_patch).unwrap(), - ))); - } - } - // Pass through non-task patches - Some(Ok(LogMsg::JsonPatch(patch))) - } - Ok(other) => Some(Ok(other)), - Err(e) => Some(Err(e)), - } - } - }) - .map_ok(|msg| msg.to_ws_message_unchecked()); - - // Pin the stream for iteration - futures_util::pin_mut!(stream); - - // Split socket into sender and receiver - let (mut sender, mut receiver) = socket.split(); - - // Drain (and ignore) any client->server messages so pings/pongs work - tokio::spawn(async move { while let Some(Ok(_)) = receiver.next().await {} }); - - // Forward server messages - while let Some(item) = stream.next().await { - match item { - Ok(msg) => { - if sender.send(msg).await.is_err() { - break; // client disconnected - } - } - Err(e) => { - tracing::error!("stream error: {}", e); - break; - } - } - } - - // Cancel the background cache refresh task when WebSocket closes - refresh_task_handle.abort(); - - Ok(()) -} - -/// Forge override: inject workspace profiles before follow-up -async fn forge_follow_up( - axum::Extension(task_attempt): axum::Extension, - State(deployment): State, - State(forge_services): State, - Json(payload): Json, -) -> Result>, ApiError> { - // Get task and project to determine workspace root - let task = task_attempt - .parent_task(&deployment.db().pool) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - let project = task - .parent_project(&deployment.db().pool) - .await? - .ok_or(ApiError::Database(SqlxError::RowNotFound))?; - - // Load workspace-specific .genie profiles and inject into global cache just-in-time - if let Ok(workspace_profiles) = forge_services - .load_profiles_for_workspace(&project.git_repo_path) - .await - { - // Log profile details for validation - let variant_count = workspace_profiles - .executors - .values() - .map(|config| config.configurations.len()) - .sum::(); - - let variant_list: Vec = workspace_profiles - .executors - .iter() - .flat_map(|(executor, config)| { - config - .configurations - .iter() - .map(move |(variant, coding_agent)| { - // Extract append_prompt from the CodingAgent enum - let prompt_preview = match coding_agent { - executors::executors::CodingAgent::ClaudeCode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Codex(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Amp(cfg) => cfg.append_prompt.get(), - executors::executors::CodingAgent::Gemini(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Opencode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::CursorAgent(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::QwenCode(cfg) => { - cfg.append_prompt.get() - } - executors::executors::CodingAgent::Copilot(cfg) => { - cfg.append_prompt.get() - } - } - .map(|p| { - let trimmed = p.trim(); - if trimmed.len() > 60 { - format!("{}...", &trimmed[..60]) - } else { - trimmed.to_string() - } - }) - .unwrap_or_else(|| "".to_string()); - - format!("{}:{} ({})", executor, variant, prompt_preview) - }) - }) - .collect(); - - tracing::info!( - "🔧 Injected {} .genie profile variant(s) for workspace: {} (follow-up) | Profiles: [{}]", - variant_count, - project.git_repo_path.display(), - variant_list.join(", ") - ); - - executors::profile::ExecutorConfigs::set_cached(workspace_profiles); - - // Register project in profile cache for subsequent API lookups - forge_services - .profile_cache - .register_project(project.id, project.git_repo_path.clone()) - .await; - } else { - tracing::warn!( - "âš ī¸ Failed to load .genie profiles for workspace: {} (follow-up), using defaults", - project.git_repo_path.display() - ); - } - - // Call upstream follow_up - re-parse JSON into the correct type - let typed_payload: task_attempts::CreateFollowUpAttempt = serde_json::from_value(payload) - .map_err(|e| { - ApiError::TaskAttempt(db::models::task_attempt::TaskAttemptError::ValidationError( - format!("Invalid follow-up payload: {}", e), - )) - })?; - - task_attempts::follow_up( - axum::Extension(task_attempt), - State(deployment), - Json(typed_payload), - ) - .await -} - -/// Forge override for get_task_attempt_branch_status -/// Adds remote_commits_behind and remote_commits_ahead calculation -/// -/// TODO: Remove this override when forge-core fix is merged -/// Upstream: namastexlabs/forge-core (issues disabled - cannot report) -/// Tracking issue: https://github.com/automagik-dev/forge/issues/232 -/// -/// This override wraps the upstream implementation and adds calculation for remote_commits_behind -/// and remote_commits_ahead by comparing the local branch against its remote tracking branch -/// (e.g., forge/task-xyz vs origin/forge/task-xyz). These values are needed for the -/// UpdateNeededBadge and PushToPRButton components. -async fn forge_get_task_attempt_branch_status( - axum::Extension(task_attempt): axum::Extension, - State(deployment): State, -) -> Result>, ApiError> { - use std::process::Command; - - // Call upstream to get basic branch status - this returns all the standard fields - // We'll then augment it with remote tracking information - let upstream_result = task_attempts::get_task_attempt_branch_status( - axum::Extension(task_attempt.clone()), - State(deployment.clone()), - ) - .await; - - // If upstream fails, propagate the error - let Json(api_response) = upstream_result?; - - // Serialize the ApiResponse to JSON so we can modify it - let branch_status_value = serde_json::to_value(&api_response).map_err(|e| { - ApiError::TaskAttempt(db::models::task_attempt::TaskAttemptError::ValidationError( - format!("Failed to serialize upstream response: {}", e), - )) - })?; - - // Extract the actual data object (ApiResponse has a wrapper structure) - let mut branch_status = if let Some(data) = branch_status_value.get("data").cloned() { - data - } else if branch_status_value.is_object() { - // If it's already the data object, use it directly - branch_status_value.clone() - } else { - // Fallback: serialize the response to Value and return - let fallback_value = serde_json::to_value(&api_response).unwrap_or(json!({})); - return Ok(Json(ApiResponse::success(fallback_value))); - }; - - // Get worktree path from task attempt's container_ref - // container_ref is an Option, so we need to unwrap it or use a default - let container_ref_str = task_attempt.container_ref.as_ref().ok_or_else(|| { - ApiError::TaskAttempt(db::models::task_attempt::TaskAttemptError::ValidationError( - "Task attempt has no container_ref".to_string(), - )) - })?; - let worktree_path = std::path::PathBuf::from(container_ref_str); - - // Get current branch in the worktree - let current_branch_output = Command::new("git") - .current_dir(&worktree_path) - .args(["rev-parse", "--abbrev-ref", "HEAD"]) - .output(); - - let current_branch = match current_branch_output { - Ok(output) if output.status.success() => { - String::from_utf8_lossy(&output.stdout).trim().to_string() - } - _ => { - tracing::warn!( - "Failed to get current branch for task attempt {}, cannot calculate remote commits", - task_attempt.id - ); - // Return upstream response as-is if we can't get the current branch - // We already have branch_status as Value, so return that - return Ok(Json(ApiResponse::success(branch_status))); - } - }; - - // Get the configured upstream tracking branch (e.g., origin/forge/task-xyz, upstream/main, etc.) - let upstream_output = Command::new("git") - .current_dir(&worktree_path) - .args(["rev-parse", "--abbrev-ref", "@{u}"]) - .output(); - - let remote_tracking_branch = match upstream_output { - Ok(output) if output.status.success() => { - String::from_utf8_lossy(&output.stdout).trim().to_string() - } - _ => { - // No upstream configured - branch might not be pushed yet - tracing::debug!( - "No upstream tracking branch for {} in task attempt {}, cannot calculate remote commits", - current_branch, - task_attempt.id - ); - // Return upstream response as-is if no tracking branch exists - return Ok(Json(ApiResponse::success(branch_status))); - } - }; - - // Fetch from remote to ensure we have latest refs (don't fail if this fails) - // Extract remote name from tracking branch (e.g., "origin" from "origin/branch") - if let Some(remote_name) = remote_tracking_branch.split('/').next() { - let _ = Command::new("git") - .current_dir(&worktree_path) - .args(["fetch", remote_name, ¤t_branch]) - .output(); - } - - let remote_commits_output = Command::new("git") - .current_dir(&worktree_path) - .args([ - "rev-list", - "--left-right", - "--count", - &format!("{}...{}", remote_tracking_branch, current_branch), - ]) - .output(); - - let (remote_commits_behind, remote_commits_ahead) = match remote_commits_output { - Ok(output) if output.status.success() => { - let output_str = String::from_utf8_lossy(&output.stdout); - let parts: Vec<&str> = output_str.split_whitespace().collect(); - if parts.len() == 2 { - (parts[0].parse::().ok(), parts[1].parse::().ok()) - } else { - (None, None) - } - } - _ => { - // Remote tracking branch might not exist yet (e.g., new local branch not pushed) - tracing::debug!( - "Remote tracking branch {} not found for task attempt {}, likely not pushed yet", - remote_tracking_branch, - task_attempt.id - ); - (None, None) - } - }; - - // Add the calculated values to the branch status - if let Some(obj) = branch_status.as_object_mut() { - obj.insert( - "remote_commits_behind".to_string(), - json!(remote_commits_behind), - ); - obj.insert( - "remote_commits_ahead".to_string(), - json!(remote_commits_ahead), - ); - } - - // Return the augmented response - Ok(Json(ApiResponse::success(branch_status))) -} - -/// Build task_attempts router with forge override for create endpoint -fn build_task_attempts_router_with_forge_override( - deployment: &DeploymentImpl, -) -> Router { - use axum::middleware::from_fn_with_state; - use server::middleware::load_task_attempt_middleware; - - let task_attempt_id_router = Router::new() - .route("/", get(task_attempts::get_task_attempt)) - .route("/follow-up", post(forge_follow_up)) - .route( - "/draft", - get(task_attempts::drafts::get_draft) - .put(task_attempts::drafts::save_draft) - .delete(task_attempts::drafts::delete_draft), - ) - .route("/draft/queue", post(task_attempts::drafts::set_draft_queue)) - .route("/replace-process", post(task_attempts::replace_process)) - .route("/commit-info", get(task_attempts::get_commit_info)) - .route( - "/commit-compare", - get(task_attempts::compare_commit_to_head), - ) - .route("/start-dev-server", post(task_attempts::start_dev_server)) - .route( - "/branch-status", - get(forge_get_task_attempt_branch_status), // Forge override to calculate remote_commits_behind/ahead - ) - .route("/diff/ws", get(task_attempts::stream_task_attempt_diff_ws)) - .route("/merge", post(task_attempts::merge_task_attempt)) - .route("/push", post(task_attempts::push_task_attempt_branch)) - .route("/rebase", post(task_attempts::rebase_task_attempt)) - .route( - "/conflicts/abort", - post(task_attempts::abort_conflicts_task_attempt), - ) - .route("/pr", post(task_attempts::create_github_pr)) - .route("/pr/attach", post(task_attempts::attach_existing_pr)) - .route( - "/open-editor", - post(task_attempts::open_task_attempt_in_editor), - ) - .route( - "/delete-file", - post(task_attempts::delete_task_attempt_file), - ) - .route("/children", get(task_attempts::get_task_attempt_children)) - .route("/stop", post(task_attempts::stop_task_attempt_execution)) - .route( - "/change-target-branch", - post(task_attempts::change_target_branch), - ) - .layer(from_fn_with_state( - deployment.clone(), - load_task_attempt_middleware, - )); - - let task_attempts_router = Router::new() - .route( - "/", - get(task_attempts::get_task_attempts).post(forge_create_task_attempt), - ) // Forge override - .nest("/{id}", task_attempt_id_router); - - Router::new().nest("/task-attempts", task_attempts_router) -} - -/// Build config router with forge override for increased body limit on /profiles -fn forge_config_router() -> Router { - use axum::extract::DefaultBodyLimit; - - // Use upstream router and layer on increased body limit globally for config routes - // This affects all config routes, but /profiles is the only one with large payloads - upstream_config::router().layer(DefaultBodyLimit::max(20 * 1024 * 1024)) // 20MB limit for 37 agent profiles -} - /// Build images router with forge override for increased body limit on uploads fn forge_images_router() -> Router { use axum::extract::DefaultBodyLimit; - // Use upstream router and layer on increased body limit globally for image routes - // Upstream has 20MB limits on upload routes, we increase to 100MB for large images - images::routes().layer(DefaultBodyLimit::max(100 * 1024 * 1024)) // 100MB limit for image uploads -} - -async fn frontend_handler(uri: axum::http::Uri) -> Response { - let path = uri.path().trim_start_matches('/'); - - if path.is_empty() { - serve_index().await - } else { - serve_assets(Path(path.to_string())).await - } -} - -async fn serve_index() -> Response { - match Frontend::get("index.html") { - Some(content) => Html(content.data.to_vec()).into_response(), - None => (StatusCode::NOT_FOUND, "404 Not Found").into_response(), - } -} - -async fn serve_assets(Path(path): Path) -> Response { - serve_static_file::(&path).await -} - -/// Serve public assets (no auth required) - used for PWA manifest and other public files -async fn serve_assets_public() -> Response { - serve_static_file::("site.webmanifest").await -} - -async fn serve_static_file(path: &str) -> Response { - match T::get(path) { - Some(content) => { - let mime = mime_guess::from_path(path).first_or_octet_stream(); - - let mut response = Response::new(content.data.into()); - response.headers_mut().insert( - header::CONTENT_TYPE, - HeaderValue::from_str(mime.as_ref()).unwrap(), - ); - response - } - None => { - // Fallback to index.html for SPA routing - if let Some(index) = T::get("index.html") { - Html(index.data.to_vec()).into_response() - } else { - (StatusCode::NOT_FOUND, "404 Not Found").into_response() - } - } - } -} - -async fn health_check() -> Json { - Json(json!({ - "status": "ok", - "service": "forge-app", - "version": crate::version::get_version(), - "message": "Forge application ready - backend extensions extracted successfully" - })) -} - -/// Serve OpenAPI specification as JSON -async fn serve_openapi_spec() -> Result, (StatusCode, String)> { - const OPENAPI_YAML: &str = include_str!("../openapi.yaml"); - - serde_yaml::from_str::(OPENAPI_YAML) - .map(Json) - .map_err(|e| { - tracing::error!("Failed to parse openapi.yaml: {}", e); - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Failed to parse OpenAPI spec: {}", e), - ) - }) -} - -/// Serve Swagger UI HTML -async fn serve_swagger_ui() -> Html { - Html( - r#" - - - - - Automagik Forge API Documentation - - - -
- - - - -"# - .to_string(), - ) -} - -/// Simple route listing - practical solution instead of broken OpenAPI -async fn list_routes() -> Json { - Json(json!({ - "version": crate::version::get_version(), - "routes": { - "core": [ - "GET /health", - "GET /api/health", - "GET /api/routes (this endpoint)" - ], - "auth": [ - "POST /api/auth/github/device", - "POST /api/auth/github/device/poll", - "POST /api/auth/logout" - ], - "projects": [ - "GET /api/projects", - "POST /api/projects", - "GET /api/projects/{id}", - "PUT /api/projects/{id}", - "DELETE /api/projects/{id}" - ], - "tasks": [ - "GET /api/tasks", - "POST /api/tasks", - "POST /api/tasks/create-and-start", - "GET /api/tasks/{id}", - "PUT /api/tasks/{id}", - "DELETE /api/tasks/{id}", - "GET /api/tasks/stream/ws" - ], - "task_attempts": [ - "GET /api/task-attempts", - "POST /api/task-attempts", - "GET /api/task-attempts/{id}", - "POST /api/task-attempts/{id}/follow-up", - "POST /api/task-attempts/{id}/stop", - "POST /api/task-attempts/{id}/merge", - "POST /api/task-attempts/{id}/push", - "POST /api/task-attempts/{id}/rebase", - "POST /api/task-attempts/{id}/pr", - "POST /api/task-attempts/{id}/pr/attach", - "GET /api/task-attempts/{id}/branch-status", - "GET /api/task-attempts/{id}/diff/ws", - "GET /api/task-attempts/{id}/draft", - "PUT /api/task-attempts/{id}/draft", - "DELETE /api/task-attempts/{id}/draft" - ], - "processes": [ - "GET /api/execution-processes", - "GET /api/execution-processes/{id}", - "POST /api/execution-processes/{id}/stop" - ], - "events": [ - "GET /api/events/processes/{id}/logs", - "GET /api/events/task-attempts/{id}/diff" - ], - "images": [ - "POST /api/images", - "GET /api/images/{id}" - ], - "forge": [ - "GET /api/forge/config", - "PUT /api/forge/config", - "GET /api/forge/projects/{id}/settings", - "PUT /api/forge/projects/{id}/settings", - "GET /api/forge/omni/status", - "GET /api/forge/omni/instances", - "POST /api/forge/omni/validate", - "GET /api/forge/omni/notifications", - "GET /api/forge/releases", - "GET /api/forge/master-genie/{attempt_id}/neurons", - "GET /api/forge/neurons/{neuron_attempt_id}/subtasks" - ], - "filesystem": [ - "GET /api/filesystem/tree", - "GET /api/filesystem/file" - ], - "config": [ - "GET /api/config", - "PUT /api/config" - ], - "drafts": [ - "GET /api/drafts", - "POST /api/drafts", - "GET /api/drafts/{id}", - "PUT /api/drafts/{id}", - "DELETE /api/drafts/{id}" - ], - "containers": [ - "GET /api/containers", - "GET /api/containers/{id}" - ], - "approvals": [ - "POST /api/approvals/create", - "GET /api/approvals/{id}/status", - "POST /api/approvals/{id}/respond", - "GET /api/approvals/pending" - ] - }, - "note": "This is a simple route listing. Most endpoints require GitHub OAuth authentication via /api/auth/github/device" - })) -} - -async fn get_auth_required(State(state): State) -> Json { - Json(json!({ - "auth_required": state.auth_required - })) -} - -async fn get_forge_config( - State(services): State, -) -> Result>, StatusCode> { - services - .config - .get_global_settings() - .await - .map(|settings| Json(ApiResponse::success(settings))) - .map_err(|e| { - tracing::error!("Failed to load forge config: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - }) -} - -async fn update_forge_config( - State(services): State, - Json(settings): Json, -) -> Result>, StatusCode> { - services - .config - .set_global_settings(&settings) - .await - .map_err(|e| { - tracing::error!("Failed to persist forge config: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - services.apply_global_omni_config().await.map_err(|e| { - tracing::error!("Failed to refresh Omni config: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - Ok(Json(ApiResponse::success(settings))) -} - -async fn get_project_settings( - Path(project_id): Path, - State(services): State, -) -> Result>, StatusCode> { - services - .config - .get_forge_settings(project_id) - .await - .map(|settings| Json(ApiResponse::success(settings))) - .map_err(|e| { - tracing::error!("Failed to load project settings {}: {}", project_id, e); - StatusCode::INTERNAL_SERVER_ERROR - }) -} - -async fn update_project_settings( - Path(project_id): Path, - State(services): State, - Json(settings): Json, -) -> Result>, StatusCode> { - services - .config - .set_forge_settings(project_id, &settings) - .await - .map_err(|e| { - tracing::error!("Failed to persist project settings {}: {}", project_id, e); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - Ok(Json(ApiResponse::success(settings))) -} - -/// Get executor profiles for a specific project -async fn get_project_profiles( - Path(project_id): Path, - State(services): State, -) -> Result>, StatusCode> { - services - .profile_cache - .get_profiles_for_project(project_id) - .await - .map(|profiles| { - tracing::debug!( - "Retrieved {} executor profiles for project {}", - profiles.executors.len(), - project_id - ); - Json(ApiResponse::success(profiles)) - }) - .map_err(|e| { - tracing::error!("Failed to load profiles for project {}: {}", project_id, e); - StatusCode::NOT_FOUND - }) -} - -#[derive(Deserialize)] -struct BranchStatusQuery { - /// Optional base branch to compare against (defaults to "main") - base: Option, -} - -/// Get branch status for a project's main repository -/// This checks the git status of the project's working directory (not worktree) -/// Supports optional ?base= query parameter to specify target branch -async fn get_project_branch_status( - Path(project_id): Path, - Query(query): Query, - State(deployment): State, -) -> Result>, StatusCode> { - use db::models::project::Project; - use std::process::Command; - - // Get project to determine workspace root - let project = match Project::find_by_id(&deployment.db().pool, project_id).await { - Ok(Some(p)) => p, - Ok(None) => { - tracing::error!("Project {} not found", project_id); - return Err(StatusCode::NOT_FOUND); - } - Err(e) => { - tracing::error!("Database error finding project {}: {}", project_id, e); - return Err(StatusCode::INTERNAL_SERVER_ERROR); - } - }; - - // Get current branch - let current_branch_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["rev-parse", "--abbrev-ref", "HEAD"]) - .output(); - - let current_branch = match current_branch_output { - Ok(output) if output.status.success() => { - String::from_utf8_lossy(&output.stdout).trim().to_string() - } - _ => { - tracing::warn!( - "Failed to get current branch for project {}, defaulting to 'main'", - project_id - ); - "main".to_string() - } - }; - - // Get target branch from query parameter or default to "main" - let target_branch = query.base.as_deref().unwrap_or("main"); - - // Fetch from remote to ensure we have latest refs - let _ = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["fetch", "origin"]) - .output(); - - // Compare against remote tracking branch (origin/target_branch) - let remote_branch = format!("origin/{}", target_branch); - let commits_behind_ahead_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args([ - "rev-list", - "--left-right", - "--count", - &format!("{}...{}", remote_branch, current_branch), - ]) - .output(); - - let (commits_behind, commits_ahead) = match commits_behind_ahead_output { - Ok(output) if output.status.success() => { - let output_str = String::from_utf8_lossy(&output.stdout); - let parts: Vec<&str> = output_str.split_whitespace().collect(); - if parts.len() == 2 { - (parts[0].parse::().ok(), parts[1].parse::().ok()) - } else { - (None, None) - } - } - _ => (None, None), - }; - - // Get the configured upstream tracking branch (e.g., origin/main, upstream/main, etc.) - // This tells us if we need to push (local ahead) or pull (remote ahead) - let upstream_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["rev-parse", "--abbrev-ref", "@{u}"]) - .output(); - - let (remote_commits_behind, remote_commits_ahead) = match upstream_output { - Ok(output) if output.status.success() => { - let remote_tracking_branch = String::from_utf8_lossy(&output.stdout).trim().to_string(); - - // Compare local to its configured upstream - let remote_commits_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args([ - "rev-list", - "--left-right", - "--count", - &format!("{}...{}", remote_tracking_branch, current_branch), - ]) - .output(); - - match remote_commits_output { - Ok(output) if output.status.success() => { - let output_str = String::from_utf8_lossy(&output.stdout); - let parts: Vec<&str> = output_str.split_whitespace().collect(); - if parts.len() == 2 { - (parts[0].parse::().ok(), parts[1].parse::().ok()) - } else { - (None, None) - } - } - _ => (None, None), - } - } - _ => { - // No upstream tracking branch configured (e.g., new local branch not pushed) - tracing::debug!( - "No upstream tracking branch for {} in project {}", - current_branch, - project_id - ); - (None, None) - } - }; - - // Check for uncommitted changes - let status_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["status", "--porcelain"]) - .output(); - - let (has_uncommitted_changes, uncommitted_count, untracked_count) = match status_output { - Ok(output) if output.status.success() => { - let status_str = String::from_utf8_lossy(&output.stdout).to_string(); - let status_lines: Vec<&str> = status_str.lines().collect(); - let uncommitted = status_lines.iter().filter(|l| !l.starts_with("??")).count(); - let untracked = status_lines.iter().filter(|l| l.starts_with("??")).count(); - ( - !status_lines.is_empty(), - Some(uncommitted as i32), - Some(untracked as i32), - ) - } - _ => (false, None, None), - }; - - // Get HEAD commit OID - let head_oid_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["rev-parse", "HEAD"]) - .output(); - - let head_oid = match head_oid_output { - Ok(output) if output.status.success() => { - Some(String::from_utf8_lossy(&output.stdout).trim().to_string()) - } - _ => None, - }; - - // Build response matching BranchStatus structure - let response = json!({ - "commits_behind": commits_behind, - "commits_ahead": commits_ahead, - "has_uncommitted_changes": has_uncommitted_changes, - "head_oid": head_oid, - "uncommitted_count": uncommitted_count, - "untracked_count": untracked_count, - "target_branch_name": target_branch, - "remote_commits_behind": remote_commits_behind, - "remote_commits_ahead": remote_commits_ahead, - "merges": [], - "is_rebase_in_progress": false, - "conflict_op": null, - "conflicted_files": [] - }); - - Ok(Json(ApiResponse::success(response))) -} - -/// Pull updates for a project's main repository -/// This performs a git pull --rebase to update the working tree with remote changes -async fn post_project_pull( - Path(project_id): Path, - State(deployment): State, -) -> Result, StatusCode> { - use db::models::project::Project; - use std::process::Command; - - // Get project - let project = match Project::find_by_id(&deployment.db().pool, project_id).await { - Ok(Some(p)) => p, - Ok(None) => { - tracing::error!("Project {} not found", project_id); - return Err(StatusCode::NOT_FOUND); - } - Err(e) => { - tracing::error!("Database error finding project {}: {}", project_id, e); - return Err(StatusCode::INTERNAL_SERVER_ERROR); - } - }; - - // Get current branch name - let branch_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["rev-parse", "--abbrev-ref", "HEAD"]) - .output(); - - let current_branch = match branch_output { - Ok(output) if output.status.success() => { - String::from_utf8_lossy(&output.stdout).trim().to_string() - } - Ok(output) => { - let stderr = String::from_utf8_lossy(&output.stderr); - tracing::error!( - "Failed to get current branch for project {}: {}", - project_id, - stderr - ); - return Err(StatusCode::INTERNAL_SERVER_ERROR); - } - Err(e) => { - tracing::error!( - "Failed to execute git rev-parse for project {}: {}", - project_id, - e - ); - return Err(StatusCode::INTERNAL_SERVER_ERROR); - } - }; - - // Run git pull to actually update the working tree - tracing::info!( - "Pulling updates for project {} branch {} at {:?}", - project_id, - current_branch, - project.git_repo_path - ); - - let pull_output = Command::new("git") - .current_dir(&project.git_repo_path) - .args(["pull", "--rebase", "origin", ¤t_branch]) - .output(); - - match pull_output { - Ok(output) if output.status.success() => { - let stdout = String::from_utf8_lossy(&output.stdout); - tracing::info!( - "Successfully pulled updates for project {}: {}", - project_id, - stdout - ); - Ok(Json(json!({ - "success": true, - "message": format!("Successfully pulled updates from origin/{}", current_branch) - }))) - } - Ok(output) => { - let stderr = String::from_utf8_lossy(&output.stderr); - let stdout = String::from_utf8_lossy(&output.stdout); - - // Check if it's a merge conflict or dirty working tree - if stderr.contains("conflict") || stderr.contains("Cannot rebase") { - tracing::warn!( - "Git pull conflict for project {}: {} {}", - project_id, - stdout, - stderr - ); - Ok(Json(json!({ - "success": false, - "message": "Cannot pull: working tree has conflicts or uncommitted changes. Please resolve manually.", - "details": stderr.to_string() - }))) - } else { - tracing::error!( - "Git pull failed for project {}: {} {}", - project_id, - stdout, - stderr - ); - Err(StatusCode::INTERNAL_SERVER_ERROR) - } - } - Err(e) => { - tracing::error!( - "Failed to execute git pull for project {}: {}", - project_id, - e - ); - Err(StatusCode::INTERNAL_SERVER_ERROR) - } - } -} - -async fn get_omni_status(State(services): State) -> Result, StatusCode> { - let omni = services.omni.read().await; - let config = omni.config(); - - Ok(Json(json!({ - "enabled": config.enabled, - "version": crate::version::get_version(), - "config": if config.enabled { - serde_json::to_value(config).ok() - } else { - None - } - }))) -} - -async fn list_omni_instances( - State(services): State, -) -> Result, StatusCode> { - let omni = services.omni.read().await; - match omni.list_instances().await { - Ok(instances) => Ok(Json(json!({ "instances": instances }))), - Err(e) => { - tracing::error!("Failed to list Omni instances: {}", e); - Ok(Json(json!({ - "instances": [], - "error": "Failed to connect to Omni service" - }))) - } - } -} - -async fn list_omni_notifications( - State(services): State, -) -> Result, StatusCode> { - let rows = sqlx::query( - r#"SELECT - id, - task_id, - notification_type, - status, - message, - error_message, - sent_at, - created_at, - metadata - FROM forge_omni_notifications - ORDER BY created_at DESC - LIMIT 50"#, - ) - .fetch_all(services.pool()) - .await - .map_err(|error| { - tracing::error!("Failed to fetch Omni notifications: {}", error); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - let mut notifications = Vec::with_capacity(rows.len()); - - for row in rows { - let metadata = match row.try_get::, _>("metadata") { - Ok(Some(raw)) => serde_json::from_str::(&raw).ok(), - _ => None, - }; - - let record = json!({ - "id": row.try_get::("id").unwrap_or_default(), - "task_id": row.try_get::, _>("task_id").unwrap_or(None), - "notification_type": row - .try_get::("notification_type") - .unwrap_or_else(|_| "unknown".to_string()), - "status": row - .try_get::("status") - .unwrap_or_else(|_| "pending".to_string()), - "message": row.try_get::, _>("message").unwrap_or(None), - "error_message": row - .try_get::, _>("error_message") - .unwrap_or(None), - "sent_at": row.try_get::, _>("sent_at").unwrap_or(None), - "created_at": row - .try_get::("created_at") - .unwrap_or_else(|_| chrono::Utc::now().to_rfc3339()), - "metadata": metadata, - }); - - notifications.push(record); - } - - Ok(Json(json!({ "notifications": notifications }))) -} - -#[derive(Debug, Deserialize)] -struct ValidateOmniRequest { - host: String, - api_key: String, -} - -#[derive(Debug, Serialize)] -struct ValidateOmniResponse { - valid: bool, - instances: Vec, - error: Option, -} - -async fn validate_omni_config( - State(_services): State, - Json(req): Json, -) -> Result, StatusCode> { - // Create temporary OmniService with provided credentials - let temp_config = forge_omni::OmniConfig { - enabled: false, - host: Some(req.host), - api_key: Some(req.api_key), - instance: None, - recipient: None, - recipient_type: None, - }; - - let temp_service = forge_omni::OmniService::new(temp_config); - match temp_service.list_instances().await { - Ok(instances) => Ok(Json(ValidateOmniResponse { - valid: true, - instances, - error: None, - })), - Err(e) => Ok(Json(ValidateOmniResponse { - valid: false, - instances: vec![], - error: Some(format!("Configuration validation failed: {}", e)), - })), - } -} - -#[derive(Debug, Serialize, Deserialize)] -struct GitHubRelease { - tag_name: String, - name: String, - body: Option, - prerelease: bool, - created_at: String, - published_at: Option, - html_url: String, -} - -/// Fetch GitHub releases from the repository -async fn get_github_releases() -> Result>>, StatusCode> { - let client = reqwest::Client::new(); - - match client - .get("https://api.github.com/repos/automagik.dev/automagik-forge/releases") - .header("User-Agent", "automagik-forge") - .header("Accept", "application/vnd.github+json") - .send() - .await - { - Ok(response) => { - if response.status().is_success() { - match response.json::>().await { - Ok(releases) => Ok(Json(ApiResponse::success(releases))), - Err(e) => { - tracing::error!("Failed to parse GitHub releases: {}", e); - Err(StatusCode::INTERNAL_SERVER_ERROR) - } - } - } else { - tracing::error!("GitHub API returned error: {}", response.status()); - Err(StatusCode::BAD_GATEWAY) - } - } - Err(e) => { - tracing::error!("Failed to fetch GitHub releases: {}", e); - Err(StatusCode::BAD_GATEWAY) - } - } -} - -/// Neuron type definitions -#[derive(Debug, Serialize)] -struct Neuron { - #[serde(rename = "type")] - neuron_type: String, // "wish", "forge", or "review" - task: Task, - attempt: TaskAttempt, -} - -/// Get neurons for a Master Genie task attempt -/// Returns Wish, Forge, and Review neurons (tasks with parent_task_attempt = master_attempt_id) -async fn get_master_genie_neurons( - State(deployment): State, - Path(attempt_id): Path, -) -> Result>>, ApiError> { - let pool = &deployment.db().pool; - - // Find all tasks where parent_task_attempt = master_attempt_id AND status = 'agent' - let neuron_tasks: Vec = sqlx::query_as::<_, Task>( - r#"SELECT * FROM tasks - WHERE parent_task_attempt = ? AND status = 'agent' - ORDER BY created_at ASC"#, - ) - .bind(attempt_id) - .fetch_all(pool) - .await?; - - let mut neurons = Vec::new(); - - // For each neuron task, find its latest attempt and determine type from executor variant - for task in neuron_tasks { - // Get latest attempt for this neuron task (fetch_all returns newest first) - if let Ok(attempts) = TaskAttempt::fetch_all(pool, Some(task.id)).await - && let Some(attempt) = attempts.into_iter().next() - { - // Parse executor to get variant (e.g., "CLAUDE_CODE:WISH" → "WISH") - let neuron_type = if let Some((_base, variant)) = attempt.executor.split_once(':') { - variant.to_string() // Keep uppercase to match profile variants - } else { - "unknown".to_string() - }; - - neurons.push(Neuron { - neuron_type, - task, - attempt, - }); - } - } - - Ok(Json(ApiResponse::success(neurons))) -} - -/// Get subtasks for a neuron -/// Returns tasks where parent_task_attempt = neuron_attempt_id AND status = 'agent' -async fn get_neuron_subtasks( - State(deployment): State, - Path(neuron_attempt_id): Path, -) -> Result>>, ApiError> { - let pool = &deployment.db().pool; - - // Find all tasks where parent_task_attempt = neuron_attempt_id AND status = 'agent' - let subtasks: Vec = sqlx::query_as::<_, Task>( - r#"SELECT * FROM tasks - WHERE parent_task_attempt = ? AND status = 'agent' - ORDER BY created_at DESC"#, - ) - .bind(neuron_attempt_id) - .fetch_all(pool) - .await?; - - Ok(Json(ApiResponse::success(subtasks))) -} - -/// Forge Agent model -#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)] -struct ForgeAgent { - id: Uuid, - project_id: Uuid, - agent_type: String, // 'master', 'wish', 'forge', 'review' - task_id: Uuid, - created_at: String, - updated_at: String, -} - -#[derive(Debug, Deserialize)] -struct GetForgeAgentsParams { - project_id: Uuid, - agent_type: Option, -} - -/// Get forge agents for a project -async fn get_forge_agents( - State(deployment): State, - Query(params): Query, -) -> Result>>, ApiError> { - let pool = &deployment.db().pool; - - let agents = if let Some(agent_type) = params.agent_type { - sqlx::query_as::<_, ForgeAgent>( - "SELECT * FROM forge_agents WHERE project_id = ? AND agent_type = ?", - ) - .bind(params.project_id) - .bind(agent_type) - .fetch_all(pool) - .await? - } else { - sqlx::query_as::<_, ForgeAgent>("SELECT * FROM forge_agents WHERE project_id = ?") - .bind(params.project_id) - .fetch_all(pool) - .await? - }; - - Ok(Json(ApiResponse::success(agents))) -} - -#[derive(Debug, Deserialize)] -struct CreateForgeAgentBody { - project_id: Uuid, - agent_type: String, -} - -/// Create a forge agent (and its fixed task) -async fn create_forge_agent( - State(deployment): State, - Json(payload): Json, -) -> Result>, ApiError> { - let pool = &deployment.db().pool; - let agent_id = Uuid::new_v4(); - let task_id = Uuid::new_v4(); - - // Create the fixed task - let title = "Genie".to_string(); - - sqlx::query( - r#"INSERT INTO tasks (id, project_id, title, description, status, created_at, updated_at) - VALUES (?, ?, ?, NULL, 'agent', datetime('now'), datetime('now'))"#, - ) - .bind(task_id) - .bind(payload.project_id) - .bind(&title) - .execute(pool) - .await?; - - // Create the agent entry - sqlx::query( - r#"INSERT INTO forge_agents (id, project_id, agent_type, task_id, created_at, updated_at) - VALUES (?, ?, ?, ?, datetime('now'), datetime('now'))"#, - ) - .bind(agent_id) - .bind(payload.project_id) - .bind(&payload.agent_type) - .bind(task_id) - .execute(pool) - .await?; - - // Fetch the created agent - let agent: ForgeAgent = sqlx::query_as("SELECT * FROM forge_agents WHERE id = ?") - .bind(agent_id) - .fetch_one(pool) - .await?; - - Ok(Json(ApiResponse::success(agent))) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_forge_branch_prefix_format() { - // Test that branch names use "forge" prefix instead of "vk" - let attempt_id = Uuid::new_v4(); - let task_title = "test task"; - - let task_title_id = git_branch_id(task_title); - let short_id = short_uuid(&attempt_id); - let branch_name = format!("forge/{}-{}", short_id, task_title_id); - - assert!(branch_name.starts_with("forge/")); - assert!(branch_name.contains(&short_id)); - assert!(branch_name.contains(&task_title_id)); - } - - #[test] - fn test_forge_branch_prefix_uniqueness() { - // Test that different attempt IDs produce different branch names - let attempt_id_1 = Uuid::new_v4(); - let attempt_id_2 = Uuid::new_v4(); - let task_title = "test"; - - let task_title_id = git_branch_id(task_title); - let short_id_1 = short_uuid(&attempt_id_1); - let short_id_2 = short_uuid(&attempt_id_2); - - let branch_1 = format!("forge/{}-{}", short_id_1, task_title_id); - let branch_2 = format!("forge/{}-{}", short_id_2, task_title_id); - - assert_ne!(branch_1, branch_2); - assert!(branch_1.starts_with("forge/")); - assert!(branch_2.starts_with("forge/")); - } - - #[test] - fn test_forge_branch_format_matches_upstream() { - // Verify format is identical to upstream except for "forge" vs "vk" prefix - let attempt_id = Uuid::new_v4(); - let task_title = "my-test-task"; - - let task_title_id = git_branch_id(task_title); - let short_id = short_uuid(&attempt_id); - - let forge_branch = format!("forge/{}-{}", short_id, task_title_id); - let upstream_branch = format!("vk/{}-{}", short_id, task_title_id); - - // Only difference should be the prefix - assert_eq!( - forge_branch.replace("forge/", ""), - upstream_branch.replace("vk/", "") - ); - } + images::routes().layer(DefaultBodyLimit::max(100 * 1024 * 1024)) } diff --git a/forge-app/src/routes/agents.rs b/forge-app/src/routes/agents.rs new file mode 100644 index 000000000..9ca520c83 --- /dev/null +++ b/forge-app/src/routes/agents.rs @@ -0,0 +1,173 @@ +//! Agent routes for Forge +//! +//! Handles forge agents, neurons, and related endpoints. + +use axum::{ + Json, + extract::{Path, Query, State}, +}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use db::models::{ + task::Task, + task_attempt::TaskAttempt, +}; +use deployment::Deployment; +use server::{DeploymentImpl, error::ApiError}; +use utils::response::ApiResponse; + +/// Forge Agent model +#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)] +pub struct ForgeAgent { + pub id: Uuid, + pub project_id: Uuid, + pub agent_type: String, + pub task_id: Uuid, + pub created_at: String, + pub updated_at: String, +} + +/// Neuron type definitions +#[derive(Debug, Serialize)] +pub struct Neuron { + #[serde(rename = "type")] + pub neuron_type: String, + pub task: Task, + pub attempt: TaskAttempt, +} + +#[derive(Debug, Deserialize)] +pub struct GetForgeAgentsParams { + pub project_id: Uuid, + pub agent_type: Option, +} + +#[derive(Debug, Deserialize)] +pub struct CreateForgeAgentBody { + pub project_id: Uuid, + pub agent_type: String, +} + +/// Get forge agents for a project +pub async fn get_forge_agents( + State(deployment): State, + Query(params): Query, +) -> Result>>, ApiError> { + let pool = &deployment.db().pool; + + let agents = if let Some(agent_type) = params.agent_type { + sqlx::query_as::<_, ForgeAgent>( + "SELECT * FROM forge_agents WHERE project_id = ? AND agent_type = ?", + ) + .bind(params.project_id) + .bind(agent_type) + .fetch_all(pool) + .await? + } else { + sqlx::query_as::<_, ForgeAgent>("SELECT * FROM forge_agents WHERE project_id = ?") + .bind(params.project_id) + .fetch_all(pool) + .await? + }; + + Ok(Json(ApiResponse::success(agents))) +} + +/// Create a forge agent (and its fixed task) +pub async fn create_forge_agent( + State(deployment): State, + Json(payload): Json, +) -> Result>, ApiError> { + let pool = &deployment.db().pool; + let agent_id = Uuid::new_v4(); + let task_id = Uuid::new_v4(); + + let title = "Genie".to_string(); + + sqlx::query( + r#"INSERT INTO tasks (id, project_id, title, description, status, created_at, updated_at) + VALUES (?, ?, ?, NULL, 'agent', datetime('now'), datetime('now'))"#, + ) + .bind(task_id) + .bind(payload.project_id) + .bind(&title) + .execute(pool) + .await?; + + sqlx::query( + r#"INSERT INTO forge_agents (id, project_id, agent_type, task_id, created_at, updated_at) + VALUES (?, ?, ?, ?, datetime('now'), datetime('now'))"#, + ) + .bind(agent_id) + .bind(payload.project_id) + .bind(&payload.agent_type) + .bind(task_id) + .execute(pool) + .await?; + + let agent: ForgeAgent = sqlx::query_as("SELECT * FROM forge_agents WHERE id = ?") + .bind(agent_id) + .fetch_one(pool) + .await?; + + Ok(Json(ApiResponse::success(agent))) +} + +/// Get neurons for a Master Genie task attempt +pub async fn get_master_genie_neurons( + State(deployment): State, + Path(attempt_id): Path, +) -> Result>>, ApiError> { + let pool = &deployment.db().pool; + + let neuron_tasks: Vec = sqlx::query_as::<_, Task>( + r#"SELECT * FROM tasks + WHERE parent_task_attempt = ? AND status = 'agent' + ORDER BY created_at ASC"#, + ) + .bind(attempt_id) + .fetch_all(pool) + .await?; + + let mut neurons = Vec::new(); + + for task in neuron_tasks { + if let Ok(attempts) = TaskAttempt::fetch_all(pool, Some(task.id)).await { + if let Some(attempt) = attempts.into_iter().next() { + let neuron_type = if let Some((_base, variant)) = attempt.executor.split_once(':') { + variant.to_string() + } else { + "unknown".to_string() + }; + + neurons.push(Neuron { + neuron_type, + task, + attempt, + }); + } + } + } + + Ok(Json(ApiResponse::success(neurons))) +} + +/// Get subtasks for a neuron +pub async fn get_neuron_subtasks( + State(deployment): State, + Path(neuron_attempt_id): Path, +) -> Result>>, ApiError> { + let pool = &deployment.db().pool; + + let subtasks: Vec = sqlx::query_as::<_, Task>( + r#"SELECT * FROM tasks + WHERE parent_task_attempt = ? AND status = 'agent' + ORDER BY created_at DESC"#, + ) + .bind(neuron_attempt_id) + .fetch_all(pool) + .await?; + + Ok(Json(ApiResponse::success(subtasks))) +} diff --git a/forge-app/src/routes/attempts.rs b/forge-app/src/routes/attempts.rs new file mode 100644 index 000000000..e4140f280 --- /dev/null +++ b/forge-app/src/routes/attempts.rs @@ -0,0 +1,306 @@ +//! Task attempt routes for Forge +//! +//! Handles task attempt creation, follow-up, and related operations with forge-specific extensions. + +use axum::{ + Json, Router, + extract::State, + routing::{get, post}, +}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use super::state::ForgeAppState; +use crate::services::ForgeServices; +use db::models::{ + task::Task, + task_attempt::{CreateTaskAttempt, TaskAttempt}, +}; +use deployment::Deployment; +use executors::profile::ExecutorProfileId; +use server::{DeploymentImpl, error::ApiError, routes::task_attempts}; +use services::services::container::ContainerService; +use sqlx::Error as SqlxError; +use utils::response::ApiResponse; +use utils::text::{git_branch_id, short_uuid}; + +/// Forge-specific CreateTaskAttemptBody that includes use_worktree field +#[derive(Debug, Serialize, Deserialize)] +pub struct ForgeCreateTaskAttemptBody { + pub task_id: Uuid, + pub executor_profile_id: ExecutorProfileId, + pub base_branch: String, + #[serde(default = "default_use_worktree")] + pub use_worktree: bool, +} + +fn default_use_worktree() -> bool { + true +} + +impl ForgeCreateTaskAttemptBody { + pub fn get_executor_profile_id(&self) -> ExecutorProfileId { + self.executor_profile_id.clone() + } +} + +/// Build task_attempts router with forge override for create endpoint +pub fn build_task_attempts_router_with_forge_override( + deployment: &DeploymentImpl, +) -> Router { + use axum::middleware::from_fn_with_state; + use server::middleware::load_task_attempt_middleware; + + let task_attempt_id_router = Router::new() + .route("/", get(task_attempts::get_task_attempt)) + .route("/follow-up", post(forge_follow_up)) + .route( + "/draft", + get(task_attempts::drafts::get_draft) + .put(task_attempts::drafts::save_draft) + .delete(task_attempts::drafts::delete_draft), + ) + .route("/draft/queue", post(task_attempts::drafts::set_draft_queue)) + .route("/replace-process", post(task_attempts::replace_process)) + .route("/commit-info", get(task_attempts::get_commit_info)) + .route( + "/commit-compare", + get(task_attempts::compare_commit_to_head), + ) + .route("/start-dev-server", post(task_attempts::start_dev_server)) + .route( + "/branch-status", + get(task_attempts::get_task_attempt_branch_status), + ) + .route("/diff/ws", get(task_attempts::stream_task_attempt_diff_ws)) + .route("/merge", post(task_attempts::merge_task_attempt)) + .route("/push", post(task_attempts::push_task_attempt_branch)) + .route("/rebase", post(task_attempts::rebase_task_attempt)) + .route( + "/conflicts/abort", + post(task_attempts::abort_conflicts_task_attempt), + ) + .route("/pr", post(task_attempts::create_github_pr)) + .route("/pr/attach", post(task_attempts::attach_existing_pr)) + .route( + "/open-editor", + post(task_attempts::open_task_attempt_in_editor), + ) + .route( + "/delete-file", + post(task_attempts::delete_task_attempt_file), + ) + .route("/children", get(task_attempts::get_task_attempt_children)) + .route("/stop", post(task_attempts::stop_task_attempt_execution)) + .route( + "/change-target-branch", + post(task_attempts::change_target_branch), + ) + .layer(from_fn_with_state( + deployment.clone(), + load_task_attempt_middleware, + )); + + let task_attempts_router = Router::new() + .route( + "/", + get(task_attempts::get_task_attempts).post(forge_create_task_attempt), + ) + .nest("/{id}", task_attempt_id_router); + + Router::new().nest("/task-attempts", task_attempts_router) +} + +/// Forge override: create task attempt with forge/ branch prefix +pub async fn forge_create_task_attempt( + State(deployment): State, + State(forge_services): State, + Json(payload): Json, +) -> Result>, ApiError> { + let executor_profile_id = payload.get_executor_profile_id(); + let task = Task::find_by_id(&deployment.db().pool, payload.task_id) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + let attempt_id = Uuid::new_v4(); + + let git_branch_name = if payload.use_worktree { + let task_title_id = git_branch_id(&task.title); + let short_id = short_uuid(&attempt_id); + format!("forge/{}-{}", short_id, task_title_id) + } else { + payload.base_branch.clone() + }; + + let mut task_attempt = TaskAttempt::create( + &deployment.db().pool, + &CreateTaskAttempt { + executor: executor_profile_id.executor, + base_branch: payload.base_branch.clone(), + branch: git_branch_name.clone(), + }, + attempt_id, + payload.task_id, + ) + .await?; + + sqlx::query( + "INSERT INTO forge_task_attempt_config (task_attempt_id, use_worktree) VALUES (?, ?)" + ) + .bind(attempt_id) + .bind(payload.use_worktree) + .execute(&deployment.db().pool) + .await?; + + if let Some(variant) = &executor_profile_id.variant { + let executor_with_variant = format!("{}:{}", executor_profile_id.executor, variant); + sqlx::query( + "UPDATE task_attempts SET executor = ?, updated_at = datetime('now') WHERE id = ?", + ) + .bind(&executor_with_variant) + .bind(attempt_id) + .execute(&deployment.db().pool) + .await?; + task_attempt.executor = executor_with_variant; + } + + let project = task + .parent_project(&deployment.db().pool) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + if let Ok(workspace_profiles) = forge_services.load_profiles_for_workspace(&project.git_repo_path).await { + let variant_count = workspace_profiles.executors.values() + .map(|config| config.configurations.len()) + .sum::(); + + let variant_list: Vec = workspace_profiles.executors.iter() + .flat_map(|(executor, config)| { + config.configurations.iter().map(move |(variant, coding_agent)| { + let prompt_preview = match coding_agent { + executors::executors::CodingAgent::ClaudeCode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Codex(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Amp(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Gemini(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Opencode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::CursorAgent(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::QwenCode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Copilot(cfg) => cfg.append_prompt.get(), + }.map(|p| { + let trimmed = p.trim(); + if trimmed.len() > 60 { + format!("{}...", &trimmed[..60]) + } else { + trimmed.to_string() + } + }).unwrap_or_else(|| "".to_string()); + + format!("{}:{} ({})", executor, variant, prompt_preview) + }) + }) + .collect(); + + tracing::info!( + "Injected {} .genie profile variant(s) for workspace: {} | Profiles: [{}]", + variant_count, + project.git_repo_path.display(), + variant_list.join(", ") + ); + + executors::profile::ExecutorConfigs::set_cached(workspace_profiles); + } else { + tracing::warn!( + "Failed to load .genie profiles for workspace: {}, using defaults", + project.git_repo_path.display() + ); + } + + let _execution_process = deployment + .container() + .start_attempt(&task_attempt, executor_profile_id.clone()) + .await?; + + deployment + .track_if_analytics_allowed( + "task_attempt_started", + serde_json::json!({ + "task_id": task.id.to_string(), + "executor": &executor_profile_id.executor, + "attempt_id": task_attempt.id.to_string(), + }), + ) + .await; + + Ok(Json(ApiResponse::success(task_attempt))) +} + +/// Forge override: inject workspace profiles before follow-up +pub async fn forge_follow_up( + axum::Extension(task_attempt): axum::Extension, + State(deployment): State, + State(forge_services): State, + Json(payload): Json, +) -> Result>, ApiError> { + let task = task_attempt + .parent_task(&deployment.db().pool) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + let project = task + .parent_project(&deployment.db().pool) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + if let Ok(workspace_profiles) = forge_services.load_profiles_for_workspace(&project.git_repo_path).await { + let variant_count = workspace_profiles.executors.values() + .map(|config| config.configurations.len()) + .sum::(); + + let variant_list: Vec = workspace_profiles.executors.iter() + .flat_map(|(executor, config)| { + config.configurations.iter().map(move |(variant, coding_agent)| { + let prompt_preview = match coding_agent { + executors::executors::CodingAgent::ClaudeCode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Codex(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Amp(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Gemini(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Opencode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::CursorAgent(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::QwenCode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Copilot(cfg) => cfg.append_prompt.get(), + }.map(|p| { + let trimmed = p.trim(); + if trimmed.len() > 60 { + format!("{}...", &trimmed[..60]) + } else { + trimmed.to_string() + } + }).unwrap_or_else(|| "".to_string()); + + format!("{}:{} ({})", executor, variant, prompt_preview) + }) + }) + .collect(); + + tracing::info!( + "Injected {} .genie profile variant(s) for workspace: {} (follow-up) | Profiles: [{}]", + variant_count, + project.git_repo_path.display(), + variant_list.join(", ") + ); + + executors::profile::ExecutorConfigs::set_cached(workspace_profiles); + } else { + tracing::warn!( + "Failed to load .genie profiles for workspace: {} (follow-up), using defaults", + project.git_repo_path.display() + ); + } + + let typed_payload: task_attempts::CreateFollowUpAttempt = serde_json::from_value(payload) + .map_err(|e| ApiError::TaskAttempt(db::models::task_attempt::TaskAttemptError::ValidationError( + format!("Invalid follow-up payload: {}", e) + )))?; + + task_attempts::follow_up(axum::Extension(task_attempt), State(deployment), Json(typed_payload)).await +} diff --git a/forge-app/src/routes/config.rs b/forge-app/src/routes/config.rs new file mode 100644 index 000000000..6fbf30fe6 --- /dev/null +++ b/forge-app/src/routes/config.rs @@ -0,0 +1,67 @@ +//! Configuration routes for Forge +//! +//! Handles global forge configuration and auth status endpoints. + +use axum::{ + Json, Router, + extract::State, + http::StatusCode, +}; +use serde_json::{Value, json}; + +use super::state::ForgeAppState; +use crate::services::ForgeServices; +use forge_config::ForgeProjectSettings; +use server::{DeploymentImpl, routes::config as upstream_config}; +use utils::response::ApiResponse; + +/// Build config router with forge override for increased body limit on /profiles +pub fn forge_config_router() -> Router { + use axum::extract::DefaultBodyLimit; + + upstream_config::router().layer(DefaultBodyLimit::max(20 * 1024 * 1024)) +} + +/// Check if auth is required +pub async fn get_auth_required(State(state): State) -> Json { + Json(json!({ + "auth_required": state.auth_required + })) +} + +/// Get global forge configuration +pub async fn get_forge_config( + State(services): State, +) -> Result>, StatusCode> { + services + .config + .get_global_settings() + .await + .map(|settings| Json(ApiResponse::success(settings))) + .map_err(|e| { + tracing::error!("Failed to load forge config: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + }) +} + +/// Update global forge configuration +pub async fn update_forge_config( + State(services): State, + Json(settings): Json, +) -> Result>, StatusCode> { + services + .config + .set_global_settings(&settings) + .await + .map_err(|e| { + tracing::error!("Failed to persist forge config: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + services.apply_global_omni_config().await.map_err(|e| { + tracing::error!("Failed to refresh Omni config: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + Ok(Json(ApiResponse::success(settings))) +} diff --git a/forge-app/src/routes/frontend.rs b/forge-app/src/routes/frontend.rs new file mode 100644 index 000000000..b35efd1b4 --- /dev/null +++ b/forge-app/src/routes/frontend.rs @@ -0,0 +1,275 @@ +//! Frontend routes for Forge +//! +//! Handles static file serving, SPA routing, and documentation endpoints. + +use axum::{ + Json, + extract::Path, + http::{HeaderValue, StatusCode, header}, + response::{Html, IntoResponse, Response}, +}; +use rust_embed::{Embed, RustEmbed}; +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; + +#[derive(RustEmbed)] +#[folder = "../frontend/dist"] +pub struct Frontend; + +// The RustEmbed derive macro implements the Embed trait + +/// Health check endpoint +pub async fn health_check() -> Json { + Json(json!({ + "status": "ok", + "service": "forge-app", + "version": env!("CARGO_PKG_VERSION"), + "message": "Forge application ready - backend extensions extracted successfully" + })) +} + +/// Serve OpenAPI specification as JSON +pub async fn serve_openapi_spec() -> Result, (StatusCode, String)> { + const OPENAPI_YAML: &str = include_str!("../../openapi.yaml"); + + serde_yaml::from_str::(OPENAPI_YAML) + .map(Json) + .map_err(|e| { + tracing::error!("Failed to parse openapi.yaml: {}", e); + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Failed to parse OpenAPI spec: {}", e), + ) + }) +} + +/// Serve Swagger UI HTML +pub async fn serve_swagger_ui() -> Html { + Html( + r#" + + + + + Automagik Forge API Documentation + + + +
+ + + + +"# + .to_string(), + ) +} + +/// Simple route listing +pub async fn list_routes() -> Json { + Json(json!({ + "version": env!("CARGO_PKG_VERSION"), + "routes": { + "core": [ + "GET /health", + "GET /api/health", + "GET /api/routes (this endpoint)" + ], + "auth": [ + "POST /api/auth/github/device", + "POST /api/auth/github/device/poll", + "POST /api/auth/logout" + ], + "projects": [ + "GET /api/projects", + "POST /api/projects", + "GET /api/projects/{id}", + "PUT /api/projects/{id}", + "DELETE /api/projects/{id}" + ], + "tasks": [ + "GET /api/tasks", + "POST /api/tasks", + "POST /api/tasks/create-and-start", + "GET /api/tasks/{id}", + "PUT /api/tasks/{id}", + "DELETE /api/tasks/{id}", + "GET /api/tasks/stream/ws" + ], + "task_attempts": [ + "GET /api/task-attempts", + "POST /api/task-attempts", + "GET /api/task-attempts/{id}", + "POST /api/task-attempts/{id}/follow-up", + "POST /api/task-attempts/{id}/stop", + "POST /api/task-attempts/{id}/merge", + "POST /api/task-attempts/{id}/push", + "POST /api/task-attempts/{id}/rebase", + "POST /api/task-attempts/{id}/pr", + "POST /api/task-attempts/{id}/pr/attach", + "GET /api/task-attempts/{id}/branch-status", + "GET /api/task-attempts/{id}/diff/ws", + "GET /api/task-attempts/{id}/draft", + "PUT /api/task-attempts/{id}/draft", + "DELETE /api/task-attempts/{id}/draft" + ], + "processes": [ + "GET /api/execution-processes", + "GET /api/execution-processes/{id}", + "POST /api/execution-processes/{id}/stop" + ], + "events": [ + "GET /api/events/processes/{id}/logs", + "GET /api/events/task-attempts/{id}/diff" + ], + "images": [ + "POST /api/images", + "GET /api/images/{id}" + ], + "forge": [ + "GET /api/forge/config", + "PUT /api/forge/config", + "GET /api/forge/projects/{id}/settings", + "PUT /api/forge/projects/{id}/settings", + "GET /api/forge/omni/status", + "GET /api/forge/omni/instances", + "POST /api/forge/omni/validate", + "GET /api/forge/omni/notifications", + "GET /api/forge/releases", + "GET /api/forge/master-genie/{attempt_id}/neurons", + "GET /api/forge/neurons/{neuron_attempt_id}/subtasks" + ], + "filesystem": [ + "GET /api/filesystem/tree", + "GET /api/filesystem/file" + ], + "config": [ + "GET /api/config", + "PUT /api/config" + ], + "drafts": [ + "GET /api/drafts", + "POST /api/drafts", + "GET /api/drafts/{id}", + "PUT /api/drafts/{id}", + "DELETE /api/drafts/{id}" + ], + "containers": [ + "GET /api/containers", + "GET /api/containers/{id}" + ], + "approvals": [ + "POST /api/approvals/create", + "GET /api/approvals/{id}/status", + "POST /api/approvals/{id}/respond", + "GET /api/approvals/pending" + ] + }, + "note": "This is a simple route listing. Most endpoints require GitHub OAuth authentication via /api/auth/github/device" + })) +} + +/// GitHub release model +#[derive(Debug, Serialize, Deserialize)] +pub struct GitHubRelease { + pub tag_name: String, + pub name: String, + pub body: Option, + pub prerelease: bool, + pub created_at: String, + pub published_at: Option, + pub html_url: String, +} + +/// Fetch GitHub releases from the repository +pub async fn get_github_releases() -> Result>>, StatusCode> { + let client = reqwest::Client::new(); + + match client + .get("https://api.github.com/repos/namastexlabs/automagik-forge/releases") + .header("User-Agent", "automagik-forge") + .header("Accept", "application/vnd.github+json") + .send() + .await + { + Ok(response) => { + if response.status().is_success() { + match response.json::>().await { + Ok(releases) => Ok(Json(utils::response::ApiResponse::success(releases))), + Err(e) => { + tracing::error!("Failed to parse GitHub releases: {}", e); + Err(StatusCode::INTERNAL_SERVER_ERROR) + } + } + } else { + tracing::error!("GitHub API returned error: {}", response.status()); + Err(StatusCode::BAD_GATEWAY) + } + } + Err(e) => { + tracing::error!("Failed to fetch GitHub releases: {}", e); + Err(StatusCode::BAD_GATEWAY) + } + } +} + +/// Frontend handler for SPA routing +pub async fn frontend_handler(uri: axum::http::Uri) -> Response { + let path = uri.path().trim_start_matches('/'); + + if path.is_empty() { + serve_index().await + } else { + serve_assets(Path(path.to_string())).await + } +} + +pub async fn serve_index() -> Response { + match Frontend::get("index.html") { + Some(content) => Html(content.data.to_vec()).into_response(), + None => (StatusCode::NOT_FOUND, "404 Not Found").into_response(), + } +} + +pub async fn serve_assets(Path(path): Path) -> Response { + serve_static_file::(&path).await +} + +pub async fn serve_static_file(path: &str) -> Response { + match T::get(path) { + Some(content) => { + let mime = mime_guess::from_path(path).first_or_octet_stream(); + + let mut response = Response::new(content.data.into()); + response.headers_mut().insert( + header::CONTENT_TYPE, + HeaderValue::from_str(mime.as_ref()).unwrap(), + ); + response + } + None => { + if let Some(index) = T::get("index.html") { + Html(index.data.to_vec()).into_response() + } else { + (StatusCode::NOT_FOUND, "404 Not Found").into_response() + } + } + } +} diff --git a/forge-app/src/routes/mod.rs b/forge-app/src/routes/mod.rs new file mode 100644 index 000000000..0926b47b7 --- /dev/null +++ b/forge-app/src/routes/mod.rs @@ -0,0 +1,16 @@ +//! Route modules for Forge +//! +//! This module contains domain-specific route handlers organized by functionality. +//! The main router.rs imports and composes these modules into the final API router. + +pub mod agents; +pub mod attempts; +pub mod config; +pub mod frontend; +pub mod omni; +pub mod projects; +pub mod state; +pub mod tasks; + +// Re-export commonly used types +pub use state::ForgeAppState; diff --git a/forge-app/src/routes/omni.rs b/forge-app/src/routes/omni.rs new file mode 100644 index 000000000..ea68c51d8 --- /dev/null +++ b/forge-app/src/routes/omni.rs @@ -0,0 +1,149 @@ +//! Omni routes for Forge +//! +//! Handles Omni service status, instances, notifications, and validation endpoints. + +use axum::{ + Json, + extract::State, + http::StatusCode, +}; +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; +use sqlx::Row; + +use crate::services::ForgeServices; + +#[derive(Debug, Deserialize)] +pub struct ValidateOmniRequest { + host: String, + api_key: String, +} + +#[derive(Debug, Serialize)] +pub struct ValidateOmniResponse { + valid: bool, + instances: Vec, + error: Option, +} + +/// Get Omni service status +pub async fn get_omni_status(State(services): State) -> Result, StatusCode> { + let omni = services.omni.read().await; + let config = omni.config(); + + Ok(Json(json!({ + "enabled": config.enabled, + "version": env!("CARGO_PKG_VERSION"), + "config": if config.enabled { + serde_json::to_value(config).ok() + } else { + None + } + }))) +} + +/// List Omni instances +pub async fn list_omni_instances( + State(services): State, +) -> Result, StatusCode> { + let omni = services.omni.read().await; + match omni.list_instances().await { + Ok(instances) => Ok(Json(json!({ "instances": instances }))), + Err(e) => { + tracing::error!("Failed to list Omni instances: {}", e); + Ok(Json(json!({ + "instances": [], + "error": "Failed to connect to Omni service" + }))) + } + } +} + +/// List Omni notifications +pub async fn list_omni_notifications( + State(services): State, +) -> Result, StatusCode> { + let rows = sqlx::query( + r#"SELECT + id, + task_id, + notification_type, + status, + message, + error_message, + sent_at, + created_at, + metadata + FROM forge_omni_notifications + ORDER BY created_at DESC + LIMIT 50"#, + ) + .fetch_all(services.pool()) + .await + .map_err(|error| { + tracing::error!("Failed to fetch Omni notifications: {}", error); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + let mut notifications = Vec::with_capacity(rows.len()); + + for row in rows { + let metadata = match row.try_get::, _>("metadata") { + Ok(Some(raw)) => serde_json::from_str::(&raw).ok(), + _ => None, + }; + + let record = json!({ + "id": row.try_get::("id").unwrap_or_default(), + "task_id": row.try_get::, _>("task_id").unwrap_or(None), + "notification_type": row + .try_get::("notification_type") + .unwrap_or_else(|_| "unknown".to_string()), + "status": row + .try_get::("status") + .unwrap_or_else(|_| "pending".to_string()), + "message": row.try_get::, _>("message").unwrap_or(None), + "error_message": row + .try_get::, _>("error_message") + .unwrap_or(None), + "sent_at": row.try_get::, _>("sent_at").unwrap_or(None), + "created_at": row + .try_get::("created_at") + .unwrap_or_else(|_| chrono::Utc::now().to_rfc3339()), + "metadata": metadata, + }); + + notifications.push(record); + } + + Ok(Json(json!({ "notifications": notifications }))) +} + +/// Validate Omni configuration +pub async fn validate_omni_config( + State(_services): State, + Json(req): Json, +) -> Result, StatusCode> { + let temp_config = forge_omni::OmniConfig { + enabled: false, + host: Some(req.host), + api_key: Some(req.api_key), + instance: None, + recipient: None, + recipient_type: None, + }; + + let temp_service = forge_omni::OmniService::new(temp_config); + match temp_service.list_instances().await { + Ok(instances) => Ok(Json(ValidateOmniResponse { + valid: true, + instances, + error: None, + })), + Err(e) => Ok(Json(ValidateOmniResponse { + valid: false, + instances: vec![], + error: Some(format!("Configuration validation failed: {}", e)), + })), + } +} diff --git a/forge-app/src/routes/projects.rs b/forge-app/src/routes/projects.rs new file mode 100644 index 000000000..a1a1f29a1 --- /dev/null +++ b/forge-app/src/routes/projects.rs @@ -0,0 +1,71 @@ +//! Project routes for Forge +//! +//! Handles project-specific settings and profiles endpoints. + +use axum::{ + Json, + extract::{Path, State}, + http::StatusCode, +}; +use uuid::Uuid; + +use crate::services::ForgeServices; +use forge_config::ForgeProjectSettings; +use utils::response::ApiResponse; + +/// Get project-specific settings +pub async fn get_project_settings( + Path(project_id): Path, + State(services): State, +) -> Result>, StatusCode> { + services + .config + .get_forge_settings(project_id) + .await + .map(|settings| Json(ApiResponse::success(settings))) + .map_err(|e| { + tracing::error!("Failed to load project settings {}: {}", project_id, e); + StatusCode::INTERNAL_SERVER_ERROR + }) +} + +/// Update project-specific settings +pub async fn update_project_settings( + Path(project_id): Path, + State(services): State, + Json(settings): Json, +) -> Result>, StatusCode> { + services + .config + .set_forge_settings(project_id, &settings) + .await + .map_err(|e| { + tracing::error!("Failed to persist project settings {}: {}", project_id, e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + Ok(Json(ApiResponse::success(settings))) +} + +/// Get executor profiles for a specific project +pub async fn get_project_profiles( + Path(project_id): Path, + State(services): State, +) -> Result>, StatusCode> { + services + .profile_cache + .get_profiles_for_project(project_id) + .await + .map(|profiles| { + tracing::debug!( + "Retrieved {} executor profiles for project {}", + profiles.executors.len(), + project_id + ); + Json(ApiResponse::success(profiles)) + }) + .map_err(|e| { + tracing::error!("Failed to load profiles for project {}: {}", project_id, e); + StatusCode::NOT_FOUND + }) +} diff --git a/forge-app/src/routes/state.rs b/forge-app/src/routes/state.rs new file mode 100644 index 000000000..1ed1e64a4 --- /dev/null +++ b/forge-app/src/routes/state.rs @@ -0,0 +1,38 @@ +//! Shared state types for Forge routes +//! +//! Contains ForgeAppState and related implementations used across all route modules. + +use axum::extract::FromRef; + +use crate::services::ForgeServices; +use server::DeploymentImpl; + +/// Main application state for Forge routes +#[derive(Clone)] +pub struct ForgeAppState { + pub(crate) services: ForgeServices, + pub(crate) deployment: DeploymentImpl, + pub(crate) auth_required: bool, +} + +impl ForgeAppState { + pub fn new(services: ForgeServices, deployment: DeploymentImpl, auth_required: bool) -> Self { + Self { + services, + deployment, + auth_required, + } + } +} + +impl FromRef for ForgeServices { + fn from_ref(state: &ForgeAppState) -> ForgeServices { + state.services.clone() + } +} + +impl FromRef for DeploymentImpl { + fn from_ref(state: &ForgeAppState) -> DeploymentImpl { + state.deployment.clone() + } +} diff --git a/forge-app/src/routes/tasks.rs b/forge-app/src/routes/tasks.rs new file mode 100644 index 000000000..b10870cad --- /dev/null +++ b/forge-app/src/routes/tasks.rs @@ -0,0 +1,588 @@ +//! Task routes for Forge +//! +//! Handles task creation, listing, and WebSocket streaming with forge-specific extensions. + +use axum::{ + Json, Router, + extract::{ + Query, State, + ws::{WebSocket, WebSocketUpgrade}, + }, + response::IntoResponse, + routing::{get, post}, +}; +use futures_util::{SinkExt, StreamExt, TryStreamExt}; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use uuid::Uuid; + +use super::state::ForgeAppState; +use crate::services::ForgeServices; +use db::models::{ + image::TaskImage, + task::{Task, TaskWithAttemptStatus}, + task_attempt::{CreateTaskAttempt, TaskAttempt}, +}; +use deployment::Deployment; +use server::{DeploymentImpl, error::ApiError, routes::tasks as upstream_tasks}; +use services::services::container::ContainerService; +use sqlx::{Error as SqlxError, Row}; +use utils::response::ApiResponse; +use utils::text::{git_branch_id, short_uuid}; +use utils::log_msg::LogMsg; + +/// Forge-specific CreateTask that includes is_agent field and github_issue_id +#[derive(Debug, Serialize, Deserialize)] +pub struct ForgeCreateTask { + pub project_id: Uuid, + pub title: String, + pub description: Option, + pub parent_task_attempt: Option, + pub image_ids: Option>, + pub is_agent: Option, // Forge extension: mark as agent-managed task + pub github_issue_id: Option, // GitHub issue ID for "No Wish Without Issue" rule +} + +#[derive(Deserialize)] +pub struct GetTasksParams { + project_id: Uuid, +} + +#[derive(Deserialize)] +pub struct TaskQuery { + project_id: Uuid, +} + +/// Build tasks router with forge override for create-and-start endpoint +pub fn build_tasks_router_with_forge_override(deployment: &DeploymentImpl) -> Router { + use axum::middleware::from_fn_with_state; + use server::middleware::load_task_middleware; + + let task_id_router = Router::new() + .route( + "/", + get(upstream_tasks::get_task) + .put(upstream_tasks::update_task) + .delete(upstream_tasks::delete_task), + ) + .layer(from_fn_with_state(deployment.clone(), load_task_middleware)); + + let inner = Router::new() + .route("/", get(forge_get_tasks).post(forge_create_task)) + .route("/stream/ws", get(forge_stream_tasks_ws)) + .route("/create-and-start", post(forge_create_task_and_start)) + .nest("/{task_id}", task_id_router); + + Router::new().nest("/tasks", inner) +} + +/// Forge override: create task (standard behavior, no special status handling) +/// The is_agent field is kept for future use but not currently used in task creation +/// Supports github_issue_id for "No Wish Without Issue" rule enforcement +pub async fn forge_create_task( + State(deployment): State, + Json(payload): Json, +) -> Result>, ApiError> { + let task_id = Uuid::new_v4(); + let mut task = Task::create( + &deployment.db().pool, + &db::models::task::CreateTask { + project_id: payload.project_id, + title: payload.title, + description: payload.description, + parent_task_attempt: payload.parent_task_attempt, + image_ids: payload.image_ids.clone(), + }, + task_id, + ) + .await?; + + // Set github_issue_id if provided (Forge extension for issue tracking) + if let Some(github_issue_id) = payload.github_issue_id { + sqlx::query( + "UPDATE tasks SET github_issue_id = ?, updated_at = datetime('now') WHERE id = ?", + ) + .bind(github_issue_id) + .bind(task_id) + .execute(&deployment.db().pool) + .await?; + + // Re-fetch task to get updated github_issue_id (avoids returning stale data) + task = Task::find_by_id(&deployment.db().pool, task_id) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + } + + if let Some(image_ids) = &payload.image_ids { + TaskImage::associate_many(&deployment.db().pool, task.id, image_ids).await?; + } + + deployment + .track_if_analytics_allowed( + "task_created", + serde_json::json!({ + "task_id": task.id.to_string(), + "project_id": task.project_id, + "has_description": task.description.is_some(), + "has_images": payload.image_ids.is_some(), + "github_issue_id": payload.github_issue_id, + }), + ) + .await; + + Ok(Json(ApiResponse::success(task))) +} + +/// Forge override for list tasks: Exclude agent tasks (those in forge_agents table) +pub async fn forge_get_tasks( + State(deployment): State, + Query(params): Query, +) -> Result>>, ApiError> { + let pool = &deployment.db().pool; + + let query_str = r#"SELECT + t.id AS "id", + t.project_id AS "project_id", + t.title, + t.description, + t.status AS "status", + t.parent_task_attempt AS "parent_task_attempt", + t.created_at AS "created_at", + t.updated_at AS "updated_at", + + CASE WHEN EXISTS ( + SELECT 1 + FROM task_attempts ta + JOIN execution_processes ep + ON ep.task_attempt_id = ta.id + WHERE ta.task_id = t.id + AND ep.status = 'running' + AND ep.run_reason IN ('setupscript','cleanupscript','codingagent') + LIMIT 1 + ) THEN 1 ELSE 0 END AS has_in_progress_attempt, + + CASE WHEN ( + SELECT ep.status + FROM task_attempts ta + JOIN execution_processes ep + ON ep.task_attempt_id = ta.id + WHERE ta.task_id = t.id + AND ep.run_reason IN ('setupscript','cleanupscript','codingagent') + ORDER BY ep.created_at DESC + LIMIT 1 + ) IN ('failed','killed') THEN 1 ELSE 0 END + AS last_attempt_failed, + + ( SELECT ta.executor + FROM task_attempts ta + WHERE ta.task_id = t.id + ORDER BY ta.created_at DESC + LIMIT 1 + ) AS executor + +FROM tasks t +WHERE t.project_id = ? + AND t.id NOT IN (SELECT task_id FROM forge_agents) +ORDER BY t.created_at DESC"#; + + let rows = sqlx::query(query_str) + .bind(params.project_id) + .fetch_all(pool) + .await?; + + let mut items: Vec = Vec::with_capacity(rows.len()); + for row in rows { + let task_id: Uuid = row.try_get("id").map_err(ApiError::Database)?; + let task = db::models::task::Task::find_by_id(pool, task_id) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + let has_in_progress_attempt = row + .try_get::("has_in_progress_attempt") + .map(|v| v != 0) + .unwrap_or(false); + let last_attempt_failed = row + .try_get::("last_attempt_failed") + .map(|v| v != 0) + .unwrap_or(false); + let executor: String = row.try_get("executor").unwrap_or_else(|_| String::new()); + + items.push(TaskWithAttemptStatus { + task, + has_in_progress_attempt, + has_merged_attempt: false, + last_attempt_failed, + executor, + attempt_count: 0, // TODO: Query actual attempt count if needed + }); + } + + Ok(Json(ApiResponse::success(items))) +} + +/// Forge WebSocket stream handler with agent task filtering +pub async fn forge_stream_tasks_ws( + ws: WebSocketUpgrade, + State(deployment): State, + Query(query): Query, +) -> impl IntoResponse { + ws.on_upgrade(move |socket| async move { + if let Err(e) = handle_forge_tasks_ws(socket, deployment, query.project_id).await { + tracing::warn!("forge tasks WS closed: {}", e); + } + }) +} + +async fn handle_forge_tasks_ws( + socket: WebSocket, + deployment: DeploymentImpl, + project_id: Uuid, +) -> anyhow::Result<()> { + let db_pool = deployment.db().pool.clone(); + let stream = deployment + .events() + .stream_tasks_raw(project_id) + .await? + .filter_map(move |msg_result| { + let db_pool = db_pool.clone(); + async move { + match msg_result { + Ok(LogMsg::JsonPatch(patch)) => { + if let Some(patch_op) = patch.0.first() { + if patch_op.path().starts_with("/tasks/") { + match patch_op { + json_patch::PatchOperation::Add(op) => { + if let Ok(task_with_status) = + serde_json::from_value::(op.value.clone()) + { + let is_agent: bool = sqlx::query_scalar( + "SELECT EXISTS(SELECT 1 FROM forge_agents WHERE task_id = ?)" + ) + .bind(task_with_status.task.id) + .fetch_one(&db_pool) + .await + .unwrap_or(false); + + if !is_agent { + return Some(Ok(LogMsg::JsonPatch(patch))); + } + return None; + } + } + json_patch::PatchOperation::Replace(op) => { + if let Ok(task_with_status) = + serde_json::from_value::(op.value.clone()) + { + let is_agent: bool = sqlx::query_scalar( + "SELECT EXISTS(SELECT 1 FROM forge_agents WHERE task_id = ?)" + ) + .bind(task_with_status.task.id) + .fetch_one(&db_pool) + .await + .unwrap_or(false); + + if !is_agent { + return Some(Ok(LogMsg::JsonPatch(patch))); + } + return None; + } + } + json_patch::PatchOperation::Remove(_) => { + return Some(Ok(LogMsg::JsonPatch(patch))); + } + _ => {} + } + } else if patch_op.path() == "/tasks" { + if let json_patch::PatchOperation::Replace(op) = patch_op { + if let Some(tasks_obj) = op.value.as_object() { + let mut filtered_tasks = serde_json::Map::new(); + for (task_id_str, task_value) in tasks_obj { + if let Ok(task_with_status) = + serde_json::from_value::(task_value.clone()) + { + let is_agent: bool = sqlx::query_scalar( + "SELECT EXISTS(SELECT 1 FROM forge_agents WHERE task_id = ?)" + ) + .bind(task_with_status.task.id) + .fetch_one(&db_pool) + .await + .unwrap_or(false); + + if !is_agent { + filtered_tasks.insert(task_id_str.to_string(), task_value.clone()); + } + } + } + + let filtered_patch = json!([{ + "op": "replace", + "path": "/tasks", + "value": filtered_tasks + }]); + return Some(Ok(LogMsg::JsonPatch( + serde_json::from_value(filtered_patch).unwrap() + ))); + } + } + } + } + Some(Ok(LogMsg::JsonPatch(patch))) + } + Ok(other) => Some(Ok(other)), + Err(e) => Some(Err(e)), + } + } + }) + .map_ok(|msg| msg.to_ws_message_unchecked()); + + futures_util::pin_mut!(stream); + + let (mut sender, mut receiver) = socket.split(); + + tokio::spawn(async move { while let Some(Ok(_)) = receiver.next().await {} }); + + while let Some(item) = stream.next().await { + match item { + Ok(msg) => { + if sender.send(msg).await.is_err() { + break; + } + } + Err(e) => { + tracing::error!("stream error: {}", e); + break; + } + } + } + Ok(()) +} + +/// Forge-specific CreateAndStartTaskRequest that includes github_issue_id +#[derive(Debug, Serialize, Deserialize)] +pub struct ForgeCreateAndStartTaskRequest { + pub task: db::models::task::CreateTask, + pub executor_profile_id: executors::profile::ExecutorProfileId, + pub base_branch: String, + pub github_issue_id: Option, // GitHub issue ID for "No Wish Without Issue" rule +} + +/// Forge override: create task and start with forge/ branch prefix (vk -> forge only) +/// Supports github_issue_id for "No Wish Without Issue" rule enforcement +pub async fn forge_create_task_and_start( + State(deployment): State, + State(forge_services): State, + Json(payload): Json, +) -> Result>, ApiError> { + let task_id = Uuid::new_v4(); + let mut task = Task::create(&deployment.db().pool, &payload.task, task_id).await?; + + // Set github_issue_id if provided (Forge extension for issue tracking) + if let Some(github_issue_id) = payload.github_issue_id { + sqlx::query( + "UPDATE tasks SET github_issue_id = ?, updated_at = datetime('now') WHERE id = ?", + ) + .bind(github_issue_id) + .bind(task_id) + .execute(&deployment.db().pool) + .await?; + + // Re-fetch task to get updated github_issue_id (avoids returning stale data) + task = Task::find_by_id(&deployment.db().pool, task_id) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + } + + if let Some(image_ids) = &payload.task.image_ids { + TaskImage::associate_many(&deployment.db().pool, task.id, image_ids).await?; + } + + deployment + .track_if_analytics_allowed( + "task_created", + serde_json::json!({ + "task_id": task.id.to_string(), + "project_id": task.project_id, + "has_description": task.description.is_some(), + "has_images": payload.task.image_ids.is_some(), + "github_issue_id": payload.github_issue_id, + }), + ) + .await; + + let task_attempt_id = Uuid::new_v4(); + + let task_title_id = git_branch_id(&task.title); + let short_id = short_uuid(&task_attempt_id); + let branch_name = format!("forge/{}-{}", short_id, task_title_id); + + let mut task_attempt = TaskAttempt::create( + &deployment.db().pool, + &CreateTaskAttempt { + executor: payload.executor_profile_id.executor, + base_branch: payload.base_branch.clone(), + branch: branch_name, + }, + task_attempt_id, + task.id, + ) + .await?; + + sqlx::query( + "INSERT INTO forge_task_attempt_config (task_attempt_id, use_worktree) VALUES (?, ?)" + ) + .bind(task_attempt_id) + .bind(true) + .execute(&deployment.db().pool) + .await?; + + if let Some(variant) = &payload.executor_profile_id.variant { + let executor_with_variant = format!("{}:{}", payload.executor_profile_id.executor, variant); + sqlx::query( + "UPDATE task_attempts SET executor = ?, updated_at = datetime('now') WHERE id = ?", + ) + .bind(&executor_with_variant) + .bind(task_attempt_id) + .execute(&deployment.db().pool) + .await?; + task_attempt.executor = executor_with_variant; + } + + let project = task + .parent_project(&deployment.db().pool) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + if let Ok(workspace_profiles) = forge_services.load_profiles_for_workspace(&project.git_repo_path).await { + let variant_count = workspace_profiles.executors.values() + .map(|config| config.configurations.len()) + .sum::(); + + let variant_list: Vec = workspace_profiles.executors.iter() + .flat_map(|(executor, config)| { + config.configurations.iter().map(move |(variant, coding_agent)| { + let prompt_preview = match coding_agent { + executors::executors::CodingAgent::ClaudeCode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Codex(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Amp(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Gemini(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Opencode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::CursorAgent(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::QwenCode(cfg) => cfg.append_prompt.get(), + executors::executors::CodingAgent::Copilot(cfg) => cfg.append_prompt.get(), + }.map(|p| { + let trimmed = p.trim(); + if trimmed.len() > 60 { + format!("{}...", &trimmed[..60]) + } else { + trimmed.to_string() + } + }).unwrap_or_else(|| "".to_string()); + + format!("{}:{} ({})", executor, variant, prompt_preview) + }) + }) + .collect(); + + tracing::info!( + "Injected {} .genie profile variant(s) for workspace: {} | Profiles: [{}]", + variant_count, + project.git_repo_path.display(), + variant_list.join(", ") + ); + + executors::profile::ExecutorConfigs::set_cached(workspace_profiles); + } else { + tracing::warn!( + "Failed to load .genie profiles for workspace: {}, using defaults", + project.git_repo_path.display() + ); + } + + let execution_process = deployment + .container() + .start_attempt(&task_attempt, payload.executor_profile_id.clone()) + .await?; + + deployment + .track_if_analytics_allowed( + "task_attempt_started", + serde_json::json!({ + "task_id": task.id.to_string(), + "executor": &payload.executor_profile_id.executor, + "variant": &payload.executor_profile_id.variant, + "attempt_id": task_attempt.id.to_string(), + }), + ) + .await; + + let task = Task::find_by_id(&deployment.db().pool, task.id) + .await? + .ok_or(ApiError::Database(SqlxError::RowNotFound))?; + + tracing::info!( + "Started execution process {} with forge/ branch", + execution_process.id + ); + Ok(Json(ApiResponse::success(TaskWithAttemptStatus { + task, + has_in_progress_attempt: true, + has_merged_attempt: false, + last_attempt_failed: false, + executor: task_attempt.executor, + attempt_count: 1, // Just created first attempt + }))) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_forge_branch_prefix_format() { + let attempt_id = Uuid::new_v4(); + let task_title = "test task"; + + let task_title_id = git_branch_id(task_title); + let short_id = short_uuid(&attempt_id); + let branch_name = format!("forge/{}-{}", short_id, task_title_id); + + assert!(branch_name.starts_with("forge/")); + assert!(branch_name.contains(&short_id)); + assert!(branch_name.contains(&task_title_id)); + } + + #[test] + fn test_forge_branch_prefix_uniqueness() { + let attempt_id_1 = Uuid::new_v4(); + let attempt_id_2 = Uuid::new_v4(); + let task_title = "test"; + + let task_title_id = git_branch_id(task_title); + let short_id_1 = short_uuid(&attempt_id_1); + let short_id_2 = short_uuid(&attempt_id_2); + + let branch_1 = format!("forge/{}-{}", short_id_1, task_title_id); + let branch_2 = format!("forge/{}-{}", short_id_2, task_title_id); + + assert_ne!(branch_1, branch_2); + assert!(branch_1.starts_with("forge/")); + assert!(branch_2.starts_with("forge/")); + } + + #[test] + fn test_forge_branch_format_matches_upstream() { + let attempt_id = Uuid::new_v4(); + let task_title = "my-test-task"; + + let task_title_id = git_branch_id(task_title); + let short_id = short_uuid(&attempt_id); + + let forge_branch = format!("forge/{}-{}", short_id, task_title_id); + let upstream_branch = format!("vk/{}-{}", short_id, task_title_id); + + assert_eq!( + forge_branch.replace("forge/", ""), + upstream_branch.replace("vk/", "") + ); + } +} diff --git a/forge-app/src/services/mod.rs b/forge-app/src/services/mod.rs index c86259eda..b531bb4d8 100644 --- a/forge-app/src/services/mod.rs +++ b/forge-app/src/services/mod.rs @@ -41,6 +41,7 @@ impl ForgeServices { // Note: All migrations (including forge-specific) are now in upstream/crates/db/migrations let deployment = DeploymentImpl::new().await?; ensure_legacy_base_branch_column(&deployment.db().pool).await?; + ensure_github_issue_id_column(&deployment.db().pool).await?; deployment.update_sentry_scope().await?; deployment.cleanup_orphan_executions().await?; @@ -305,6 +306,34 @@ async fn ensure_legacy_base_branch_column(pool: &SqlitePool) -> Result<()> { Ok(()) } +/// Add github_issue_id column to tasks table for "No Wish Without Issue" rule enforcement +/// Links tasks to their originating GitHub issues for traceability +async fn ensure_github_issue_id_column(pool: &SqlitePool) -> Result<()> { + let has_github_issue_id = sqlx::query_scalar::<_, i64>( + "SELECT COUNT(1) FROM pragma_table_info('tasks') WHERE name = 'github_issue_id'", + ) + .fetch_one(pool) + .await? + > 0; + + tracing::debug!( + has_github_issue_id, + "schema check for tasks.github_issue_id" + ); + + if !has_github_issue_id { + sqlx::query("ALTER TABLE tasks ADD COLUMN github_issue_id INTEGER") + .execute(pool) + .await?; + + tracing::info!( + "Added tasks.github_issue_id column for GitHub issue tracking (No Wish Without Issue rule)" + ); + } + + Ok(()) +} + fn spawn_omni_notification_worker(pool: SqlitePool, config: Arc) { tokio::spawn(async move { loop { diff --git a/frontend/package.json b/frontend/package.json index ed19e65d2..8eaa81a61 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -87,7 +87,6 @@ "@rjsf/utils": "6.0.0-beta.11", "@rjsf/validator-ajv8": "6.0.0-beta.11", "@tailwindcss/container-queries": "^0.1.1", - "@types/lodash": "^4.17.20", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^7.18.0", diff --git a/frontend/src/components/DiffCard.tsx b/frontend/src/components/DiffCard.tsx index 89438158e..57b859a13 100644 --- a/frontend/src/components/DiffCard.tsx +++ b/frontend/src/components/DiffCard.tsx @@ -1,7 +1,7 @@ import { Diff } from 'shared/types'; import { DiffModeEnum, DiffView, SplitSide } from '@git-diff-view/react'; import { generateDiffFile, type DiffFile } from '@git-diff-view/file'; -import { useMemo } from 'react'; +import { memo, useMemo } from 'react'; import { useUserSystem } from '@/components/config-provider'; import { getHighLightLanguageFromPath } from '@/utils/extToLanguage'; import { getActualTheme } from '@/utils/theme'; @@ -73,7 +73,7 @@ function readPlainLine( } } -export default function DiffCard({ +const DiffCard = memo(function DiffCard({ diff, expanded, onToggle, @@ -330,4 +330,6 @@ export default function DiffCard({ )} ); -} +}); + +export default DiffCard; diff --git a/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx b/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx index ed9b7da23..d12f2c6f0 100644 --- a/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx +++ b/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx @@ -1,3 +1,4 @@ +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import MarkdownRenderer from '@/components/ui/markdown-renderer.tsx'; import { @@ -608,7 +609,7 @@ const DisplayConversationEntryMaxWidth = (props: Props) => { ); }; -function DisplayConversationEntry({ +const DisplayConversationEntry = memo(function DisplayConversationEntry({ entry, expansionKey, executionProcessId, @@ -828,6 +829,6 @@ function DisplayConversationEntry({ ); -} +}); export default DisplayConversationEntryMaxWidth; diff --git a/frontend/src/components/layout/navbar.tsx b/frontend/src/components/layout/navbar.tsx index 18d9f0dd5..b2aaf24d8 100644 --- a/frontend/src/components/layout/navbar.tsx +++ b/frontend/src/components/layout/navbar.tsx @@ -17,8 +17,6 @@ import { MessageCircle, Menu, Plus, - Sun, - Moon, } from 'lucide-react'; import { Logo } from '@/components/logo'; import { SearchBar } from '@/components/search-bar'; @@ -28,9 +26,7 @@ import { useProject } from '@/contexts/project-context'; import { useOpenProjectInEditor } from '@/hooks/useOpenProjectInEditor'; import { useDiscordOnlineCount } from '@/hooks/useDiscordOnlineCount'; import { Breadcrumb } from '@/components/breadcrumb'; -import { useTheme } from '@/components/theme-provider'; -import { getActualTheme } from '@/utils/theme'; -import { ThemeMode } from 'shared/types'; +import { ThemeToggle } from '@/components/theme-toggle'; const INTERNAL_NAV = [ { label: 'Projects', icon: FolderOpen, to: '/projects' }, @@ -55,40 +51,6 @@ const EXTERNAL_LINKS = [ }, ]; -function ThemeToggle() { - const { theme, setTheme } = useTheme(); - const actualTheme = getActualTheme(theme); - - const toggleTheme = () => { - setTheme(actualTheme === 'light' ? ThemeMode.DARK : ThemeMode.LIGHT); - }; - - return ( - - ); -} - export function Navbar() { const location = useLocation(); const { projectId, project } = useProject(); diff --git a/frontend/src/components/projects/ProjectCard.tsx b/frontend/src/components/projects/ProjectCard.tsx index aa58edbbb..a685133bf 100644 --- a/frontend/src/components/projects/ProjectCard.tsx +++ b/frontend/src/components/projects/ProjectCard.tsx @@ -22,7 +22,7 @@ import { Loader2, } from 'lucide-react'; import { Project, TaskWithAttemptStatus } from 'shared/types'; -import { useEffect, useRef, useState } from 'react'; +import { memo, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useOpenProjectInEditor } from '@/hooks/useOpenProjectInEditor'; import { useNavigateWithSearch } from '@/hooks'; @@ -38,7 +38,7 @@ type Props = { onEdit: (project: Project) => void; }; -function ProjectCard({ +const ProjectCard = memo(function ProjectCard({ project, isFocused, fetchProjects, @@ -223,6 +223,6 @@ function ProjectCard({ ); -} +}); export default ProjectCard; diff --git a/frontend/src/components/tasks/TaskCard.tsx b/frontend/src/components/tasks/TaskCard.tsx index cf55bad74..43ee13316 100644 --- a/frontend/src/components/tasks/TaskCard.tsx +++ b/frontend/src/components/tasks/TaskCard.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { memo, useCallback, useEffect, useRef, useState } from 'react'; import { KanbanCard } from '@/components/ui/shadcn-io/kanban'; import { CheckCircle, @@ -59,7 +59,7 @@ function formatRelativeTime(dateString: string): string { return date.toLocaleDateString(); } -export function TaskCard({ +export const TaskCard = memo(function TaskCard({ task, index, status, @@ -286,4 +286,4 @@ export function TaskCard({ ); -} +}); diff --git a/frontend/src/components/theme-provider.tsx b/frontend/src/components/theme-provider.tsx index 3b3f8d6d9..6f8595ae6 100644 --- a/frontend/src/components/theme-provider.tsx +++ b/frontend/src/components/theme-provider.tsx @@ -1,6 +1,8 @@ import React, { createContext, useContext, useEffect, useState } from 'react'; import { ThemeMode } from 'shared/types'; +const THEME_STORAGE_KEY = 'forge-theme'; + type ThemeProviderProps = { children: React.ReactNode; initialTheme?: ThemeMode; @@ -9,52 +11,106 @@ type ThemeProviderProps = { type ThemeProviderState = { theme: ThemeMode; setTheme: (theme: ThemeMode) => void; + resolvedTheme: 'light' | 'dark'; }; const initialState: ThemeProviderState = { theme: ThemeMode.SYSTEM, setTheme: () => null, + resolvedTheme: 'light', }; const ThemeProviderContext = createContext(initialState); +function getStoredTheme(): ThemeMode | null { + try { + const stored = localStorage.getItem(THEME_STORAGE_KEY); + if (stored && Object.values(ThemeMode).includes(stored as ThemeMode)) { + return stored as ThemeMode; + } + } catch { + // localStorage may not be available + } + return null; +} + +function storeTheme(theme: ThemeMode): void { + try { + localStorage.setItem(THEME_STORAGE_KEY, theme); + } catch { + // localStorage may not be available + } +} + +function getResolvedTheme(theme: ThemeMode): 'light' | 'dark' { + if (theme === ThemeMode.SYSTEM) { + // SSR-safe: Check if window exists before accessing matchMedia + if (typeof window === 'undefined') { + return 'light'; // Default to light during SSR + } + return window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light'; + } + return theme.toLowerCase() as 'light' | 'dark'; +} + export function ThemeProvider({ children, - initialTheme = ThemeMode.SYSTEM, + initialTheme, ...props }: ThemeProviderProps) { - const [theme, setThemeState] = useState(initialTheme); + // Priority: initialTheme (from config) > localStorage > SYSTEM default + const [theme, setThemeState] = useState(() => { + return initialTheme ?? getStoredTheme() ?? ThemeMode.SYSTEM; + }); + const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(() => + getResolvedTheme(initialTheme ?? getStoredTheme() ?? ThemeMode.SYSTEM) + ); - // Update theme when initialTheme changes + // Update theme when initialTheme changes (from config load) useEffect(() => { - setThemeState(initialTheme); + if (initialTheme) { + setThemeState(initialTheme); + } }, [initialTheme]); + // Apply theme to DOM and update resolved theme useEffect(() => { const root = window.document.documentElement; + const resolved = getResolvedTheme(theme); root.classList.remove('light', 'dark'); + root.classList.add(resolved); + setResolvedTheme(resolved); + }, [theme]); - if (theme === ThemeMode.SYSTEM) { - const systemTheme = window.matchMedia('(prefers-color-scheme: dark)') - .matches - ? 'dark' - : 'light'; - - root.classList.add(systemTheme); - return; - } - - root.classList.add(theme.toLowerCase()); + // Listen for system theme changes when in SYSTEM mode + useEffect(() => { + if (theme !== ThemeMode.SYSTEM) return; + + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + const handleChange = (e: MediaQueryListEvent) => { + const root = window.document.documentElement; + const newResolved = e.matches ? 'dark' : 'light'; + root.classList.remove('light', 'dark'); + root.classList.add(newResolved); + setResolvedTheme(newResolved); + }; + + mediaQuery.addEventListener('change', handleChange); + return () => mediaQuery.removeEventListener('change', handleChange); }, [theme]); const setTheme = (newTheme: ThemeMode) => { setThemeState(newTheme); + storeTheme(newTheme); }; const value = { theme, setTheme, + resolvedTheme, }; return ( diff --git a/frontend/src/components/theme-toggle.tsx b/frontend/src/components/theme-toggle.tsx new file mode 100644 index 000000000..722fdeaf7 --- /dev/null +++ b/frontend/src/components/theme-toggle.tsx @@ -0,0 +1,51 @@ +import { Moon, Sun, Monitor } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { useTheme } from '@/components/theme-provider'; +import { ThemeMode } from 'shared/types'; + +export function ThemeToggle() { + const { theme, setTheme, resolvedTheme } = useTheme(); + + return ( + + + + + + setTheme(ThemeMode.LIGHT)} + className={theme === ThemeMode.LIGHT ? 'bg-accent' : ''} + > + + Light + + setTheme(ThemeMode.DARK)} + className={theme === ThemeMode.DARK ? 'bg-accent' : ''} + > + + Dark + + setTheme(ThemeMode.SYSTEM)} + className={theme === ThemeMode.SYSTEM ? 'bg-accent' : ''} + > + + System + + + + ); +} diff --git a/frontend/src/pages/settings/GeneralSettings.tsx b/frontend/src/pages/settings/GeneralSettings.tsx index 8a1484739..02cb13aab 100644 --- a/frontend/src/pages/settings/GeneralSettings.tsx +++ b/frontend/src/pages/settings/GeneralSettings.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { cloneDeep, merge, isEqual } from 'lodash'; +import { deepClone, deepMerge, isEqual } from '@/utils/object'; import { Card, CardContent, @@ -65,7 +65,7 @@ export function GeneralSettings() { } = useUserSystem(); // Draft state management - const [draft, setDraft] = useState(() => (config ? cloneDeep(config) : null)); + const [draft, setDraft] = useState(() => (config ? deepClone(config) : null)); const [dirty, setDirty] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); @@ -103,7 +103,7 @@ export function GeneralSettings() { useEffect(() => { if (!config) return; if (!dirty) { - setDraft(cloneDeep(config)); + setDraft(deepClone(config)); } }, [config, dirty]); @@ -118,7 +118,7 @@ export function GeneralSettings() { (patch: Partial) => { setDraft((prev: typeof config) => { if (!prev) return prev; - const next = merge({}, prev, patch); + const next = deepMerge({}, prev, patch); // Mark dirty if changed if (!isEqual(next, config)) { setDirty(true); @@ -176,7 +176,7 @@ export function GeneralSettings() { const handleDiscard = () => { if (!config) return; - setDraft(cloneDeep(config)); + setDraft(deepClone(config)); setDirty(false); }; diff --git a/frontend/src/pages/settings/ProjectSettings.tsx b/frontend/src/pages/settings/ProjectSettings.tsx index 5f967105b..e746eed80 100644 --- a/frontend/src/pages/settings/ProjectSettings.tsx +++ b/frontend/src/pages/settings/ProjectSettings.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { isEqual } from 'lodash'; +import { isEqual } from '@/utils/object'; import { Card, CardContent, diff --git a/frontend/src/utils/object.ts b/frontend/src/utils/object.ts new file mode 100644 index 000000000..31e5e6657 --- /dev/null +++ b/frontend/src/utils/object.ts @@ -0,0 +1,157 @@ +/** + * Native JavaScript alternatives to lodash object utilities. + * These reduce bundle size by ~40KB compared to importing from lodash. + */ + +/** + * Deep equality comparison between two values. + * Handles primitives, arrays, objects, Date, RegExp, Map, Set. + * Protects against circular references using a WeakMap. + */ +export function isEqual(a: unknown, b: unknown): boolean { + return isEqualWithTracking(a, b, new WeakMap()); +} + +function isEqualWithTracking( + a: unknown, + b: unknown, + visited: WeakMap +): boolean { + if (a === b) return true; + + if (a === null || b === null) return a === b; + if (typeof a !== typeof b) return false; + + if (typeof a !== 'object') return a === b; + + // Circular reference protection + if (visited.has(a as object)) { + return visited.get(a as object) === b; + } + if (typeof a === 'object' && typeof b === 'object') { + visited.set(a as object, b as object); + } + + // Handle Date + if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime(); + } + + // Handle RegExp + if (a instanceof RegExp && b instanceof RegExp) { + return a.toString() === b.toString(); + } + + // Handle Map + if (a instanceof Map && b instanceof Map) { + if (a.size !== b.size) return false; + for (const [key, val] of a) { + if (!b.has(key) || !isEqualWithTracking(val, b.get(key), visited)) + return false; + } + return true; + } + + // Handle Set - use deep equality for set values + if (a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return false; + const aArr = Array.from(a); + const bArr = Array.from(b); + // For each value in a, find a deeply equal value in b + for (const aVal of aArr) { + const found = bArr.some((bVal) => isEqualWithTracking(aVal, bVal, visited)); + if (!found) return false; + } + return true; + } + + // Handle Arrays + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if (!isEqualWithTracking(a[i], b[i], visited)) return false; + } + return true; + } + + // Handle plain objects + if (Array.isArray(a) !== Array.isArray(b)) return false; + + const aObj = a as Record; + const bObj = b as Record; + + const keysA = Object.keys(aObj); + const keysB = Object.keys(bObj); + + if (keysA.length !== keysB.length) return false; + + for (const key of keysA) { + if (!Object.prototype.hasOwnProperty.call(bObj, key)) return false; + if (!isEqualWithTracking(aObj[key], bObj[key], visited)) return false; + } + + return true; +} + +/** + * Deep clone an object using the native structuredClone API. + * This is the standard way to deep clone objects in modern browsers. + */ +export function deepClone(obj: T): T { + return structuredClone(obj); +} + +/** + * Check if a value is a plain object (not an array, null, Date, etc.) + */ +function isPlainObject(value: unknown): value is Record { + if (value === null || typeof value !== 'object') return false; + const proto = Object.getPrototypeOf(value); + return proto === Object.prototype || proto === null; +} + +/** + * Deep merge multiple objects into a new object. + * Later objects take precedence over earlier ones. + * Arrays are replaced, not merged. + * Protects against circular references using a WeakMap. + */ +export function deepMerge>( + ...objects: (Partial | undefined | null)[] +): T { + return deepMergeWithTracking(new WeakMap(), ...objects) as T; +} + +function deepMergeWithTracking>( + visited: WeakMap, + ...objects: (Partial | undefined | null)[] +): Record { + const result: Record = {}; + + for (const obj of objects) { + if (!obj) continue; + + // Circular reference protection + if (visited.has(obj)) { + return visited.get(obj) as Record; + } + visited.set(obj, result); + + for (const key of Object.keys(obj)) { + const targetVal = result[key]; + const sourceVal = obj[key]; + + if (isPlainObject(targetVal) && isPlainObject(sourceVal)) { + result[key] = deepMergeWithTracking( + visited, + targetVal as Record, + sourceVal as Record + ); + } else { + result[key] = sourceVal; + } + } + } + + return result; +} diff --git a/npx-cli/bin/cli.js b/npx-cli/bin/cli.js index 5815a9488..a0ce03ddf 100755 --- a/npx-cli/bin/cli.js +++ b/npx-cli/bin/cli.js @@ -15,17 +15,6 @@ if (fs.existsSync(envPath)) { } } -// Read version from package.json and set FORGE_VERSION env var -// This enables zero-rebuild promotion: binary reads version at runtime -const packageJsonPath = path.join(__dirname, "..", "package.json"); -try { - const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); - process.env.FORGE_VERSION = pkg.version; -} catch (err) { - console.warn("âš ī¸ Could not read package version, using 'unknown'"); - process.env.FORGE_VERSION = "unknown"; -} - // Resolve effective arch for our published 64-bit binaries only. // Any ARM → arm64; anything else → x64. On macOS, handle Rosetta. function getEffectiveArch() { @@ -33,7 +22,7 @@ function getEffectiveArch() { const nodeArch = process.arch; if (platform === "darwin") { - // If Node itself is arm64, we're natively on Apple silicon + // If Node itself is arm64, we’re natively on Apple silicon if (nodeArch === "arm64") return "arm64"; // Otherwise check for Rosetta translation @@ -63,15 +52,15 @@ function getEffectiveArch() { function isAndroid() { if (process.platform === "android") return true; - + if (process.env.TERMUX_VERSION) return true; if (process.env.ANDROID_ROOT || process.env.ANDROID_DATA) return true; - + try { if (fs.existsSync("/system/bin/getprop")) return true; } catch { } - + return false; } @@ -105,321 +94,16 @@ function getBinaryName(base) { return platform === "win32" ? `${base}.exe` : base; } -// ============================================================================ -// Port Takeover Helpers -// ============================================================================ - -/** - * Find the PID of a process using a given port - * @param {number|string} port - Port number to check - * @returns {number|null} - PID of the process using the port, or null - */ -function findPidUsingPort(port) { - try { - if (platform === "linux" || platform === "android") { - // Try ss first (more modern) - try { - const output = execSync(`ss -tulpn 2>/dev/null | grep ':${port} '`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"], - }); - const match = output.match(/pid=(\d+)/); - if (match) return parseInt(match[1], 10); - } catch { - // ss failed or no match, try lsof - } - // Fallback to lsof - try { - const output = execSync(`lsof -i :${port} -t 2>/dev/null`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"], - }); - const pid = parseInt(output.trim().split("\n")[0], 10); - if (!isNaN(pid)) return pid; - } catch { - // lsof failed - } - } else if (platform === "darwin") { - // macOS uses lsof - try { - const output = execSync(`lsof -i :${port} -t 2>/dev/null`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"], - }); - const pid = parseInt(output.trim().split("\n")[0], 10); - if (!isNaN(pid)) return pid; - } catch { - // lsof failed - } - } else if (platform === "win32") { - // Windows uses netstat - try { - const output = execSync(`netstat -ano | findstr :${port} | findstr LISTENING`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"], - }); - const lines = output.trim().split("\n"); - if (lines.length > 0) { - const parts = lines[0].trim().split(/\s+/); - const pid = parseInt(parts[parts.length - 1], 10); - if (!isNaN(pid)) return pid; - } - } catch { - // netstat failed - } - } - } catch { - // Command execution failed - } - return null; -} - -/** - * Check if a process is an automagik-forge instance - * @param {number} pid - Process ID to check - * @returns {boolean} - True if the process is automagik-forge - */ -function isForgeProcess(pid) { - try { - if (platform === "linux" || platform === "android") { - // Read /proc/{pid}/cmdline - const cmdline = fs.readFileSync(`/proc/${pid}/cmdline`, "utf8"); - return cmdline.includes("automagik-forge"); - } else if (platform === "darwin") { - // Use ps on macOS - const output = execSync(`ps -p ${pid} -o command= 2>/dev/null`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"], - }); - return output.includes("automagik-forge"); - } else if (platform === "win32") { - // Use wmic or tasklist on Windows - const output = execSync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH 2>nul`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"], - }); - return output.toLowerCase().includes("automagik-forge"); - } - } catch { - // Failed to check - assume it could be Forge - } - return false; -} - -/** - * Query existing Forge instance for running tasks - * @param {string} host - Host address - * @param {number|string} port - Port number - * @returns {Promise} - True if there are running tasks - */ -async function hasRunningTasks(host, port) { - try { - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), 3000); - - // First get all projects - const projectsRes = await fetch(`http://${host}:${port}/api/projects`, { - signal: controller.signal, - }); - - if (!projectsRes.ok) { - clearTimeout(timeout); - return false; - } - - const projectsData = await projectsRes.json(); - const projects = projectsData.data || []; - - // Check tasks for each project - for (const project of projects) { - try { - const tasksRes = await fetch( - `http://${host}:${port}/api/tasks?project_id=${project.id}`, - { signal: controller.signal } - ); - - if (tasksRes.ok) { - const tasksData = await tasksRes.json(); - const tasks = tasksData.data || []; - if (tasks.some((t) => t.has_in_progress_attempt)) { - clearTimeout(timeout); - return true; - } - } - } catch { - // Skip this project if request fails - } - } - - clearTimeout(timeout); - return false; - } catch { - // Can't connect or timeout - treat as no running tasks - return false; - } -} - -/** - * Prompt user for takeover confirmation - * @param {number} pid - PID of the existing process - * @param {boolean} hasRunning - Whether there are running tasks - * @returns {Promise} - True if user confirmed takeover - */ -async function promptTakeover(pid, hasRunning) { - const readline = require("readline"); - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - - const warning = hasRunning - ? "\nâš ī¸ WARNING: Running tasks will be terminated!" - : ""; - - return new Promise((resolve) => { - rl.question( - `🔒 Port in use by Forge instance (PID ${pid}).${warning}\nTake over? [y/N] `, - (answer) => { - rl.close(); - resolve(answer.toLowerCase() === "y"); - } - ); - }); -} - -/** - * Kill a process gracefully (SIGTERM first, then SIGKILL) - * @param {number} pid - Process ID to kill - * @returns {boolean} - True if process was killed successfully - */ -function killProcess(pid) { - try { - // Send SIGTERM for graceful shutdown - process.kill(pid, "SIGTERM"); - - // Wait up to 3 seconds for process to exit - const startTime = Date.now(); - while (Date.now() - startTime < 3000) { - try { - // Check if process is still running (signal 0 doesn't kill, just checks) - process.kill(pid, 0); - // Still running, wait a bit - execSync("sleep 0.1", { stdio: "ignore" }); - } catch { - // Process no longer exists - success - return true; - } - } - - // Process still running after 3s, force kill - try { - if (platform === "win32") { - execSync(`taskkill /F /PID ${pid}`, { stdio: "ignore" }); - } else { - process.kill(pid, "SIGKILL"); - } - } catch { - // Already dead or permission denied - } - return true; - } catch (e) { - if (e.code === "EPERM") { - console.error(`❌ Permission denied: Cannot kill process ${pid}`); - console.error("Try running with sudo or as the process owner."); - } else if (e.code === "ESRCH") { - // Process doesn't exist - that's fine - return true; - } - return false; - } -} - -/** - * Wait for a port to become available - * @param {number|string} port - Port number - * @param {number} timeout - Maximum wait time in ms - * @returns {Promise} - True if port is available - */ -async function waitForPort(port, timeout = 2000) { - const startTime = Date.now(); - while (Date.now() - startTime < timeout) { - if (!findPidUsingPort(port)) { - return true; - } - await new Promise((resolve) => setTimeout(resolve, 100)); - } - return false; -} - -/** - * Handle port takeover logic - * @param {string} host - Host address - * @param {number|string} port - Port number - * @param {boolean} isMcp - Whether running in MCP mode (no interactive prompts) - * @returns {Promise} - True if can proceed with startup - */ -async function handlePortConflict(host, port, isMcp) { - const pid = findPidUsingPort(port); - if (!pid) { - return true; // Port is free - } - - const isForge = isForgeProcess(pid); - - if (!isForge) { - // Non-Forge process - don't auto-kill, show error - console.error(`❌ Port ${port} is in use by another process (PID ${pid})`); - console.error("Please stop the process or use a different port:"); - console.error(` BACKEND_PORT=8888 npx automagik-forge`); - return false; - } - - // It's a Forge process - check for running tasks - const hasRunning = await hasRunningTasks(host, port); - - if (hasRunning && !isMcp) { - // Interactive prompt when there are running tasks - const proceed = await promptTakeover(pid, true); - if (!proceed) { - console.log("👋 Aborted. Existing instance kept running."); - return false; - } - } else if (!hasRunning) { - // No running tasks - automatic takeover - console.log(`🔄 Taking over from existing Forge instance (PID ${pid})...`); - } else { - // MCP mode with running tasks - proceed anyway (no stdin) - console.log(`🔄 Taking over from existing Forge instance (PID ${pid})...`); - console.log("âš ī¸ Note: Running tasks may be interrupted."); - } - - // Kill the existing process - if (!killProcess(pid)) { - console.error("❌ Failed to stop existing instance."); - return false; - } - - // Wait for port to be released - console.log("âŗ Waiting for port to be released..."); - const portFree = await waitForPort(port, 3000); - if (!portFree) { - console.error(`❌ Port ${port} still in use after stopping process.`); - console.error("This may be due to TIME_WAIT state. Try again in a few seconds."); - return false; - } - - console.log("✅ Port released, starting new instance...\n"); - return true; -} - const platformDir = getPlatformDir(); const extractDir = path.join(__dirname, "..", "dist", platformDir); const isMcpMode = process.argv.includes("--mcp"); +// Search for "cleanup" subcommand in args (more robust than hardcoding index) +const isCleanupMode = process.argv.slice(2).some(arg => arg === "cleanup"); // ensure output dir fs.mkdirSync(extractDir, { recursive: true }); -function extractAndRun(baseName, args, launch) { +function extractAndRun(baseName, launch) { const binName = getBinaryName(baseName); const binPath = path.join(extractDir, binName); const zipName = `${baseName}.zip`; @@ -457,75 +141,63 @@ function extractAndRun(baseName, args, launch) { fs.chmodSync(binPath, 0o755); } catch { } } - return launch(binPath, args); + return launch(binPath); } -if (isMcpMode) { - // MCP mode: handle port conflicts silently (no interactive prompts) - (async () => { - const backendPort = process.env.BACKEND_PORT || process.env.PORT; - const displayPort = backendPort || "8887"; - const host = process.env.HOST || "127.0.0.1"; - - // Check for port conflicts (MCP mode = true, no interactive prompts) - const canProceed = await handlePortConflict(host, displayPort, true); - if (!canProceed) { +if (isCleanupMode) { + // Cleanup mode - run forge-cleanup binary with remaining args + // Filter out "cleanup" command and pass remaining args to the binary + const cleanupArgs = process.argv.slice(2).filter(arg => arg !== "cleanup"); + extractAndRun("forge-cleanup", (bin) => { + const proc = spawn(bin, cleanupArgs, { stdio: "inherit" }); + proc.on("exit", (c) => process.exit(c || 0)); + proc.on("error", (e) => { + console.error("❌ Cleanup error:", e.message); + process.exit(1); + }); + }); +} else if (isMcpMode) { + extractAndRun("automagik-forge-mcp", (bin) => { + const proc = spawn(bin, [], { stdio: "inherit" }); + proc.on("exit", (c) => process.exit(c || 0)); + proc.on("error", (e) => { + console.error("❌ MCP server error:", e.message); process.exit(1); - } - - extractAndRun("automagik-forge", ["--mcp"], (bin, args) => { - const proc = spawn(bin, args, { stdio: "inherit" }); - proc.on("exit", (c) => process.exit(c || 0)); - proc.on("error", (e) => { - console.error("❌ MCP server error:", e.message); - process.exit(1); - }); - process.on("SIGINT", () => { - console.error("\n🛑 Shutting down MCP server..."); - proc.kill("SIGINT"); - }); - process.on("SIGTERM", () => proc.kill("SIGTERM")); }); - })(); + process.on("SIGINT", () => { + console.error("\n🛑 Shutting down MCP server..."); + proc.kill("SIGINT"); + }); + process.on("SIGTERM", () => proc.kill("SIGTERM")); + }); } else { - // Wrap in async IIFE to support port conflict handling - (async () => { - // Get port configuration early for conflict detection + console.log(`đŸ“Ļ Extracting automagik-forge...`); + extractAndRun("automagik-forge", (bin) => { + // Log port configuration const backendPort = process.env.BACKEND_PORT || process.env.PORT; const displayPort = backendPort || "8887"; - const host = process.env.HOST || "127.0.0.1"; - - // Check for port conflicts before extraction - const canProceed = await handlePortConflict(host, displayPort, false); - if (!canProceed) { - process.exit(1); + if (backendPort) { + console.log(`🔌 Using port: ${backendPort}`); + } else { + console.log(`🔌 Using default port: 8887`); } - console.log(`đŸ“Ļ Extracting automagik-forge...`); - extractAndRun("automagik-forge", [], (bin) => { - // Log port configuration - if (backendPort) { - console.log(`🔌 Using port: ${backendPort}`); - } else { - console.log(`🔌 Using default port: 8887`); - } - - console.log(`🚀 Launching automagik-forge...`); - console.log(); + console.log(`🚀 Launching automagik-forge...`); + console.log(); - // Ensure RUST_LOG is set to show logs (default to info level) - if (!process.env.RUST_LOG) { - process.env.RUST_LOG = "info"; - } + // Ensure RUST_LOG is set to show logs (default to info level) + if (!process.env.RUST_LOG) { + process.env.RUST_LOG = "info"; + } - console.log(`http://${host}:${displayPort}/`); - console.log(); + const host = process.env.HOST || "127.0.0.1"; + console.log(`http://${host}:${displayPort}/`); + console.log(); - if (platform === "win32") { - execSync(`"${bin}"`, { stdio: "inherit" }); - } else { - execSync(`"${bin}"`, { stdio: "inherit" }); - } - }); - })(); + if (platform === "win32") { + execSync(`"${bin}"`, { stdio: "inherit" }); + } else { + execSync(`"${bin}"`, { stdio: "inherit" }); + } + }); } diff --git a/package.json b/package.json index 091ab85f0..a9aa0afb1 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "@radix-ui/react-slider": "^1.3.6", "@radix-ui/react-toggle-group": "^1.1.11", "framer-motion": "^12.23.22", - "lodash": "^4.17.21", "mermaid": "11.4.1", "react-resizable-panels": "^3.0.6", "uuid": "^13.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6058d8673..871506b18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,9 +23,6 @@ importers: framer-motion: specifier: ^12.23.22 version: 12.23.24(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - lodash: - specifier: ^4.17.21 - version: 4.17.21 mermaid: specifier: 11.4.1 version: 11.4.1 @@ -41,7 +38,7 @@ importers: devDependencies: '@playwright/test': specifier: ^1.56.1 - version: 1.56.1 + version: 1.57.0 '@tailwindcss/container-queries': specifier: ^0.1.1 version: 0.1.1(tailwindcss@3.4.18(yaml@2.8.1)) @@ -56,7 +53,7 @@ importers: version: 11.0.0 playwright: specifier: ^1.56.1 - version: 1.56.1 + version: 1.57.0 typescript: specifier: ^5.9.2 version: 5.9.3 @@ -200,13 +197,13 @@ importers: version: 5.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-i18next: specifier: ^15.7.3 - version: 15.7.4(i18next@25.6.1(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(typescript@5.9.3) + version: 15.7.4(i18next@25.6.1(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(typescript@5.9.3) react-router-dom: specifier: ^6.8.1 version: 6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-spring: specifier: ^10.0.3 - version: 10.0.3(@react-three/fiber@8.18.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(three@0.181.1))(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react-konva@18.2.14(@types/react@18.3.26)(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react-zdog@1.2.2)(react@18.3.1)(three@0.181.1)(zdog@1.1.3) + version: 10.0.3(@react-three/fiber@9.4.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(three@0.181.2))(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react-konva@19.2.1(@types/react@18.3.26)(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react-zdog@1.2.2)(react@18.3.1)(three@0.181.2)(zdog@1.1.3) react-use-websocket: specifier: ^4.7.0 version: 4.13.0 @@ -227,7 +224,7 @@ importers: version: 1.0.7(tailwindcss@3.4.18(yaml@2.8.1)) use-context-selector: specifier: ^2.0.0 - version: 2.0.0(react@18.3.1)(scheduler@0.24.0-canary-efb381bbf-20230505) + version: 2.0.0(react@18.3.1)(scheduler@0.23.2) uuid: specifier: ^13.0.0 version: 13.0.0 @@ -247,9 +244,6 @@ importers: '@tailwindcss/container-queries': specifier: ^0.1.1 version: 0.1.1(tailwindcss@3.4.18(yaml@2.8.1)) - '@types/lodash': - specifier: ^4.17.20 - version: 4.17.20 '@types/react': specifier: ^18.2.43 version: 18.3.26 @@ -264,7 +258,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.9.3) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.7.0(vite@5.4.21(@types/node@24.10.0)(terser@5.44.1)) + version: 4.7.0(vite@5.4.21(@types/node@22.19.1)(terser@5.44.1)) autoprefixer: specifier: ^10.4.16 version: 10.4.21(postcss@8.5.6) @@ -297,7 +291,7 @@ importers: version: 4.3.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) knip: specifier: ^5.70.2 - version: 5.70.2(@types/node@24.10.0)(typescript@5.9.3) + version: 5.70.2(@types/node@22.19.1)(typescript@5.9.3) postcss: specifier: ^8.4.32 version: 8.5.6 @@ -312,7 +306,7 @@ importers: version: 5.9.3 vite: specifier: ^5.0.8 - version: 5.4.21(@types/node@24.10.0)(terser@5.44.1) + version: 5.4.21(@types/node@22.19.1)(terser@5.44.1) packages: @@ -368,43 +362,14 @@ packages: resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.5': - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-regexp-features-plugin@7.28.5': - resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - '@babel/helper-environment-visitor@7.24.7': - resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} - engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} @@ -415,30 +380,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.27.1': resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -451,10 +396,6 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} @@ -464,134 +405,45 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': - resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': - resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': - resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': - resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.13.0 - - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-proposal-async-generator-functions@7.20.7': - resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-class-properties@7.18.6': - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-export-default-from@7.27.1': - resolution: {integrity: sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6': - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-numeric-separator@7.18.6': - resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-object-rest-spread@7.20.7': - resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-optional-catch-binding@7.18.6': - resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-optional-chaining@7.21.0': - resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': - resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} - engines: {node: '>=6.9.0'} + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-async-generators@7.8.4': - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-dynamic-import@7.8.3': - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-export-default-from@7.27.1': - resolution: {integrity: sha512-eBC/3KSekshx19+N40MzjWqJd7KTEdOoLesAfa4IDFI8eRz5a47i5Oszus6zG/cwIXN63YhgLOMSSNJx49sENg==} + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-flow@7.27.1': - resolution: {integrity: sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==} + '@babel/plugin-syntax-import-attributes@7.27.1': + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} - engines: {node: '>=6.9.0'} + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} - engines: {node: '>=6.9.0'} + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -620,514 +472,149 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6': - resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.27.1': - resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.5': - resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.28.4': - resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@braintree/sanitize-url@7.1.1': + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} - engines: {node: '>=6.9.0'} + '@capacitor/android@7.4.4': + resolution: {integrity: sha512-y8knfV1JXNrd6XZZLZireGT+EBCN0lvOo+HZ/s7L8LkrPBu4nY5UZn0Wxz4yOezItEII9rqYJSHsS5fMJG9gdw==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': ^7.4.0 - '@babel/plugin-transform-destructuring@7.28.5': - resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} - engines: {node: '>=6.9.0'} + '@capacitor/app@7.1.0': + resolution: {integrity: sha512-W7m09IWrUjZbo7AKeq+rc/KyucxrJekTBg0l4QCm/yDtCejE3hebxp/W2esU26KKCzMc7H3ClkUw32E9lZkwRA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} - engines: {node: '>=6.9.0'} + '@capacitor/camera@7.0.2': + resolution: {integrity: sha512-1/UbZZ8MSbRTMMvjQHQFJ0cs2ZNURNoyuUex0rAJwECsyHO0I5SRvu7YoMY5qTcRWScBcqT+3QZcJvETtRg7ug==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-duplicate-keys@7.27.1': - resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/cli@7.4.4': + resolution: {integrity: sha512-J7ciBE7GlJ70sr2s8oz1+H4ZdNk4MGG41fsakUlDHWva5UWgFIZYMiEdDvGbYazAYTaxN3lVZpH9zil9FfZj+Q==} + engines: {node: '>=20.0.0'} + hasBin: true - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@capacitor/core@7.4.4': + resolution: {integrity: sha512-xzjxpr+d2zwTpCaN0k+C6wKSZzWFAb9OVEUtmO72ihjr/NEDoLvsGl4WLfjWPcCO2zOy0b2X52tfRWjECFUjtw==} - '@babel/plugin-transform-dynamic-import@7.27.1': - resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} - engines: {node: '>=6.9.0'} + '@capacitor/haptics@7.0.2': + resolution: {integrity: sha512-vqfeEM6s2zMgLjpITCTUIy7P/hadq/Gr5E/RClFgMJPB41Y5FsqOKD+j85/uwh8N2cf/aWaPeXUmjnTzJbEB2g==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} - engines: {node: '>=6.9.0'} + '@capacitor/keyboard@7.0.3': + resolution: {integrity: sha512-BIBKjmky5rOYNhvYhNeDi0MMvjwYZ6YF9JoCYcGKvKY+XLJKtezsEL78XfOlgWZBkbfR8uq3tzktY6PqgoYLKA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-exponentiation-operator@7.28.5': - resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} - engines: {node: '>=6.9.0'} + '@capacitor/push-notifications@7.0.3': + resolution: {integrity: sha512-4qt5dRVBkHzq202NEoj3JC+S+zQCrZ1FJh7sjkICy/i1iEos+VaoB3bie8eWDQ2LTARktB4+k2xkdpu8pcVo/g==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} - engines: {node: '>=6.9.0'} + '@capacitor/share@7.0.2': + resolution: {integrity: sha512-VyNPo/9831xnL17IMDeft5yNdBjoKNb451P95sRcr69hulRDqHc+kndqOVaMXnaA6IyBdWnnFv/n1HUf4cXpGw==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-flow-strip-types@7.27.1': - resolution: {integrity: sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==} - engines: {node: '>=6.9.0'} + '@capacitor/status-bar@7.0.3': + resolution: {integrity: sha512-JyRpVnKwHij9hgPWolF6PK+HT3e2HSPjN11/h2OmKxq8GAdPGARFLv+97eZl0pvuvm0Kka/LpiLb5whXISBg7Q==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@capacitor/core': '>=7.0.0' - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} - '@babel/plugin-transform-logical-assignment-operators@7.28.5': - resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} - '@babel/plugin-transform-member-expression-literals@7.27.1': - resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/autocomplete@6.19.1': + resolution: {integrity: sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw==} - '@babel/plugin-transform-modules-amd@7.27.1': - resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/commands@6.10.0': + resolution: {integrity: sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==} - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} - '@babel/plugin-transform-modules-systemjs@7.28.5': - resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/language@6.11.3': + resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} - '@babel/plugin-transform-modules-umd@7.27.1': - resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/lint@6.9.2': + resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==} - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@codemirror/search@6.5.11': + resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} - '@babel/plugin-transform-new-target@7.27.1': - resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/state@6.5.2': + resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/theme-one-dark@6.1.3': + resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@codemirror/view@6.38.6': + resolution: {integrity: sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==} - '@babel/plugin-transform-object-rest-spread@7.28.4': - resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} - engines: {node: '>=6.9.0'} + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} peerDependencies: - '@babel/core': ^7.0.0-0 + react: '>=16.8.0' - '@babel/plugin-transform-object-super@7.27.1': - resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} - engines: {node: '>=6.9.0'} + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-chaining@7.28.5': - resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-property-literals@7.27.1': - resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-display-name@7.28.0': - resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx@7.27.1': - resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regenerator@7.28.4': - resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-reserved-words@7.27.1': - resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-runtime@7.28.5': - resolution: {integrity: sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typeof-symbol@7.27.1': - resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.28.5': - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-escapes@7.27.1': - resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/preset-env@7.28.5': - resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-flow@7.27.1': - resolution: {integrity: sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-modules@0.1.6-no-external-plugins': - resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} - peerDependencies: - '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - - '@babel/preset-typescript@7.28.5': - resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/register@7.28.3': - resolution: {integrity: sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} - engines: {node: '>=6.9.0'} - - '@braintree/sanitize-url@7.1.1': - resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} - - '@capacitor/android@7.4.4': - resolution: {integrity: sha512-y8knfV1JXNrd6XZZLZireGT+EBCN0lvOo+HZ/s7L8LkrPBu4nY5UZn0Wxz4yOezItEII9rqYJSHsS5fMJG9gdw==} - peerDependencies: - '@capacitor/core': ^7.4.0 - - '@capacitor/app@7.1.0': - resolution: {integrity: sha512-W7m09IWrUjZbo7AKeq+rc/KyucxrJekTBg0l4QCm/yDtCejE3hebxp/W2esU26KKCzMc7H3ClkUw32E9lZkwRA==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@capacitor/camera@7.0.2': - resolution: {integrity: sha512-1/UbZZ8MSbRTMMvjQHQFJ0cs2ZNURNoyuUex0rAJwECsyHO0I5SRvu7YoMY5qTcRWScBcqT+3QZcJvETtRg7ug==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@capacitor/cli@7.4.4': - resolution: {integrity: sha512-J7ciBE7GlJ70sr2s8oz1+H4ZdNk4MGG41fsakUlDHWva5UWgFIZYMiEdDvGbYazAYTaxN3lVZpH9zil9FfZj+Q==} - engines: {node: '>=20.0.0'} - hasBin: true - - '@capacitor/core@7.4.4': - resolution: {integrity: sha512-xzjxpr+d2zwTpCaN0k+C6wKSZzWFAb9OVEUtmO72ihjr/NEDoLvsGl4WLfjWPcCO2zOy0b2X52tfRWjECFUjtw==} - - '@capacitor/haptics@7.0.2': - resolution: {integrity: sha512-vqfeEM6s2zMgLjpITCTUIy7P/hadq/Gr5E/RClFgMJPB41Y5FsqOKD+j85/uwh8N2cf/aWaPeXUmjnTzJbEB2g==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@capacitor/keyboard@7.0.3': - resolution: {integrity: sha512-BIBKjmky5rOYNhvYhNeDi0MMvjwYZ6YF9JoCYcGKvKY+XLJKtezsEL78XfOlgWZBkbfR8uq3tzktY6PqgoYLKA==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@capacitor/push-notifications@7.0.3': - resolution: {integrity: sha512-4qt5dRVBkHzq202NEoj3JC+S+zQCrZ1FJh7sjkICy/i1iEos+VaoB3bie8eWDQ2LTARktB4+k2xkdpu8pcVo/g==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@capacitor/share@7.0.2': - resolution: {integrity: sha512-VyNPo/9831xnL17IMDeft5yNdBjoKNb451P95sRcr69hulRDqHc+kndqOVaMXnaA6IyBdWnnFv/n1HUf4cXpGw==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@capacitor/status-bar@7.0.3': - resolution: {integrity: sha512-JyRpVnKwHij9hgPWolF6PK+HT3e2HSPjN11/h2OmKxq8GAdPGARFLv+97eZl0pvuvm0Kka/LpiLb5whXISBg7Q==} - peerDependencies: - '@capacitor/core': '>=7.0.0' - - '@chevrotain/cst-dts-gen@11.0.3': - resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} - - '@chevrotain/gast@11.0.3': - resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} - - '@chevrotain/regexp-to-ast@11.0.3': - resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} - - '@chevrotain/types@11.0.3': - resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} - - '@chevrotain/utils@11.0.3': - resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} - - '@codemirror/autocomplete@6.19.1': - resolution: {integrity: sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw==} - - '@codemirror/commands@6.10.0': - resolution: {integrity: sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==} - - '@codemirror/lang-json@6.0.2': - resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} - - '@codemirror/language@6.11.3': - resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} - - '@codemirror/lint@6.9.2': - resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==} - - '@codemirror/search@6.5.11': - resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} - - '@codemirror/state@6.5.2': - resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} - - '@codemirror/theme-one-dark@6.1.3': - resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} - - '@codemirror/view@6.38.6': - resolution: {integrity: sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==} - - '@dnd-kit/accessibility@3.1.1': - resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} - peerDependencies: - react: '>=16.8.0' - - '@dnd-kit/core@6.3.1': - resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + react: '>=16.8.0' + react-dom: '>=16.8.0' '@dnd-kit/utilities@3.2.2': resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} @@ -1357,14 +844,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@hapi/hoek@9.3.0': - resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} - - '@hapi/topo@5.1.0': - resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - - '@huggingface/jinja@0.5.2': - resolution: {integrity: sha512-3KxqfOSYtHDsq6HglCH4BDHGXXHMS7ZHUHpxVGswa4l8ycCCExDR2E4nDlTo9LCa6bxp03ywf/mAIVEsO1Ov1w==} + '@huggingface/jinja@0.5.3': + resolution: {integrity: sha512-asqfZ4GQS0hD876Uw4qiUb7Tr/V5Q+JZuo2L+BtdrD4U40QU58nIRq3ZSgAzJgT874VLjhGVacaYfrdpXtEvtA==} engines: {node: '>=18'} '@huggingface/transformers@3.8.0': @@ -1578,6 +1059,14 @@ packages: resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + '@jest/create-cache-key-function@29.7.0': resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1594,9 +1083,9 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/types@26.6.2': - resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} - engines: {node: '>= 10.14.2'} + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} @@ -1761,8 +1250,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.56.1': - resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==} + '@playwright/test@1.57.0': + resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} engines: {node: '>=18'} hasBin: true @@ -2190,98 +1679,61 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@react-native-community/cli-clean@12.3.7': - resolution: {integrity: sha512-BCYW77QqyxfhiMEBOoHyciJRNV6Rhz1RvclReIKnCA9wAwmoJBeu4Mu+AwiECA2bUITX16fvPt3NwDsSd1jwfQ==} - - '@react-native-community/cli-config@12.3.7': - resolution: {integrity: sha512-IU2UhO9yj1rEBNhHWGzIXpPDzha4hizLP/PUOrhR4BUf6RVPUWEp+e1PXNGR0qjIf6esu7OC7t6mLOhH0NUJEw==} + '@react-native/assets-registry@0.82.1': + resolution: {integrity: sha512-B1SRwpntaAcckiatxbjzylvNK562Ayza05gdJCjDQHTiDafa1OABmyB5LHt7qWDOpNkaluD+w11vHF7pBmTpzQ==} + engines: {node: '>= 20.19.4'} - '@react-native-community/cli-debugger-ui@12.3.7': - resolution: {integrity: sha512-UHUFrRdcjWSCdWG9KIp2QjuRIahBQnb9epnQI7JCq6NFbFHYfEI4rI7msjMn+gG8/tSwKTV2PTPuPmZ5wWlE7Q==} + '@react-native/codegen@0.82.1': + resolution: {integrity: sha512-ezXTN70ygVm9l2m0i+pAlct0RntoV4afftWMGUIeAWLgaca9qItQ54uOt32I/9dBJvzBibT33luIR/pBG0dQvg==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' - '@react-native-community/cli-doctor@12.3.7': - resolution: {integrity: sha512-gCamZztRoAyhciuQPqdz4Xe4t3gOdNsaADNd+rva+Rx8W2PoPeNv60i7/et06wlsn6B6Sh0/hMiAftJbiHDFkg==} + '@react-native/community-cli-plugin@0.82.1': + resolution: {integrity: sha512-H/eMdtOy9nEeX7YVeEG1N2vyCoifw3dr9OV8++xfUElNYV7LtSmJ6AqxZUUfxGJRDFPQvaU/8enmJlM/l11VxQ==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': '*' + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true - '@react-native-community/cli-hermes@12.3.7': - resolution: {integrity: sha512-ezzeiSKjRXK2+i1AAe7NhhN9CEHrgtRmTn2MAdBpE++N8fH5EQZgxFcGgGdwGvns2fm9ivyyeVnI5eAYwvM+jg==} + '@react-native/debugger-frontend@0.82.1': + resolution: {integrity: sha512-a2O6M7/OZ2V9rdavOHyCQ+10z54JX8+B+apYKCQ6a9zoEChGTxUMG2YzzJ8zZJVvYf1ByWSNxv9Se0dca1hO9A==} + engines: {node: '>= 20.19.4'} - '@react-native-community/cli-platform-android@12.3.7': - resolution: {integrity: sha512-mOltF3cpjNdJb3WSFwEHc1GH4ibCcnOvQ34OdWyblKy9ijuvG5SjNTlYR/UW/CURaDi3OUKAhxQMTY5d27bzGQ==} + '@react-native/debugger-shell@0.82.1': + resolution: {integrity: sha512-fdRHAeqqPT93bSrxfX+JHPpCXHApfDUdrXMXhoxlPgSzgXQXJDykIViKhtpu0M6slX6xU/+duq+AtP/qWJRpBw==} + engines: {node: '>= 20.19.4'} - '@react-native-community/cli-platform-ios@12.3.7': - resolution: {integrity: sha512-2WnVsMH4ORZIhBm/5nCms1NeeKG4KarNC7PMLmrXWXB/bibDcaNsjrJiqnmCUcpTEvTQTokRfoO7Aj6NM0Cqow==} + '@react-native/dev-middleware@0.82.1': + resolution: {integrity: sha512-wuOIzms/Qg5raBV6Ctf2LmgzEOCqdP3p1AYN4zdhMT110c39TVMbunpBaJxm0Kbt2HQ762MQViF9naxk7SBo4w==} + engines: {node: '>= 20.19.4'} - '@react-native-community/cli-plugin-metro@12.3.7': - resolution: {integrity: sha512-ahEw0Vfnv2Nv/jdZ2QDuGjQ9l2SczO4lXjb3ubu5vEYNLyTw3jYsLMK6iES7YQ/ApQmKdG476HU1O9uZdpaYPg==} + '@react-native/gradle-plugin@0.82.1': + resolution: {integrity: sha512-KkF/2T1NSn6EJ5ALNT/gx0MHlrntFHv8YdooH9OOGl9HQn5NM0ZmQSr86o5utJsGc7ME3R6p3SaQuzlsFDrn8Q==} + engines: {node: '>= 20.19.4'} - '@react-native-community/cli-server-api@12.3.7': - resolution: {integrity: sha512-LYETs3CCjrLn1ZU0kYv44TywiIl5IPFHZGeXhAh2TtgOk4mo3kvXxECDil9CdO3bmDra6qyiG61KHvzr8IrHdg==} + '@react-native/js-polyfills@0.82.1': + resolution: {integrity: sha512-tf70X7pUodslOBdLN37J57JmDPB/yiZcNDzS2m+4bbQzo8fhx3eG9QEBv5n4fmzqfGAgSB4BWRHgDMXmmlDSVA==} + engines: {node: '>= 20.19.4'} - '@react-native-community/cli-tools@12.3.7': - resolution: {integrity: sha512-7NL/1/i+wzd4fBr/FSr3ypR05tiU/Kv9l/M1sL1c6jfcDtWXAL90R161gQkQFK7shIQ8Idp0dQX1rq49tSyfQw==} + '@react-native/normalize-colors@0.82.1': + resolution: {integrity: sha512-CCfTR1uX+Z7zJTdt3DNX9LUXr2zWXsNOyLbwupW2wmRzrxlHRYfmLgTABzRL/cKhh0Ubuwn15o72MQChvCRaHw==} - '@react-native-community/cli-types@12.3.7': - resolution: {integrity: sha512-NFtUMyIrNfi3A5C1cjVKDVvYHvvOF7MnOMwdD8jm2NQKewQJrehKBh1eMuykKdqhWyZmuemD4KKhL8f4FxgG0w==} - - '@react-native-community/cli@12.3.7': - resolution: {integrity: sha512-7+mOhk+3+X3BjSJZZvYrDJynA00gPYTlvT28ZjiLlbuVGfqfNiBKaxuF7rty+gjjpch4iKGvLhIhSN5cuOsdHQ==} - engines: {node: '>=18'} - hasBin: true - - '@react-native/assets-registry@0.73.1': - resolution: {integrity: sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg==} - engines: {node: '>=18'} - - '@react-native/babel-plugin-codegen@0.73.4': - resolution: {integrity: sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==} - engines: {node: '>=18'} - - '@react-native/babel-preset@0.73.21': - resolution: {integrity: sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' - - '@react-native/codegen@0.73.3': - resolution: {integrity: sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==} - engines: {node: '>=18'} - peerDependencies: - '@babel/preset-env': ^7.1.6 - - '@react-native/community-cli-plugin@0.73.18': - resolution: {integrity: sha512-RN8piDh/eF+QT6YYmrj3Zd9uiaDsRY/kMT0FYR42j8/M/boE4hs4Xn0u91XzT8CAkU9q/ilyo3wJsXIJo2teww==} - engines: {node: '>=18'} - - '@react-native/debugger-frontend@0.73.3': - resolution: {integrity: sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw==} - engines: {node: '>=18'} - - '@react-native/dev-middleware@0.73.8': - resolution: {integrity: sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==} - engines: {node: '>=18'} - - '@react-native/gradle-plugin@0.73.5': - resolution: {integrity: sha512-Orrn8J/kqzEuXudl96XcZk84ZcdIpn1ojjwGSuaSQSXNcCYbOXyt0RwtW5kjCqjgSzGnOMsJNZc5FDXHVq/WzA==} - engines: {node: '>=18'} - - '@react-native/js-polyfills@0.73.1': - resolution: {integrity: sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g==} - engines: {node: '>=18'} - - '@react-native/metro-babel-transformer@0.73.15': - resolution: {integrity: sha512-LlkSGaXCz+xdxc9819plmpsl4P4gZndoFtpjN3GMBIu6f7TBV0GVbyJAU4GE8fuAWPVSVL5ArOcdkWKSbI1klw==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' - - '@react-native/normalize-colors@0.73.2': - resolution: {integrity: sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w==} - - '@react-native/virtualized-lists@0.73.4': - resolution: {integrity: sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==} - engines: {node: '>=18'} - peerDependencies: - react-native: '*' + '@react-native/virtualized-lists@0.82.1': + resolution: {integrity: sha512-f5zpJg9gzh7JtCbsIwV+4kP3eI0QBuA93JGmwFRd4onQ3DnCjV2J5pYqdWtM95sjSKK1dyik59Gj01lLeKqs1Q==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@types/react': ^19.1.1 + react: '*' + react-native: '*' + peerDependenciesMeta: + '@types/react': + optional: true '@react-spring/animated@10.0.3': resolution: {integrity: sha512-7MrxADV3vaUADn2V9iYhaIL6iOWRx9nCJjYrsk2AHD2kwPr6fg7Pt0v+deX5RnCDmCKNnD6W5fasiyM8D+wzJQ==} @@ -2338,17 +1790,17 @@ packages: react-zdog: '>=1.0' zdog: '>=1.0' - '@react-three/fiber@8.18.0': - resolution: {integrity: sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==} + '@react-three/fiber@9.4.0': + resolution: {integrity: sha512-k4iu1R6e5D54918V4sqmISUkI5OgTw3v7/sDRKEC632Wd5g2WBtUS5gyG63X0GJO/HZUj1tsjSXfyzwrUHZl1g==} peerDependencies: expo: '>=43.0' expo-asset: '>=8.4' expo-file-system: '>=11.0' expo-gl: '>=11.0' - react: '>=18 <19' - react-dom: '>=18 <19' - react-native: '>=0.64' - three: '>=0.133' + react: ^19.0.0 + react-dom: ^19.0.0 + react-native: '>=0.78' + three: '>=0.156' peerDependenciesMeta: expo: optional: true @@ -2593,15 +2045,6 @@ packages: resolution: {integrity: sha512-fMR2d+EHwbzBa0S1fp45SNUTProxmyFBp+DeBWWQOSP9IU6AH6ea2rqrpMAnp/skkcdW4z4LSRrOEpMZ5rWXLw==} engines: {node: '>= 14'} - '@sideway/address@4.1.5': - resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} - - '@sideway/formula@3.0.1': - resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} - - '@sideway/pinpoint@2.0.0': - resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -2755,6 +2198,9 @@ packages: '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -2770,15 +2216,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/lodash@4.17.20': - resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==} - '@types/node@22.19.1': resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} - '@types/node@24.10.0': - resolution: {integrity: sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==} - '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} @@ -2787,14 +2227,16 @@ packages: peerDependencies: '@types/react': ^18.0.0 - '@types/react-reconciler@0.26.7': - resolution: {integrity: sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==} - '@types/react-reconciler@0.28.9': resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==} peerDependencies: '@types/react': '*' + '@types/react-reconciler@0.32.3': + resolution: {integrity: sha512-cMi5ZrLG7UtbL7LTK6hq9w/EZIRk4Mf1Z5qHoI+qBh7/WkYkFXQ7gOto2yfUvPzF5ERMAhaXS5eTQ2SAnHjLzA==} + peerDependencies: + '@types/react': '*' + '@types/react@18.3.26': resolution: {integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==} @@ -2816,11 +2258,8 @@ packages: '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@15.0.19': - resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} - - '@types/yargs@17.0.34': - resolution: {integrity: sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==} + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} '@typescript-eslint/eslint-plugin@7.18.0': resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} @@ -3020,6 +2459,10 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ai@4.3.19: resolution: {integrity: sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==} engines: {node: '>=18'} @@ -3052,13 +2495,6 @@ packages: anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} - ansi-fragments@0.2.1: - resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} - - ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3067,10 +2503,6 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -3090,9 +2522,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - appdirsjs@1.2.7: - resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -3113,14 +2542,6 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - ast-types@0.15.2: - resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} - engines: {node: '>=4'} - - astral-regex@1.0.0: - resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} - engines: {node: '>=4'} - astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -3139,28 +2560,33 @@ packages: peerDependencies: postcss: ^8.1.0 - babel-core@7.0.0-bridge.0: - resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.8.0 - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + babel-plugin-syntax-hermes-parser@0.32.0: + resolution: {integrity: sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg==} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/core': ^7.0.0 || ^8.0.0-0 - babel-plugin-transform-flow-enums@0.0.2: - resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -3180,9 +2606,6 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -3215,28 +2638,9 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - caller-callsite@2.0.0: - resolution: {integrity: sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==} - engines: {node: '>=4'} - - caller-path@2.0.0: - resolution: {integrity: sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==} - engines: {node: '>=4'} - - callsites@2.0.0: - resolution: {integrity: sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==} - engines: {node: '>=4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -3293,8 +2697,8 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - chromium-edge-launcher@1.0.0: - resolution: {integrity: sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==} + chromium-edge-launcher@0.2.0: + resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -3306,34 +2710,15 @@ packages: class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - click-to-react-component@1.1.3: resolution: {integrity: sha512-tHXsXuvHBKCjjrevtGUzanngE+8HtZLt57precpAO677vjCO9Vxr3Lc3VqgNGGd2JpVybL0QHhnsrijZ2T5cng==} peerDependencies: react: '>=16.8.0' - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - clone-deep@4.0.1: - resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} - engines: {node: '>=6'} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -3341,25 +2726,13 @@ packages: codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - - command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -3379,21 +2752,6 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.1: - resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} - engines: {node: '>= 0.8.0'} - compute-gcd@1.2.1: resolution: {integrity: sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==} @@ -3421,25 +2779,15 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - core-js-compat@3.46.0: - resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} - core-js@3.46.0: resolution: {integrity: sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==} - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} cose-base@2.2.0: resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} - cosmiconfig@5.2.1: - resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} - engines: {node: '>=4'} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -3640,20 +2988,9 @@ packages: supports-color: optional: true - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -3669,17 +3006,10 @@ packages: delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} - denodeify@1.2.1: - resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - deprecated-react-native-prop-types@5.0.0: - resolution: {integrity: sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==} - engines: {node: '>=18'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -3789,21 +3119,9 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - envinfo@7.20.0: - resolution: {integrity: sha512-+zUomDcLXsVkQ37vUqWBvQwLaLlj8eZPSi61llaEFAVBY5mhcXdaSw1pSJVl4yTYD5g/gEfpNl28YYk4IPvrrg==} - engines: {node: '>=4'} - hasBin: true - - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - errorhandler@1.5.1: - resolution: {integrity: sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==} - engines: {node: '>= 0.8'} - es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -3944,10 +3262,6 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} @@ -3976,13 +3290,14 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@4.5.3: - resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} - hasBin: true - fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -4007,14 +3322,6 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} - find-cache-dir@2.1.0: - resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} - engines: {node: '>=6'} - - find-up@3.0.0: - resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} - engines: {node: '>=6'} - find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -4036,10 +3343,6 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - flow-parser@0.206.0: - resolution: {integrity: sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==} - engines: {node: '>=0.4.0'} - foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -4079,10 +3382,6 @@ packages: resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} engines: {node: '>=14.14'} - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -4119,9 +3418,9 @@ packages: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -4138,10 +3437,9 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@11.0.3: - resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + glob@13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} engines: {node: 20 || >=22} - hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -4198,21 +3496,14 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hermes-estree@0.15.0: - resolution: {integrity: sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==} - - hermes-estree@0.23.1: - resolution: {integrity: sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==} - - hermes-parser@0.15.0: - resolution: {integrity: sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==} + hermes-compiler@0.0.0: + resolution: {integrity: sha512-boVFutx6ME/Km2mB6vvsQcdnazEYYI/jV1pomx1wcFUG/EVqTkr5CU0CW9bKipOA/8Hyu3NYwW3THg2Q1kNCfA==} - hermes-parser@0.23.1: - resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==} + hermes-estree@0.32.0: + resolution: {integrity: sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==} - hermes-profile-transformer@0.0.6: - resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} - engines: {node: '>=8'} + hermes-parser@0.32.0: + resolution: {integrity: sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==} highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} @@ -4235,9 +3526,9 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} i18next-browser-languagedetector@8.2.0: resolution: {integrity: sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==} @@ -4266,10 +3557,6 @@ packages: engines: {node: '>=16.x'} hasBin: true - import-fresh@2.0.0: - resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} - engines: {node: '>=4'} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -4299,9 +3586,6 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -4310,10 +3594,6 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-directory@0.3.1: - resolution: {integrity: sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==} - engines: {node: '>=0.10.0'} - is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -4323,10 +3603,6 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -4335,10 +3611,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -4347,48 +3619,29 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-wsl@1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} - is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} - its-fine@1.2.5: - resolution: {integrity: sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==} + its-fine@2.0.0: + resolution: {integrity: sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==} peerDependencies: - react: '>=18.0' + react: ^19.0.0 jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jackspeak@4.1.1: - resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} - engines: {node: 20 || >=22} - jest-environment-node@29.7.0: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4397,6 +3650,10 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4405,6 +3662,10 @@ packages: resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4429,14 +3690,11 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - joi@17.13.3: - resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true js-yaml@4.1.0: @@ -4447,18 +3705,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsc-android@250231.0.0: - resolution: {integrity: sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==} - jsc-safe-url@0.2.4: resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} - jscodeshift@0.14.0: - resolution: {integrity: sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==} - hasBin: true - peerDependencies: - '@babel/preset-env': ^7.1.6 - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -4467,9 +3716,6 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -4505,9 +3751,6 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} @@ -4525,10 +3768,6 @@ packages: khroma@2.1.0: resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -4548,8 +3787,8 @@ packages: kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - konva@10.0.8: - resolution: {integrity: sha512-kQqErBIj2mR/srYDheRD2hq5v0gkwqoJZvbPz3DhCcyRNJfMEnd/AzLhWz2f567BB9vtL2p2EqKwI6n+MyM9Hw==} + konva@10.0.12: + resolution: {integrity: sha512-DHmkeG5FbW6tLCkbMQTi1ihWycfzljrn0V7umUUuewxx7aoINcI71ksgBX9fTPNXhlsK4/JoMgKwI/iCde+BRw==} langium@3.0.0: resolution: {integrity: sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==} @@ -4587,10 +3826,6 @@ packages: resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} engines: {node: '>=14'} - locate-path@3.0.0: - resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} - engines: {node: '>=6'} - locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -4602,9 +3837,6 @@ packages: lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -4614,14 +3846,6 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - logkitty@0.7.1: - resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} - hasBin: true - long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} @@ -4651,10 +3875,6 @@ packages: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} - make-dir@2.1.0: - resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} - engines: {node: '>=6'} - makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -4692,62 +3912,62 @@ packages: mermaid@11.4.1: resolution: {integrity: sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==} - metro-babel-transformer@0.80.12: - resolution: {integrity: sha512-YZziRs0MgA3pzCkkvOoQRXjIoVjvrpi/yRlJnObyIvMP6lFdtyG4nUGIwGY9VXnBvxmXD6mPY2e+NSw6JAyiRg==} - engines: {node: '>=18'} + metro-babel-transformer@0.83.3: + resolution: {integrity: sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==} + engines: {node: '>=20.19.4'} - metro-cache-key@0.80.12: - resolution: {integrity: sha512-o4BspKnugg/pE45ei0LGHVuBJXwRgruW7oSFAeSZvBKA/sGr0UhOGY3uycOgWInnS3v5yTTfiBA9lHlNRhsvGA==} - engines: {node: '>=18'} + metro-cache-key@0.83.3: + resolution: {integrity: sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==} + engines: {node: '>=20.19.4'} - metro-cache@0.80.12: - resolution: {integrity: sha512-p5kNHh2KJ0pbQI/H7ZBPCEwkyNcSz7OUkslzsiIWBMPQGFJ/xArMwkV7I+GJcWh+b4m6zbLxE5fk6fqbVK1xGA==} - engines: {node: '>=18'} + metro-cache@0.83.3: + resolution: {integrity: sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==} + engines: {node: '>=20.19.4'} - metro-config@0.80.12: - resolution: {integrity: sha512-4rwOWwrhm62LjB12ytiuR5NgK1ZBNr24/He8mqCsC+HXZ+ATbrewLNztzbAZHtFsrxP4D4GLTGgh96pCpYLSAQ==} - engines: {node: '>=18'} + metro-config@0.83.3: + resolution: {integrity: sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==} + engines: {node: '>=20.19.4'} - metro-core@0.80.12: - resolution: {integrity: sha512-QqdJ/yAK+IpPs2HU/h5v2pKEdANBagSsc6DRSjnwSyJsCoHlmyJKCaCJ7KhWGx+N4OHxh37hoA8fc2CuZbx0Fw==} - engines: {node: '>=18'} + metro-core@0.83.3: + resolution: {integrity: sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==} + engines: {node: '>=20.19.4'} - metro-file-map@0.80.12: - resolution: {integrity: sha512-sYdemWSlk66bWzW2wp79kcPMzwuG32x1ZF3otI0QZTmrnTaaTiGyhE66P1z6KR4n2Eu5QXiABa6EWbAQv0r8bw==} - engines: {node: '>=18'} + metro-file-map@0.83.3: + resolution: {integrity: sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==} + engines: {node: '>=20.19.4'} - metro-minify-terser@0.80.12: - resolution: {integrity: sha512-muWzUw3y5k+9083ZoX9VaJLWEV2Jcgi+Oan0Mmb/fBNMPqP9xVDuy4pOMn/HOiGndgfh/MK7s4bsjkyLJKMnXQ==} - engines: {node: '>=18'} + metro-minify-terser@0.83.3: + resolution: {integrity: sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==} + engines: {node: '>=20.19.4'} - metro-resolver@0.80.12: - resolution: {integrity: sha512-PR24gYRZnYHM3xT9pg6BdbrGbM/Cu1TcyIFBVlAk7qDAuHkUNQ1nMzWumWs+kwSvtd9eZGzHoucGJpTUEeLZAw==} - engines: {node: '>=18'} + metro-resolver@0.83.3: + resolution: {integrity: sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==} + engines: {node: '>=20.19.4'} - metro-runtime@0.80.12: - resolution: {integrity: sha512-LIx7+92p5rpI0i6iB4S4GBvvLxStNt6fF0oPMaUd1Weku7jZdfkCZzmrtDD9CSQ6EPb0T9NUZoyXIxlBa3wOCw==} - engines: {node: '>=18'} + metro-runtime@0.83.3: + resolution: {integrity: sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==} + engines: {node: '>=20.19.4'} - metro-source-map@0.80.12: - resolution: {integrity: sha512-o+AXmE7hpvM8r8MKsx7TI21/eerYYy2DCDkWfoBkv+jNkl61khvDHlQn0cXZa6lrcNZiZkl9oHSMcwLLIrFmpw==} - engines: {node: '>=18'} + metro-source-map@0.83.3: + resolution: {integrity: sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==} + engines: {node: '>=20.19.4'} - metro-symbolicate@0.80.12: - resolution: {integrity: sha512-/dIpNdHksXkGHZXARZpL7doUzHqSNxgQ8+kQGxwpJuHnDhGkENxB5PS2QBaTDdEcmyTMjS53CN1rl9n1gR6fmw==} - engines: {node: '>=18'} + metro-symbolicate@0.83.3: + resolution: {integrity: sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==} + engines: {node: '>=20.19.4'} hasBin: true - metro-transform-plugins@0.80.12: - resolution: {integrity: sha512-WQWp00AcZvXuQdbjQbx1LzFR31IInlkCDYJNRs6gtEtAyhwpMMlL2KcHmdY+wjDO9RPcliZ+Xl1riOuBecVlPA==} - engines: {node: '>=18'} + metro-transform-plugins@0.83.3: + resolution: {integrity: sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==} + engines: {node: '>=20.19.4'} - metro-transform-worker@0.80.12: - resolution: {integrity: sha512-KAPFN1y3eVqEbKLx1I8WOarHPqDMUa8WelWxaJCNKO/yHCP26zELeqTJvhsQup+8uwB6EYi/sp0b6TGoh6lOEA==} - engines: {node: '>=18'} + metro-transform-worker@0.83.3: + resolution: {integrity: sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==} + engines: {node: '>=20.19.4'} - metro@0.80.12: - resolution: {integrity: sha512-1UsH5FzJd9quUsD1qY+zUG4JY3jo3YEMxbMYH9jT6NK3j4iORhlwTK8fYTfAUBhDKjgLfKjAh7aoazNE23oIRA==} - engines: {node: '>=18'} + metro@0.83.3: + resolution: {integrity: sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==} + engines: {node: '>=20.19.4'} hasBin: true micromatch@4.0.8: @@ -4767,15 +3987,6 @@ packages: engines: {node: '>=4'} hasBin: true - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - minimatch@10.1.1: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} @@ -4818,10 +4029,6 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -4867,24 +4074,9 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nocache@3.0.4: - resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} - engines: {node: '>=12.0.0'} - - node-abort-controller@3.1.1: - resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - - node-dir@0.1.17: - resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} - engines: {node: '>= 0.10.5'} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -4900,10 +4092,6 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - node-stream-zip@1.15.0: - resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} - engines: {node: '>=0.12.0'} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -4912,16 +4100,12 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - ob1@0.80.12: - resolution: {integrity: sha512-VMArClVT6LkhUGpnuEoBuyjG9rzUyEzg4PDkav6wK1cLhOK02gPCYFxoiB4mqVnrMhDpIzJcrGNAMVi9P+hXrw==} - engines: {node: '>=18'} + ob1@0.83.3: + resolution: {integrity: sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==} + engines: {node: '>=20.19.4'} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -4943,17 +4127,9 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - onnxruntime-common@1.21.0: resolution: {integrity: sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==} @@ -4967,10 +4143,6 @@ packages: onnxruntime-web@1.22.0-dev.20250409-89f8206ba4: resolution: {integrity: sha512-0uS76OPgH0hWCPrFKlL8kYVV7ckM7t/36HfbgoFw6Nd0CZVVbQC4PkrR8mBX8LtNUFZO25IQBqV2Hx2ho3FlbQ==} - open@6.4.0: - resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} - engines: {node: '>=8'} - open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -4983,10 +4155,6 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - oxc-resolver@11.14.0: resolution: {integrity: sha512-i4wNrqhOd+4YdHJfHglHtFiqqSxXuzFA+RUqmmWN1aMD3r1HqUSrIhw17tSO4jwKfhLs9uw1wzFPmvMsWacStg==} @@ -4998,10 +4166,6 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@3.0.0: - resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} - engines: {node: '>=6'} - p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -5017,17 +4181,13 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@1.5.0: - resolution: {integrity: sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-json@4.0.0: - resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} - engines: {node: '>=4'} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -5035,10 +4195,6 @@ packages: path-data-parser@0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} - path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -5087,18 +4243,10 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - pkg-dir@3.0.0: - resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} - engines: {node: '>=6'} - pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -5108,13 +4256,13 @@ packages: platform@1.3.6: resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} - playwright-core@1.56.1: - resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} + playwright-core@1.57.0: + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} engines: {node: '>=18'} hasBin: true - playwright@1.56.1: - resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} + playwright@1.57.0: + resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} engines: {node: '>=18'} hasBin: true @@ -5201,17 +4349,10 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-format@26.6.2: - resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} - engines: {node: '>= 10'} - pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -5253,8 +4394,8 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - react-devtools-core@4.28.5: - resolution: {integrity: sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==} + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} @@ -5286,40 +4427,41 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-konva@18.2.14: - resolution: {integrity: sha512-lBDe/5fTgquMdg1AHI0B16YZdAOvEhWMBWuo12ioyY0icdxcz9Cf12j86fsCJCHdnvjUOlZeC0f5q+siyHbD4Q==} + react-konva@19.2.1: + resolution: {integrity: sha512-sqZWCzQGpdMrU5aeunR0oxUY8UeCPbU8gnAYxMtAn6BT4coeSpiATKOctsoxRu6F56TAcF+s0c6Lul9ansNqQA==} peerDependencies: konva: ^8.0.1 || ^7.2.5 || ^9.0.0 || ^10.0.0 - react: '>=18.0.0' - react-dom: '>=18.0.0' + react: ^19.2.0 + react-dom: ^19.2.0 react-merge-refs@1.1.0: resolution: {integrity: sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==} - react-native@0.73.11: - resolution: {integrity: sha512-yvQIX+ZXOHMFnhmwZ1fBpRI/53k+iLN8DxVf24Fx4ABU63RGAYfyCZC0/3W+5OUVx4KSIZUv4Tv+/NGIieBOwg==} - engines: {node: '>=18'} + react-native@0.82.1: + resolution: {integrity: sha512-tFAqcU7Z4g49xf/KnyCEzI4nRTu1Opcx05Ov2helr8ZTg1z7AJR/3sr2rZ+AAVlAs2IXk+B0WOxXGmdD3+4czA==} + engines: {node: '>= 20.19.4'} hasBin: true peerDependencies: - react: 18.2.0 + '@types/react': ^19.1.1 + react: ^19.1.1 + peerDependenciesMeta: + '@types/react': + optional: true - react-reconciler@0.27.0: - resolution: {integrity: sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==} + react-reconciler@0.31.0: + resolution: {integrity: sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: ^18.0.0 + react: ^19.0.0 - react-reconciler@0.29.2: - resolution: {integrity: sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==} + react-reconciler@0.33.0: + resolution: {integrity: sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA==} engines: {node: '>=0.10.0'} peerDependencies: - react: ^18.3.1 + react: ^19.2.0 react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} @@ -5368,11 +4510,6 @@ packages: peerDependencies: react: '>=16.8' - react-shallow-renderer@16.15.0: - resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-spring@10.0.3: resolution: {integrity: sha512-opangIUqCLmkf7+AJZAlM4fLlvzdzWOG/yqAzylKjUoe97Tsjgouz1PsDLu6C9uckvcaMfb4wS/VXiU6dULz5A==} peerDependencies: @@ -5422,9 +4559,6 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -5433,34 +4567,9 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readline@1.3.0: - resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} - - recast@0.21.5: - resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==} - engines: {node: '>= 4'} - - regenerate-unicode-properties@10.2.2: - resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} - engines: {node: '>=4'} - - regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - regexpu-core@6.4.0: - resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} - engines: {node: '>=4'} - - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - - regjsparser@0.13.0: - resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} - hasBin: true - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -5469,9 +4578,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requireindex@1.1.0: resolution: {integrity: sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==} engines: {node: '>=0.10.5'} @@ -5479,23 +4585,19 @@ packages: resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} - resolve-from@3.0.0: - resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} - engines: {node: '>=4'} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -5503,18 +4605,13 @@ packages: rfc6902@5.1.2: resolution: {integrity: sha512-zxcb+PWlE8PwX0tiKE6zP97THQ8/lHmeiwucRrJ3YFupWEmp25RmFSlB1dNTqjkovwqG4iq+u1gzJMBS3um8mA==} - rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@6.1.0: - resolution: {integrity: sha512-DxdlA1bdNzkZK7JiNWH+BAx1x4tEJWoTofIopFo6qWUU94jYrFZ0ubY05TqH3nWPJ1nKa1JWVFDINZ3fnrle/A==} + rimraf@6.1.2: + resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} engines: {node: 20 || >=22} hasBin: true @@ -5542,9 +4639,6 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -5557,14 +4651,17 @@ packages: sax@1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} - scheduler@0.21.0: - resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} - scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - scheduler@0.24.0-canary-efb381bbf-20230505: - resolution: {integrity: sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==} + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} @@ -5576,10 +4673,6 @@ packages: semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -5608,16 +4701,9 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shallow-clone@3.0.1: - resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} - engines: {node: '>=8'} - sharp@0.34.5: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -5652,10 +4738,6 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - slice-ansi@2.1.0: - resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} - engines: {node: '>=6'} - slice-ansi@4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} @@ -5679,10 +4761,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} @@ -5723,16 +4801,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@5.2.0: - resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} - engines: {node: '>=6'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -5741,10 +4812,6 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -5753,9 +4820,6 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} - strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} @@ -5767,10 +4831,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true - sudo-prompt@9.2.1: - resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -5825,14 +4885,6 @@ packages: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} - temp-dir@2.0.0: - resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} - engines: {node: '>=8'} - - temp@0.8.4: - resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} - engines: {node: '>=6.0.0'} - terser-webpack-plugin@5.3.14: resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} engines: {node: '>= 10.13.0'} @@ -5854,6 +4906,10 @@ packages: engines: {node: '>=10'} hasBin: true + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -5864,8 +4920,8 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - three@0.181.1: - resolution: {integrity: sha512-bz9xZUQMw3pJbjKy7roiwXWgAp+oVUa+4k5o0oBAQ+IFJuru1xzvtk63h6k72XZanXS/SgoEhV6927Vgazyq2w==} + three@0.181.2: + resolution: {integrity: sha512-k/CjiZ80bYss6Qs7/ex1TBlPD11whT9oKfT8oTGiHa34W4JRd1NiH/Tr1DbHWQ2/vMUypxksLnF2CfmlmM5XFQ==} throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} @@ -5874,9 +4930,6 @@ packages: resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} engines: {node: '>=18'} - through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} @@ -5949,29 +5002,6 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} - engines: {node: '>=4'} - - unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - - unicode-match-property-value-ecmascript@2.2.1: - resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} - engines: {node: '>=4'} - - unicode-property-aliases-ecmascript@2.2.0: - resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} - engines: {node: '>=4'} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -6066,10 +5096,6 @@ packages: validate.io-number@1.0.3: resolution: {integrity: sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - vite@5.4.21: resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} engines: {node: ^18.0.0 || >=20.0.0} @@ -6142,9 +5168,6 @@ packages: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} @@ -6174,9 +5197,6 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -6186,10 +5206,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -6201,8 +5217,9 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@2.4.3: - resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} ws@6.2.3: resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} @@ -6239,13 +5256,6 @@ packages: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -6265,18 +5275,10 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -6288,911 +5290,255 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zdog@1.1.3: - resolution: {integrity: sha512-raRj6r0gPzopFm5XWBJZr/NuV4EEnT4iE+U3dp5FV5pCb588Gmm3zLIp/j9yqqcMiHH8VNQlerLTgOqL7krh6w==} - - zod-to-json-schema@3.25.0: - resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} - peerDependencies: - zod: ^3.25 || ^4 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - - zustand@3.7.2: - resolution: {integrity: sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==} - engines: {node: '>=12.7.0'} - peerDependencies: - react: '>=16.8' - peerDependenciesMeta: - react: - optional: true - - zustand@4.5.7: - resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} - engines: {node: '>=12.7.0'} - peerDependencies: - '@types/react': '>=16.8' - immer: '>=9.0.6' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - -snapshots: - - '@ai-sdk/provider-utils@2.2.8(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 1.1.3 - nanoid: 3.3.11 - secure-json-parse: 2.7.0 - zod: 3.25.76 - - '@ai-sdk/provider@1.1.3': - dependencies: - json-schema: 0.4.0 - - '@ai-sdk/react@1.2.12(react@18.3.1)(zod@3.25.76)': - dependencies: - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) - react: 18.3.1 - swr: 2.3.6(react@18.3.1) - throttleit: 2.1.0 - optionalDependencies: - zod: 3.25.76 - - '@ai-sdk/ui-utils@1.2.11(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) - zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) - - '@alloc/quick-lru@5.2.0': {} - - '@antfu/install-pkg@1.1.0': - dependencies: - package-manager-detector: 1.5.0 - tinyexec: 1.0.2 - - '@antfu/utils@8.1.1': {} - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.5': {} - - '@babel/core@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.27.0 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.4.0 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.3 - lodash.debounce: 4.0.8 - resolve: 1.22.11 - transitivePeerDependencies: - - supports-color - - '@babel/helper-environment-visitor@7.24.7': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.28.5': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helper-wrap-function@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - - '@babel/parser@7.28.5': - dependencies: - '@babel/types': 7.28.5 - - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-export-default-from@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.5) - - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.5) - - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.28.5)': - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.5) - - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-export-default-from@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-flow@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 - - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + zdog@1.1.3: + resolution: {integrity: sha512-raRj6r0gPzopFm5XWBJZr/NuV4EEnT4iE+U3dp5FV5pCb588Gmm3zLIp/j9yqqcMiHH8VNQlerLTgOqL7krh6w==} - '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.28.5) + zod-to-json-schema@3.25.0: + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} + peerDependencies: + zod: ^3.25 || ^4 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + zustand@4.5.7: + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true - '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 +snapshots: - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': + '@ai-sdk/provider-utils@2.2.8(zod@3.25.76)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@ai-sdk/provider': 1.1.3 + nanoid: 3.3.11 + secure-json-parse: 2.7.0 + zod: 3.25.76 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': + '@ai-sdk/provider@1.1.3': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + json-schema: 0.4.0 - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + '@ai-sdk/react@1.2.12(react@18.3.1)(zod@3.25.76)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) + react: 18.3.1 + swr: 2.3.6(react@18.3.1) + throttleit: 2.1.0 + optionalDependencies: + zod: 3.25.76 - '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': + '@ai-sdk/ui-utils@1.2.11(zod@3.25.76)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.25.0(zod@3.25.76) - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@alloc/quick-lru@5.2.0': {} - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@antfu/install-pkg@1.1.0': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@antfu/utils@8.1.1': {} - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': + '@babel/code-frame@7.27.1': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data@7.28.5': {} - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': + '@babel/core@7.28.5': dependencies: - '@babel/core': 7.28.5 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': + '@babel/generator@7.28.5': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 - '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.27.0 + lru-cache: 5.1.1 + semver: 6.3.1 - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-globals@7.28.0': {} - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils@7.27.1': {} - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-string-parser@7.27.1': {} - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option@7.27.1': {} - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/helpers@7.28.4': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/template': 7.27.2 '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': + '@babel/parser@7.28.5': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.5 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-runtime@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/preset-env@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/compat-data': 7.28.5 '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.46.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/preset-flow@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.28.5) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.5 - esutils: 2.0.3 - '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/register@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - clone-deep: 4.0.1 - find-cache-dir: 2.1.0 - make-dir: 2.1.0 - pirates: 4.0.7 - source-map-support: 0.5.21 '@babel/runtime@7.28.4': {} @@ -7247,7 +5593,7 @@ snapshots: open: 8.4.2 plist: 3.1.0 prompts: 2.4.2 - rimraf: 6.1.0 + rimraf: 6.1.2 semver: 7.7.3 tar: 6.2.1 tslib: 2.8.1 @@ -7569,17 +5915,11 @@ snapshots: reactivity-store: 0.3.12(react@18.3.1) use-sync-external-store: 1.6.0(react@18.3.1) - '@hapi/hoek@9.3.0': {} - - '@hapi/topo@5.1.0': - dependencies: - '@hapi/hoek': 9.3.0 - - '@huggingface/jinja@0.5.2': {} + '@huggingface/jinja@0.5.3': {} '@huggingface/transformers@3.8.0': dependencies: - '@huggingface/jinja': 0.5.2 + '@huggingface/jinja': 0.5.3 onnxruntime-node: 1.21.0 onnxruntime-web: 1.22.0-dev.20250409-89f8206ba4 sharp: 0.34.5 @@ -7804,6 +6144,16 @@ snapshots: '@isaacs/ttlcache@1.4.1': {} + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + '@jest/create-cache-key-function@29.7.0': dependencies: '@jest/types': 29.6.3 @@ -7828,13 +6178,25 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@jest/types@26.6.2': + '@jest/transform@29.7.0': dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 22.19.1 - '@types/yargs': 15.0.19 + '@babel/core': 7.28.5 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color '@jest/types@29.6.3': dependencies: @@ -7842,7 +6204,7 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 22.19.1 - '@types/yargs': 17.0.34 + '@types/yargs': 17.0.35 chalk: 4.1.2 '@jridgewell/gen-mapping@0.3.13': @@ -7976,9 +6338,9 @@ snapshots: '@pkgr/core@0.2.9': {} - '@playwright/test@1.56.1': + '@playwright/test@1.57.0': dependencies: - playwright: 1.56.1 + playwright: 1.57.0 '@posthog/core@1.5.2': dependencies: @@ -8383,280 +6745,72 @@ snapshots: '@radix-ui/rect@1.1.1': {} - '@react-native-community/cli-clean@12.3.7': - dependencies: - '@react-native-community/cli-tools': 12.3.7 - chalk: 4.1.2 - execa: 5.1.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-config@12.3.7': - dependencies: - '@react-native-community/cli-tools': 12.3.7 - chalk: 4.1.2 - cosmiconfig: 5.2.1 - deepmerge: 4.3.1 - glob: 7.2.3 - joi: 17.13.3 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-debugger-ui@12.3.7': - dependencies: - serve-static: 1.16.2 - transitivePeerDependencies: - - supports-color - - '@react-native-community/cli-doctor@12.3.7': - dependencies: - '@react-native-community/cli-config': 12.3.7 - '@react-native-community/cli-platform-android': 12.3.7 - '@react-native-community/cli-platform-ios': 12.3.7 - '@react-native-community/cli-tools': 12.3.7 - chalk: 4.1.2 - command-exists: 1.2.9 - deepmerge: 4.3.1 - envinfo: 7.20.0 - execa: 5.1.1 - hermes-profile-transformer: 0.0.6 - node-stream-zip: 1.15.0 - ora: 5.4.1 - semver: 7.7.3 - strip-ansi: 5.2.0 - wcwidth: 1.0.1 - yaml: 2.8.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-hermes@12.3.7': - dependencies: - '@react-native-community/cli-platform-android': 12.3.7 - '@react-native-community/cli-tools': 12.3.7 - chalk: 4.1.2 - hermes-profile-transformer: 0.0.6 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-platform-android@12.3.7': - dependencies: - '@react-native-community/cli-tools': 12.3.7 - chalk: 4.1.2 - execa: 5.1.1 - fast-xml-parser: 4.5.3 - glob: 7.2.3 - logkitty: 0.7.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-platform-ios@12.3.7': - dependencies: - '@react-native-community/cli-tools': 12.3.7 - chalk: 4.1.2 - execa: 5.1.1 - fast-xml-parser: 4.5.3 - glob: 7.2.3 - ora: 5.4.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-plugin-metro@12.3.7': {} - - '@react-native-community/cli-server-api@12.3.7': - dependencies: - '@react-native-community/cli-debugger-ui': 12.3.7 - '@react-native-community/cli-tools': 12.3.7 - compression: 1.8.1 - connect: 3.7.0 - errorhandler: 1.5.1 - nocache: 3.0.4 - pretty-format: 26.6.2 - serve-static: 1.16.2 - ws: 7.5.10 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - - '@react-native-community/cli-tools@12.3.7': - dependencies: - appdirsjs: 1.2.7 - chalk: 4.1.2 - find-up: 5.0.0 - mime: 2.6.0 - node-fetch: 2.7.0 - open: 6.4.0 - ora: 5.4.1 - semver: 7.7.3 - shell-quote: 1.8.3 - sudo-prompt: 9.2.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-types@12.3.7': - dependencies: - joi: 17.13.3 - - '@react-native-community/cli@12.3.7': - dependencies: - '@react-native-community/cli-clean': 12.3.7 - '@react-native-community/cli-config': 12.3.7 - '@react-native-community/cli-debugger-ui': 12.3.7 - '@react-native-community/cli-doctor': 12.3.7 - '@react-native-community/cli-hermes': 12.3.7 - '@react-native-community/cli-plugin-metro': 12.3.7 - '@react-native-community/cli-server-api': 12.3.7 - '@react-native-community/cli-tools': 12.3.7 - '@react-native-community/cli-types': 12.3.7 - chalk: 4.1.2 - commander: 9.5.0 - deepmerge: 4.3.1 - execa: 5.1.1 - find-up: 4.1.0 - fs-extra: 8.1.0 - graceful-fs: 4.2.11 - prompts: 2.4.2 - semver: 7.7.3 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - - '@react-native/assets-registry@0.73.1': {} - - '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.28.5(@babel/core@7.28.5))': - dependencies: - '@react-native/codegen': 0.73.3(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color + '@react-native/assets-registry@0.82.1': {} - '@react-native/babel-preset@0.73.21(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))': + '@react-native/codegen@0.82.1(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.28.5) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.28.5) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.28.5) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-export-default-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-runtime': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.28.5) - react-refresh: 0.14.2 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - - '@react-native/codegen@0.73.3(@babel/preset-env@7.28.5(@babel/core@7.28.5))': - dependencies: '@babel/parser': 7.28.5 - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - flow-parser: 0.206.0 glob: 7.2.3 + hermes-parser: 0.32.0 invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - mkdirp: 0.5.6 nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color + yargs: 17.7.2 - '@react-native/community-cli-plugin@0.73.18(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))': + '@react-native/community-cli-plugin@0.82.1': dependencies: - '@react-native-community/cli-server-api': 12.3.7 - '@react-native-community/cli-tools': 12.3.7 - '@react-native/dev-middleware': 0.73.8 - '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - chalk: 4.1.2 - execa: 5.1.1 - metro: 0.80.12 - metro-config: 0.80.12 - metro-core: 0.80.12 - node-fetch: 2.7.0 - readline: 1.3.0 + '@react-native/dev-middleware': 0.82.1 + debug: 4.4.3 + invariant: 2.2.4 + metro: 0.83.3 + metro-config: 0.83.3 + metro-core: 0.83.3 + semver: 7.7.3 transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - bufferutil - - encoding - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.73.3': {} + '@react-native/debugger-frontend@0.82.1': {} + + '@react-native/debugger-shell@0.82.1': + dependencies: + cross-spawn: 7.0.6 + fb-dotslash: 0.5.8 - '@react-native/dev-middleware@0.73.8': + '@react-native/dev-middleware@0.82.1': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.73.3 + '@react-native/debugger-frontend': 0.82.1 + '@react-native/debugger-shell': 0.82.1 chrome-launcher: 0.15.2 - chromium-edge-launcher: 1.0.0 + chromium-edge-launcher: 0.2.0 connect: 3.7.0 - debug: 2.6.9 - node-fetch: 2.7.0 + debug: 4.4.3 + invariant: 2.2.4 + nullthrows: 1.1.1 open: 7.4.2 serve-static: 1.16.2 - temp-dir: 2.0.0 ws: 6.2.3 transitivePeerDependencies: - bufferutil - - encoding - supports-color - utf-8-validate - '@react-native/gradle-plugin@0.73.5': {} - - '@react-native/js-polyfills@0.73.1': {} + '@react-native/gradle-plugin@0.82.1': {} - '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))': - dependencies: - '@babel/core': 7.28.5 - '@react-native/babel-preset': 0.73.21(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - hermes-parser: 0.15.0 - nullthrows: 1.1.1 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color + '@react-native/js-polyfills@0.82.1': {} - '@react-native/normalize-colors@0.73.2': {} + '@react-native/normalize-colors@0.82.1': {} - '@react-native/virtualized-lists@0.73.4(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))': + '@react-native/virtualized-lists@0.82.1(@types/react@18.3.26)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 - react-native: 0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1) + react: 18.3.1 + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.26 '@react-spring/animated@10.0.3(react@18.3.1)': dependencies: @@ -8671,24 +6825,24 @@ snapshots: '@react-spring/types': 10.0.3 react: 18.3.1 - '@react-spring/konva@10.0.3(konva@10.0.8)(react-konva@18.2.14(@types/react@18.3.26)(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@react-spring/konva@10.0.3(konva@10.0.12)(react-konva@19.2.1(@types/react@18.3.26)(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@react-spring/animated': 10.0.3(react@18.3.1) '@react-spring/core': 10.0.3(react@18.3.1) '@react-spring/shared': 10.0.3(react@18.3.1) '@react-spring/types': 10.0.3 - konva: 10.0.8 + konva: 10.0.12 react: 18.3.1 - react-konva: 18.2.14(@types/react@18.3.26)(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-konva: 19.2.1(@types/react@18.3.26)(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-spring/native@10.0.3(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)': + '@react-spring/native@10.0.3(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)': dependencies: '@react-spring/animated': 10.0.3(react@18.3.1) '@react-spring/core': 10.0.3(react@18.3.1) '@react-spring/shared': 10.0.3(react@18.3.1) '@react-spring/types': 10.0.3 react: 18.3.1 - react-native: 0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1) '@react-spring/rafz@10.0.3': {} @@ -8698,15 +6852,15 @@ snapshots: '@react-spring/types': 10.0.3 react: 18.3.1 - '@react-spring/three@10.0.3(@react-three/fiber@8.18.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(three@0.181.1))(react@18.3.1)(three@0.181.1)': + '@react-spring/three@10.0.3(@react-three/fiber@9.4.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(three@0.181.2))(react@18.3.1)(three@0.181.2)': dependencies: '@react-spring/animated': 10.0.3(react@18.3.1) '@react-spring/core': 10.0.3(react@18.3.1) '@react-spring/shared': 10.0.3(react@18.3.1) '@react-spring/types': 10.0.3 - '@react-three/fiber': 8.18.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(three@0.181.1) + '@react-three/fiber': 9.4.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(three@0.181.2) react: 18.3.1 - three: 0.181.1 + three: 0.181.2 '@react-spring/types@10.0.3': {} @@ -8730,26 +6884,28 @@ snapshots: react-zdog: 1.2.2 zdog: 1.1.3 - '@react-three/fiber@8.18.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(three@0.181.1)': + '@react-three/fiber@9.4.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(three@0.181.2)': dependencies: '@babel/runtime': 7.28.4 - '@types/react-reconciler': 0.26.7 + '@types/react-reconciler': 0.32.3(@types/react@18.3.26) '@types/webxr': 0.5.24 base64-js: 1.5.1 buffer: 6.0.3 - its-fine: 1.2.5(@types/react@18.3.26)(react@18.3.1) + its-fine: 2.0.0(@types/react@18.3.26)(react@18.3.1) react: 18.3.1 - react-reconciler: 0.27.0(react@18.3.1) + react-reconciler: 0.31.0(react@18.3.1) react-use-measure: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - scheduler: 0.21.0 + scheduler: 0.25.0 suspend-react: 0.1.3(react@18.3.1) - three: 0.181.1 - zustand: 3.7.2(react@18.3.1) + three: 0.181.2 + use-sync-external-store: 1.6.0(react@18.3.1) + zustand: 5.0.8(@types/react@18.3.26)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) optionalDependencies: react-dom: 18.3.1(react@18.3.1) - react-native: 0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1) transitivePeerDependencies: - '@types/react' + - immer '@remix-run/router@1.23.0': {} @@ -8953,14 +7109,6 @@ snapshots: - encoding - supports-color - '@sideway/address@4.1.5': - dependencies: - '@hapi/hoek': 9.3.0 - - '@sideway/formula@3.0.1': {} - - '@sideway/pinpoint@2.0.0': {} - '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': @@ -9150,6 +7298,10 @@ snapshots: '@types/geojson@7946.0.16': {} + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 22.19.1 + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -9166,27 +7318,21 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/lodash@4.17.20': {} - '@types/node@22.19.1': dependencies: undici-types: 6.21.0 - '@types/node@24.10.0': - dependencies: - undici-types: 7.16.0 - '@types/prop-types@15.7.15': {} '@types/react-dom@18.3.7(@types/react@18.3.26)': dependencies: '@types/react': 18.3.26 - '@types/react-reconciler@0.26.7': + '@types/react-reconciler@0.28.9(@types/react@18.3.26)': dependencies: '@types/react': 18.3.26 - '@types/react-reconciler@0.28.9(@types/react@18.3.26)': + '@types/react-reconciler@0.32.3(@types/react@18.3.26)': dependencies: '@types/react': 18.3.26 @@ -9208,11 +7354,7 @@ snapshots: '@types/yargs-parser@21.0.3': {} - '@types/yargs@15.0.19': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@types/yargs@17.0.34': + '@types/yargs@17.0.35': dependencies: '@types/yargs-parser': 21.0.3 @@ -9344,7 +7486,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@24.10.0)(terser@5.44.1))': + '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@22.19.1)(terser@5.44.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -9352,7 +7494,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 5.4.21(@types/node@24.10.0)(terser@5.44.1) + vite: 5.4.21(@types/node@22.19.1)(terser@5.44.1) transitivePeerDependencies: - supports-color @@ -9469,6 +7611,8 @@ snapshots: transitivePeerDependencies: - supports-color + agent-base@7.1.4: {} + ai@4.3.19(react@18.3.1)(zod@3.25.76): dependencies: '@ai-sdk/provider': 1.1.3 @@ -9506,22 +7650,10 @@ snapshots: anser@1.4.10: {} - ansi-fragments@0.2.1: - dependencies: - colorette: 1.4.0 - slice-ansi: 2.1.0 - strip-ansi: 5.2.0 - - ansi-regex@4.1.1: {} - ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -9537,8 +7669,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - appdirsjs@1.2.7: {} - arg@5.0.2: {} argparse@1.0.10: @@ -9555,12 +7685,6 @@ snapshots: asap@2.0.6: {} - ast-types@0.15.2: - dependencies: - tslib: 2.8.1 - - astral-regex@1.0.0: {} - astral-regex@2.0.0: {} async-limiter@1.0.1: {} @@ -9577,39 +7701,64 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 - babel-core@7.0.0-bridge.0(@babel/core@7.28.5): - dependencies: - '@babel/core': 7.28.5 - - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): + babel-jest@29.7.0(@babel/core@7.28.5): dependencies: - '@babel/compat-data': 7.28.5 '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - semver: 6.3.1 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.28.5) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): + babel-plugin-istanbul@6.1.1: dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.46.0 + '@babel/helper-plugin-utils': 7.27.1 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.28.0 + + babel-plugin-syntax-hermes-parser@0.32.0: + dependencies: + hermes-parser: 0.32.0 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.5) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.5) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.28.5): + babel-preset-jest@29.6.3(@babel/core@7.28.5): dependencies: - '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - '@babel/core' + '@babel/core': 7.28.5 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) balanced-match@1.0.2: {} @@ -9621,12 +7770,6 @@ snapshots: binary-extensions@2.3.0: {} - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - boolean@3.2.0: {} bplist-parser@0.3.2: @@ -9662,28 +7805,11 @@ snapshots: buffer-from@1.1.2: {} - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - buffer@6.0.3: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - bytes@3.1.2: {} - - caller-callsite@2.0.0: - dependencies: - callsites: 2.0.0 - - caller-path@2.0.0: - dependencies: - caller-callsite: 2.0.0 - - callsites@2.0.0: {} - callsites@3.1.0: {} camelcase-css@2.0.1: {} @@ -9742,7 +7868,7 @@ snapshots: chrome-trace-event@1.0.4: {} - chromium-edge-launcher@1.0.0: + chromium-edge-launcher@0.2.0: dependencies: '@types/node': 22.19.1 escape-string-regexp: 4.0.0 @@ -9761,12 +7887,6 @@ snapshots: dependencies: clsx: 2.1.1 - cli-cursor@3.1.0: - dependencies: - restore-cursor: 3.1.0 - - cli-spinners@2.9.2: {} - click-to-react-component@1.1.3(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@floating-ui/react-dom-interactions': 0.3.1(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -9777,26 +7897,12 @@ snapshots: - '@types/react' - react-dom - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - clone-deep@4.0.1: - dependencies: - is-plain-object: 2.0.4 - kind-of: 6.0.3 - shallow-clone: 3.0.1 - - clone@1.0.4: {} - clsx@2.1.1: {} codemirror@6.0.2: @@ -9809,22 +7915,12 @@ snapshots: '@codemirror/state': 6.5.2 '@codemirror/view': 6.38.6 - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - color-convert@2.0.1: dependencies: color-name: 1.1.4 - color-name@1.1.3: {} - color-name@1.1.4: {} - colorette@1.4.0: {} - - command-exists@1.2.9: {} - commander@12.1.0: {} commander@2.20.3: {} @@ -9835,26 +7931,6 @@ snapshots: commander@8.3.0: {} - commander@9.5.0: {} - - commondir@1.0.1: {} - - compressible@2.0.18: - dependencies: - mime-db: 1.52.0 - - compression@1.8.1: - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9 - negotiator: 0.6.4 - on-headers: 1.1.0 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - compute-gcd@1.2.1: dependencies: validate.io-array: 1.0.6 @@ -9897,14 +7973,8 @@ snapshots: convert-source-map@2.0.0: {} - core-js-compat@3.46.0: - dependencies: - browserslist: 4.27.0 - core-js@3.46.0: {} - core-util-is@1.0.2: {} - cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -9913,13 +7983,6 @@ snapshots: dependencies: layout-base: 2.0.1 - cosmiconfig@5.2.1: - dependencies: - import-fresh: 2.0.0 - is-directory: 0.3.1 - js-yaml: 3.14.1 - parse-json: 4.0.0 - crelt@1.0.6: {} cross-env@7.0.3: @@ -10134,16 +8197,8 @@ snapshots: dependencies: ms: 2.1.3 - decamelize@1.2.0: {} - deep-is@0.1.4: {} - deepmerge@4.3.1: {} - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -10162,16 +8217,8 @@ snapshots: dependencies: robust-predicates: 3.0.2 - denodeify@1.2.1: {} - depd@2.0.0: {} - deprecated-react-native-prop-types@5.0.0: - dependencies: - '@react-native/normalize-colors': 0.73.2 - invariant: 2.2.4 - prop-types: 15.8.1 - dequal@2.0.3: {} destroy@1.2.0: {} @@ -10258,21 +8305,10 @@ snapshots: env-paths@2.2.1: {} - envinfo@7.20.0: {} - - error-ex@1.3.4: - dependencies: - is-arrayish: 0.2.1 - error-stack-parser@2.1.4: dependencies: stackframe: 1.3.4 - errorhandler@1.5.1: - dependencies: - accepts: 1.3.8 - escape-html: 1.0.3 - es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -10429,21 +8465,9 @@ snapshots: etag@1.8.1: {} - event-target-shim@5.0.1: {} - - events@3.3.0: {} - - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 + event-target-shim@5.0.1: {} + + events@3.3.0: {} exponential-backoff@3.1.3: {} @@ -10471,14 +8495,12 @@ snapshots: fast-uri@3.1.0: {} - fast-xml-parser@4.5.3: - dependencies: - strnum: 1.1.2 - fastq@1.19.1: dependencies: reusify: 1.1.0 + fb-dotslash@0.5.8: {} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -10513,16 +8535,6 @@ snapshots: transitivePeerDependencies: - supports-color - find-cache-dir@2.1.0: - dependencies: - commondir: 1.0.1 - make-dir: 2.1.0 - pkg-dir: 3.0.0 - - find-up@3.0.0: - dependencies: - locate-path: 3.0.0 - find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -10545,8 +8557,6 @@ snapshots: flow-enums-runtime@0.0.6: {} - flow-parser@0.206.0: {} - foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -10587,12 +8597,6 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 @@ -10620,7 +8624,7 @@ snapshots: get-nonce@1.0.1: {} - get-stream@6.0.1: {} + get-package-type@0.1.0: {} glob-parent@5.1.2: dependencies: @@ -10641,13 +8645,10 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@11.0.3: + glob@13.0.0: dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 minimatch: 10.1.1 minipass: 7.1.2 - package-json-from-dist: 1.0.1 path-scurry: 2.0.1 glob@7.2.3: @@ -10715,21 +8716,13 @@ snapshots: dependencies: function-bind: 1.1.2 - hermes-estree@0.15.0: {} + hermes-compiler@0.0.0: {} - hermes-estree@0.23.1: {} + hermes-estree@0.32.0: {} - hermes-parser@0.15.0: + hermes-parser@0.32.0: dependencies: - hermes-estree: 0.15.0 - - hermes-parser@0.23.1: - dependencies: - hermes-estree: 0.23.1 - - hermes-profile-transformer@0.0.6: - dependencies: - source-map: 0.7.6 + hermes-estree: 0.32.0 highlight.js@11.11.1: {} @@ -10758,7 +8751,12 @@ snapshots: transitivePeerDependencies: - supports-color - human-signals@2.1.0: {} + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color i18next-browser-languagedetector@8.2.0: dependencies: @@ -10782,11 +8780,6 @@ snapshots: dependencies: queue: 6.0.2 - import-fresh@2.0.0: - dependencies: - caller-path: 2.0.0 - resolve-from: 3.0.0 - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -10811,8 +8804,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - is-arrayish@0.2.1: {} - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -10821,47 +8812,39 @@ snapshots: dependencies: hasown: 2.0.2 - is-directory@0.3.1: {} - is-docker@2.2.1: {} is-extglob@2.1.1: {} - is-fullwidth-code-point@2.0.0: {} - is-fullwidth-code-point@3.0.0: {} is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - is-interactive@1.0.0: {} - is-number@7.0.0: {} is-path-inside@3.0.3: {} - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - - is-stream@2.0.1: {} - - is-unicode-supported@0.1.0: {} - - is-wsl@1.1.0: {} - is-wsl@2.2.0: dependencies: is-docker: 2.2.1 - isarray@1.0.0: {} - isexe@2.0.0: {} - isobject@3.0.1: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - its-fine@1.2.5(@types/react@18.3.26)(react@18.3.1): + its-fine@2.0.0(@types/react@18.3.26)(react@18.3.1): dependencies: '@types/react-reconciler': 0.28.9(@types/react@18.3.26) react: 18.3.1 @@ -10874,10 +8857,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jackspeak@4.1.1: - dependencies: - '@isaacs/cliui': 8.0.2 - jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 @@ -10889,6 +8868,22 @@ snapshots: jest-get-type@29.6.3: {} + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.19.1 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + jest-message-util@29.7.0: dependencies: '@babel/code-frame': 7.27.1 @@ -10907,6 +8902,8 @@ snapshots: '@types/node': 22.19.1 jest-util: 29.7.0 + jest-regex-util@29.6.3: {} + jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 @@ -10942,17 +8939,9 @@ snapshots: jiti@2.6.1: {} - joi@17.13.3: - dependencies: - '@hapi/hoek': 9.3.0 - '@hapi/topo': 5.1.0 - '@sideway/address': 4.1.5 - '@sideway/formula': 3.0.1 - '@sideway/pinpoint': 2.0.0 - js-tokens@4.0.0: {} - js-yaml@3.14.1: + js-yaml@3.14.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 @@ -10965,41 +8954,12 @@ snapshots: dependencies: argparse: 2.0.1 - jsc-android@250231.0.0: {} - jsc-safe-url@0.2.4: {} - jscodeshift@0.14.0(@babel/preset-env@7.28.5(@babel/core@7.28.5)): - dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - '@babel/preset-flow': 7.27.1(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@babel/register': 7.28.3(@babel/core@7.28.5) - babel-core: 7.0.0-bridge.0(@babel/core@7.28.5) - chalk: 4.1.2 - flow-parser: 0.206.0 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - neo-async: 2.6.2 - node-dir: 0.1.17 - recast: 0.21.5 - temp: 0.8.4 - write-file-atomic: 2.4.3 - transitivePeerDependencies: - - supports-color - jsesc@3.1.0: {} json-buffer@3.0.1: {} - json-parse-better-errors@1.0.2: {} - json-parse-even-better-errors@2.3.1: {} json-schema-compare@0.2.2: @@ -11030,10 +8990,6 @@ snapshots: chalk: 5.6.2 diff-match-patch: 1.0.5 - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -11052,16 +9008,14 @@ snapshots: khroma@2.1.0: {} - kind-of@6.0.3: {} - kleur@3.0.3: {} kleur@4.1.5: {} - knip@5.70.2(@types/node@24.10.0)(typescript@5.9.3): + knip@5.70.2(@types/node@22.19.1)(typescript@5.9.3): dependencies: '@nodelib/fs.walk': 1.2.8 - '@types/node': 24.10.0 + '@types/node': 22.19.1 fast-glob: 3.3.3 formatly: 0.3.0 jiti: 2.6.1 @@ -11077,7 +9031,7 @@ snapshots: kolorist@1.8.0: {} - konva@10.0.8: {} + konva@10.0.12: {} langium@3.0.0: dependencies: @@ -11117,11 +9071,6 @@ snapshots: pkg-types: 2.3.0 quansync: 0.2.11 - locate-path@3.0.0: - dependencies: - p-locate: 3.0.0 - path-exists: 3.0.0 - locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -11132,25 +9081,12 @@ snapshots: lodash-es@4.17.21: {} - lodash.debounce@4.0.8: {} - lodash.merge@4.6.2: {} lodash.throttle@4.1.1: {} lodash@4.17.21: {} - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - logkitty@0.7.1: - dependencies: - ansi-fragments: 0.2.1 - dayjs: 1.11.19 - yargs: 15.4.1 - long@5.3.2: {} loose-envify@1.4.0: @@ -11179,11 +9115,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - make-dir@2.1.0: - dependencies: - pify: 4.0.1 - semver: 5.7.2 - makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -11231,105 +9162,104 @@ snapshots: transitivePeerDependencies: - supports-color - metro-babel-transformer@0.80.12: + metro-babel-transformer@0.83.3: dependencies: '@babel/core': 7.28.5 flow-enums-runtime: 0.0.6 - hermes-parser: 0.23.1 + hermes-parser: 0.32.0 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-cache-key@0.80.12: + metro-cache-key@0.83.3: dependencies: flow-enums-runtime: 0.0.6 - metro-cache@0.80.12: + metro-cache@0.83.3: dependencies: exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 - metro-core: 0.80.12 + https-proxy-agent: 7.0.6 + metro-core: 0.83.3 + transitivePeerDependencies: + - supports-color - metro-config@0.80.12: + metro-config@0.83.3: dependencies: connect: 3.7.0 - cosmiconfig: 5.2.1 flow-enums-runtime: 0.0.6 jest-validate: 29.7.0 - metro: 0.80.12 - metro-cache: 0.80.12 - metro-core: 0.80.12 - metro-runtime: 0.80.12 + metro: 0.83.3 + metro-cache: 0.83.3 + metro-core: 0.83.3 + metro-runtime: 0.83.3 + yaml: 2.8.1 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - metro-core@0.80.12: + metro-core@0.83.3: dependencies: flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 - metro-resolver: 0.80.12 + metro-resolver: 0.83.3 - metro-file-map@0.80.12: + metro-file-map@0.83.3: dependencies: - anymatch: 3.1.3 - debug: 2.6.9 + debug: 4.4.3 fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 micromatch: 4.0.8 - node-abort-controller: 3.1.1 nullthrows: 1.1.1 walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 transitivePeerDependencies: - supports-color - metro-minify-terser@0.80.12: + metro-minify-terser@0.83.3: dependencies: flow-enums-runtime: 0.0.6 terser: 5.44.1 - metro-resolver@0.80.12: + metro-resolver@0.83.3: dependencies: flow-enums-runtime: 0.0.6 - metro-runtime@0.80.12: + metro-runtime@0.83.3: dependencies: '@babel/runtime': 7.28.4 flow-enums-runtime: 0.0.6 - metro-source-map@0.80.12: + metro-source-map@0.83.3: dependencies: '@babel/traverse': 7.28.5 + '@babel/traverse--for-generate-function-map': '@babel/traverse@7.28.5' '@babel/types': 7.28.5 flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-symbolicate: 0.80.12 + metro-symbolicate: 0.83.3 nullthrows: 1.1.1 - ob1: 0.80.12 + ob1: 0.83.3 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-symbolicate@0.80.12: + metro-symbolicate@0.83.3: dependencies: flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-source-map: 0.80.12 + metro-source-map: 0.83.3 nullthrows: 1.1.1 source-map: 0.5.7 - through2: 2.0.5 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-transform-plugins@0.80.12: + metro-transform-plugins@0.83.3: dependencies: '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -11340,27 +9270,27 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.12: + metro-transform-worker@0.83.3: dependencies: '@babel/core': 7.28.5 '@babel/generator': 7.28.5 '@babel/parser': 7.28.5 '@babel/types': 7.28.5 flow-enums-runtime: 0.0.6 - metro: 0.80.12 - metro-babel-transformer: 0.80.12 - metro-cache: 0.80.12 - metro-cache-key: 0.80.12 - metro-minify-terser: 0.80.12 - metro-source-map: 0.80.12 - metro-transform-plugins: 0.80.12 + metro: 0.83.3 + metro-babel-transformer: 0.83.3 + metro-cache: 0.83.3 + metro-cache-key: 0.83.3 + metro-minify-terser: 0.83.3 + metro-source-map: 0.83.3 + metro-transform-plugins: 0.83.3 nullthrows: 1.1.1 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - metro@0.80.12: + metro@0.83.3: dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.28.5 @@ -11373,34 +9303,32 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 2.6.9 - denodeify: 1.2.1 + debug: 4.4.3 error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 - hermes-parser: 0.23.1 + hermes-parser: 0.32.0 image-size: 1.2.1 invariant: 2.2.4 jest-worker: 29.7.0 jsc-safe-url: 0.2.4 lodash.throttle: 4.1.1 - metro-babel-transformer: 0.80.12 - metro-cache: 0.80.12 - metro-cache-key: 0.80.12 - metro-config: 0.80.12 - metro-core: 0.80.12 - metro-file-map: 0.80.12 - metro-resolver: 0.80.12 - metro-runtime: 0.80.12 - metro-source-map: 0.80.12 - metro-symbolicate: 0.80.12 - metro-transform-plugins: 0.80.12 - metro-transform-worker: 0.80.12 + metro-babel-transformer: 0.83.3 + metro-cache: 0.83.3 + metro-cache-key: 0.83.3 + metro-config: 0.83.3 + metro-core: 0.83.3 + metro-file-map: 0.83.3 + metro-resolver: 0.83.3 + metro-runtime: 0.83.3 + metro-source-map: 0.83.3 + metro-symbolicate: 0.83.3 + metro-transform-plugins: 0.83.3 + metro-transform-worker: 0.83.3 mime-types: 2.1.35 nullthrows: 1.1.1 serialize-error: 2.1.0 source-map: 0.5.7 - strip-ansi: 6.0.1 throat: 5.0.0 ws: 7.5.10 yargs: 17.7.2 @@ -11422,10 +9350,6 @@ snapshots: mime@1.6.0: {} - mime@2.6.0: {} - - mimic-fn@2.1.0: {} - minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -11463,10 +9387,6 @@ snapshots: dependencies: minipass: 7.1.2 - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - mkdirp@1.0.4: {} mlly@1.8.0: @@ -11516,18 +9436,8 @@ snapshots: negotiator@0.6.3: {} - negotiator@0.6.4: {} - neo-async@2.6.2: {} - nocache@3.0.4: {} - - node-abort-controller@3.1.1: {} - - node-dir@0.1.17: - dependencies: - minimatch: 3.1.2 - node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -11536,19 +9446,13 @@ snapshots: node-releases@2.0.27: {} - node-stream-zip@1.15.0: {} - normalize-path@3.0.0: {} normalize-range@0.1.2: {} - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - nullthrows@1.1.1: {} - ob1@0.80.12: + ob1@0.83.3: dependencies: flow-enums-runtime: 0.0.6 @@ -11566,16 +9470,10 @@ snapshots: dependencies: ee-first: 1.1.1 - on-headers@1.1.0: {} - once@1.4.0: dependencies: wrappy: 1.0.2 - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - onnxruntime-common@1.21.0: {} onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: {} @@ -11595,10 +9493,6 @@ snapshots: platform: 1.3.6 protobufjs: 7.5.4 - open@6.4.0: - dependencies: - is-wsl: 1.1.0 - open@7.4.2: dependencies: is-docker: 2.2.1 @@ -11619,18 +9513,6 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - oxc-resolver@11.14.0: optionalDependencies: '@oxc-resolver/binding-android-arm-eabi': 11.14.0 @@ -11661,10 +9543,6 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-locate@3.0.0: - dependencies: - p-limit: 2.3.0 - p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -11677,23 +9555,16 @@ snapshots: package-json-from-dist@1.0.1: {} - package-manager-detector@1.5.0: {} + package-manager-detector@1.6.0: {} parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-json@4.0.0: - dependencies: - error-ex: 1.3.4 - json-parse-better-errors: 1.0.2 - parseurl@1.3.3: {} path-data-parser@0.1.0: {} - path-exists@3.0.0: {} - path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -11726,14 +9597,8 @@ snapshots: pify@2.3.0: {} - pify@4.0.1: {} - pirates@4.0.7: {} - pkg-dir@3.0.0: - dependencies: - find-up: 3.0.0 - pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -11748,11 +9613,11 @@ snapshots: platform@1.3.6: {} - playwright-core@1.56.1: {} + playwright-core@1.57.0: {} - playwright@1.56.1: + playwright@1.57.0: dependencies: - playwright-core: 1.56.1 + playwright-core: 1.57.0 optionalDependencies: fsevents: 2.3.2 @@ -11832,21 +9697,12 @@ snapshots: prettier@3.6.2: {} - pretty-format@26.6.2: - dependencies: - '@jest/types': 26.6.2 - ansi-regex: 5.0.1 - ansi-styles: 4.3.0 - react-is: 17.0.2 - pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.3.1 - process-nextick-args@2.0.1: {} - progress@2.0.3: {} promise@8.3.0: @@ -11897,7 +9753,7 @@ snapshots: range-parser@1.2.1: {} - react-devtools-core@4.28.5: + react-devtools-core@6.1.5: dependencies: shell-quote: 1.8.3 ws: 7.5.10 @@ -11916,7 +9772,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-i18next@15.7.4(i18next@25.6.1(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(typescript@5.9.3): + react-i18next@15.7.4(i18next@25.6.1(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 html-parse-stringify: 3.0.1 @@ -11924,89 +9780,84 @@ snapshots: react: 18.3.1 optionalDependencies: react-dom: 18.3.1(react@18.3.1) - react-native: 0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1) typescript: 5.9.3 react-is@16.13.1: {} - react-is@17.0.2: {} - react-is@18.3.1: {} - react-konva@18.2.14(@types/react@18.3.26)(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-konva@19.2.1(@types/react@18.3.26)(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@types/react-reconciler': 0.28.9(@types/react@18.3.26) - its-fine: 1.2.5(@types/react@18.3.26)(react@18.3.1) - konva: 10.0.8 + '@types/react-reconciler': 0.32.3(@types/react@18.3.26) + its-fine: 2.0.0(@types/react@18.3.26)(react@18.3.1) + konva: 10.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-reconciler: 0.29.2(react@18.3.1) - scheduler: 0.23.2 + react-reconciler: 0.33.0(react@18.3.1) + scheduler: 0.27.0 transitivePeerDependencies: - '@types/react' react-merge-refs@1.1.0: {} - react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1): + react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 12.3.7 - '@react-native-community/cli-platform-android': 12.3.7 - '@react-native-community/cli-platform-ios': 12.3.7 - '@react-native/assets-registry': 0.73.1 - '@react-native/codegen': 0.73.3(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5)) - '@react-native/gradle-plugin': 0.73.5 - '@react-native/js-polyfills': 0.73.1 - '@react-native/normalize-colors': 0.73.2 - '@react-native/virtualized-lists': 0.73.4(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1)) + '@react-native/assets-registry': 0.82.1 + '@react-native/codegen': 0.82.1(@babel/core@7.28.5) + '@react-native/community-cli-plugin': 0.82.1 + '@react-native/gradle-plugin': 0.82.1 + '@react-native/js-polyfills': 0.82.1 + '@react-native/normalize-colors': 0.82.1 + '@react-native/virtualized-lists': 0.82.1(@types/react@18.3.26)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 + babel-jest: 29.7.0(@babel/core@7.28.5) + babel-plugin-syntax-hermes-parser: 0.32.0 base64-js: 1.5.1 - chalk: 4.1.2 - deprecated-react-native-prop-types: 5.0.0 - event-target-shim: 5.0.1 + commander: 12.1.0 flow-enums-runtime: 0.0.6 + glob: 7.2.3 + hermes-compiler: 0.0.0 invariant: 2.2.4 jest-environment-node: 29.7.0 - jsc-android: 250231.0.0 memoize-one: 5.2.1 - metro-runtime: 0.80.12 - metro-source-map: 0.80.12 - mkdirp: 0.5.6 + metro-runtime: 0.83.3 + metro-source-map: 0.83.3 nullthrows: 1.1.1 - pretty-format: 26.6.2 + pretty-format: 29.7.0 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 4.28.5 + react-devtools-core: 6.1.5 react-refresh: 0.14.2 - react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 - scheduler: 0.24.0-canary-efb381bbf-20230505 + scheduler: 0.26.0 + semver: 7.7.3 stacktrace-parser: 0.1.11 whatwg-fetch: 3.6.20 ws: 6.2.3 yargs: 17.7.2 + optionalDependencies: + '@types/react': 18.3.26 transitivePeerDependencies: - '@babel/core' - - '@babel/preset-env' + - '@react-native-community/cli' + - '@react-native/metro-config' - bufferutil - - encoding - supports-color - utf-8-validate - react-reconciler@0.27.0(react@18.3.1): + react-reconciler@0.31.0(react@18.3.1): dependencies: - loose-envify: 1.4.0 react: 18.3.1 - scheduler: 0.21.0 + scheduler: 0.25.0 - react-reconciler@0.29.2(react@18.3.1): + react-reconciler@0.33.0(react@18.3.1): dependencies: - loose-envify: 1.4.0 react: 18.3.1 - scheduler: 0.23.2 + scheduler: 0.27.0 react-refresh@0.14.2: {} @@ -12048,18 +9899,12 @@ snapshots: '@remix-run/router': 1.23.0 react: 18.3.1 - react-shallow-renderer@16.15.0(react@18.3.1): - dependencies: - object-assign: 4.1.1 - react: 18.3.1 - react-is: 18.3.1 - - react-spring@10.0.3(@react-three/fiber@8.18.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(three@0.181.1))(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react-konva@18.2.14(@types/react@18.3.26)(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react-zdog@1.2.2)(react@18.3.1)(three@0.181.1)(zdog@1.1.3): + react-spring@10.0.3(@react-three/fiber@9.4.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(three@0.181.2))(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react-konva@19.2.1(@types/react@18.3.26)(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react-zdog@1.2.2)(react@18.3.1)(three@0.181.2)(zdog@1.1.3): dependencies: '@react-spring/core': 10.0.3(react@18.3.1) - '@react-spring/konva': 10.0.3(konva@10.0.8)(react-konva@18.2.14(@types/react@18.3.26)(konva@10.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) - '@react-spring/native': 10.0.3(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1) - '@react-spring/three': 10.0.3(@react-three/fiber@8.18.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.73.11(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1))(react@18.3.1)(three@0.181.1))(react@18.3.1)(three@0.181.1) + '@react-spring/konva': 10.0.3(konva@10.0.12)(react-konva@19.2.1(@types/react@18.3.26)(konva@10.0.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@react-spring/native': 10.0.3(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1) + '@react-spring/three': 10.0.3(@react-three/fiber@9.4.0(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.26)(react@18.3.1))(react@18.3.1)(three@0.181.2))(react@18.3.1)(three@0.181.2) '@react-spring/web': 10.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@react-spring/zdog': 10.0.3(react-dom@18.3.1(react@18.3.1))(react-zdog@1.2.2)(react@18.3.1)(zdog@1.1.3) react: 18.3.1 @@ -12115,16 +9960,6 @@ snapshots: dependencies: pify: 2.3.0 - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.2 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -12135,78 +9970,37 @@ snapshots: dependencies: picomatch: 2.3.1 - readline@1.3.0: {} - - recast@0.21.5: - dependencies: - ast-types: 0.15.2 - esprima: 4.0.1 - source-map: 0.6.1 - tslib: 2.8.1 - - regenerate-unicode-properties@10.2.2: - dependencies: - regenerate: 1.4.2 - - regenerate@1.4.2: {} - regenerator-runtime@0.13.11: {} - regexpu-core@6.4.0: - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.2 - regjsgen: 0.8.0 - regjsparser: 0.13.0 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.1 - - regjsgen@0.8.0: {} - - regjsparser@0.13.0: - dependencies: - jsesc: 3.1.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} - require-main-filename@2.0.0: {} - requireindex@1.1.0: {} resize-observer-polyfill@1.5.1: {} - resolve-from@3.0.0: {} - resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - reusify@1.1.0: {} rfc6902@5.1.2: {} - rimraf@2.6.3: - dependencies: - glob: 7.2.3 - rimraf@3.0.2: dependencies: glob: 7.2.3 - rimraf@6.1.0: + rimraf@6.1.2: dependencies: - glob: 11.0.3 + glob: 13.0.0 package-json-from-dist: 1.0.1 roarr@2.15.4: @@ -12265,8 +10059,6 @@ snapshots: dependencies: tslib: 2.8.1 - safe-buffer@5.1.2: {} - safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -12275,17 +10067,15 @@ snapshots: sax@1.4.3: {} - scheduler@0.21.0: - dependencies: - loose-envify: 1.4.0 - scheduler@0.23.2: dependencies: loose-envify: 1.4.0 - scheduler@0.24.0-canary-efb381bbf-20230505: - dependencies: - loose-envify: 1.4.0 + scheduler@0.25.0: {} + + scheduler@0.26.0: {} + + scheduler@0.27.0: {} schema-utils@4.3.3: dependencies: @@ -12298,8 +10088,6 @@ snapshots: semver-compare@1.0.0: {} - semver@5.7.2: {} - semver@6.3.1: {} semver@7.7.3: {} @@ -12341,14 +10129,8 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} - setprototypeof@1.2.0: {} - shallow-clone@3.0.1: - dependencies: - kind-of: 6.0.3 - sharp@0.34.5: dependencies: '@img/colour': 1.0.0 @@ -12398,12 +10180,6 @@ snapshots: slash@3.0.0: {} - slice-ansi@2.1.0: - dependencies: - ansi-styles: 3.2.1 - astral-regex: 1.0.0 - is-fullwidth-code-point: 2.0.0 - slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 @@ -12423,8 +10199,6 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.6: {} - spawn-command@0.0.2: {} split2@4.2.0: {} @@ -12459,18 +10233,10 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - strip-ansi@5.2.0: - dependencies: - ansi-regex: 4.1.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -12479,14 +10245,10 @@ snapshots: dependencies: ansi-regex: 6.2.2 - strip-final-newline@2.0.0: {} - strip-json-comments@3.1.1: {} strip-json-comments@5.0.3: {} - strnum@1.1.2: {} - style-mod@4.1.3: {} stylis@4.3.6: {} @@ -12501,8 +10263,6 @@ snapshots: pirates: 4.0.7 ts-interface-checker: 0.1.13 - sudo-prompt@9.2.1: {} - supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -12582,12 +10342,6 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 - temp-dir@2.0.0: {} - - temp@0.8.4: - dependencies: - rimraf: 2.6.3 - terser-webpack-plugin@5.3.14(webpack@5.103.0): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -12604,6 +10358,12 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + text-table@0.2.0: {} thenify-all@1.6.0: @@ -12614,17 +10374,12 @@ snapshots: dependencies: any-promise: 1.3.0 - three@0.181.1: {} + three@0.181.2: {} throat@5.0.0: {} throttleit@2.1.0: {} - through2@2.0.5: - dependencies: - readable-stream: 2.3.8 - xtend: 4.0.2 - through2@4.0.2: dependencies: readable-stream: 3.6.2 @@ -12671,21 +10426,6 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.16.0: {} - - unicode-canonical-property-names-ecmascript@2.0.1: {} - - unicode-match-property-ecmascript@2.0.0: - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.2.0 - - unicode-match-property-value-ecmascript@2.2.1: {} - - unicode-property-aliases-ecmascript@2.2.0: {} - - universalify@0.1.2: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -12716,10 +10456,10 @@ snapshots: optionalDependencies: '@types/react': 18.3.26 - use-context-selector@2.0.0(react@18.3.1)(scheduler@0.24.0-canary-efb381bbf-20230505): + use-context-selector@2.0.0(react@18.3.1)(scheduler@0.23.2): dependencies: react: 18.3.1 - scheduler: 0.24.0-canary-efb381bbf-20230505 + scheduler: 0.23.2 use-isomorphic-layout-effect@1.2.1(@types/react@18.3.26)(react@18.3.1): dependencies: @@ -12762,15 +10502,13 @@ snapshots: validate.io-number@1.0.3: {} - vary@1.1.2: {} - - vite@5.4.21(@types/node@24.10.0)(terser@5.44.1): + vite@5.4.21(@types/node@22.19.1)(terser@5.44.1): dependencies: esbuild: 0.21.5 postcss: 8.5.6 rollup: 4.53.1 optionalDependencies: - '@types/node': 24.10.0 + '@types/node': 22.19.1 fsevents: 2.3.3 terser: 5.44.1 @@ -12808,10 +10546,6 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - web-vitals@4.2.4: {} webidl-conversions@3.0.1: {} @@ -12859,20 +10593,12 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 - which-module@2.0.1: {} - which@2.0.2: dependencies: isexe: 2.0.0 word-wrap@1.2.5: {} - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -12887,9 +10613,8 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@2.4.3: + write-file-atomic@4.0.2: dependencies: - graceful-fs: 4.2.11 imurmurhash: 0.1.4 signal-exit: 3.0.7 @@ -12908,10 +10633,6 @@ snapshots: xmlbuilder@15.1.1: {} - xtend@4.0.2: {} - - y18n@4.0.3: {} - y18n@5.0.8: {} yallist@3.1.1: {} @@ -12922,27 +10643,8 @@ snapshots: yaml@2.8.1: {} - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - yargs-parser@21.1.1: {} - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -12970,13 +10672,15 @@ snapshots: zod@4.1.13: {} - zustand@3.7.2(react@18.3.1): - optionalDependencies: - react: 18.3.1 - zustand@4.5.7(@types/react@18.3.26)(react@18.3.1): dependencies: use-sync-external-store: 1.6.0(react@18.3.1) optionalDependencies: '@types/react': 18.3.26 react: 18.3.1 + + zustand@5.0.8(@types/react@18.3.26)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + optionalDependencies: + '@types/react': 18.3.26 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) diff --git a/scripts/build/build.sh b/scripts/build/build.sh index 4a97fe0e8..5c728da9e 100755 --- a/scripts/build/build.sh +++ b/scripts/build/build.sh @@ -167,9 +167,11 @@ if [ "$NEEDS_BACKEND_BUILD" = "true" ]; then export SQLX_OFFLINE=true cargo build --release --bin forge-app + cargo build --release --bin mcp_task_server + cargo build --release --bin forge-cleanup else # Verify binaries actually exist before skipping - if [ ! -f "target/release/forge-app${BIN_EXT}" ]; then + if [ ! -f "target/release/forge-app${BIN_EXT}" ] || [ ! -f "target/release/mcp_task_server${BIN_EXT}" ] || [ ! -f "target/release/forge-cleanup${BIN_EXT}" ]; then echo "âš ī¸ Backend binaries missing despite no detected changes - rebuilding" # Use SQLx offline mode for compilation @@ -177,6 +179,8 @@ else export SQLX_OFFLINE=true cargo build --release --bin forge-app + cargo build --release --bin mcp_task_server + cargo build --release --bin forge-cleanup else echo "â­ī¸ Skipping backend build (no changes)" echo " Using existing binaries from target/release/" @@ -214,12 +218,19 @@ zip_one "automagik-forge-mcp${BIN_EXT}" "automagik-forge-mcp.zip" rm -f "automagik-forge-mcp${BIN_EXT}" mv "automagik-forge-mcp.zip" "npx-cli/dist/$PLATFORM_DIR/automagik-forge-mcp.zip" +# Copy and zip the cleanup binary +cp "target/release/forge-cleanup${BIN_EXT}" "forge-cleanup${BIN_EXT}" +zip_one "forge-cleanup${BIN_EXT}" "forge-cleanup.zip" +rm -f "forge-cleanup${BIN_EXT}" +mv "forge-cleanup.zip" "npx-cli/dist/$PLATFORM_DIR/forge-cleanup.zip" + # On Android/Termux, also copy to android-arm64 directory (for npm package) if [ "$IS_ANDROID" = true ] && [ "$PLATFORM_DIR" = "linux-arm64" ]; then echo "📱 Creating android-arm64 package for Termux..." mkdir -p "npx-cli/dist/android-arm64" cp "npx-cli/dist/linux-arm64/automagik-forge.zip" "npx-cli/dist/android-arm64/automagik-forge.zip" cp "npx-cli/dist/linux-arm64/automagik-forge-mcp.zip" "npx-cli/dist/android-arm64/automagik-forge-mcp.zip" + cp "npx-cli/dist/linux-arm64/forge-cleanup.zip" "npx-cli/dist/android-arm64/forge-cleanup.zip" echo "✅ Created android-arm64 package" fi @@ -235,6 +246,7 @@ echo "✅ Binary zips staged for NPX CLI" echo "📁 Files created:" echo " - npx-cli/dist/$PLATFORM_DIR/automagik-forge.zip" echo " - npx-cli/dist/$PLATFORM_DIR/automagik-forge-mcp.zip" +echo " - npx-cli/dist/$PLATFORM_DIR/forge-cleanup.zip" echo "📋 Other platform placeholders created under npx-cli/dist/" echo "â„šī¸ To create the npm package tarball, run:"